9e78148a16ecfe9cdcbb2c012465502db4f05faa
[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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, 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
31 #include "gnunet_rps_service.h"
32 #include "rps-test_util.h"
33 #include "gnunet-service-rps_sampler_elem.h"
34
35 #include <inttypes.h>
36
37
38 /**
39  * How many peers do we start?
40  */
41 uint32_t num_peers;
42
43 /**
44  * How long do we run the test?
45  */
46 //#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
47 static struct GNUNET_TIME_Relative timeout;
48
49
50 /**
51  * Portion of malicious peers
52  */
53 static double portion = .1;
54
55 /**
56  * Type of malicious peer to test
57  */
58 static unsigned int mal_type = 0;
59
60 /**
61  * Handles to all of the running peers
62  */
63 static struct GNUNET_TESTBED_Peer **testbed_peers;
64
65
66 /**
67  * Operation map entry
68  */
69 struct OpListEntry
70 {
71   /**
72    * DLL next ptr
73    */
74   struct OpListEntry *next;
75
76   /**
77    * DLL prev ptr
78    */
79   struct OpListEntry *prev;
80
81   /**
82    * The testbed operation
83    */
84   struct GNUNET_TESTBED_Operation *op;
85
86   /**
87    * Depending on whether we start or stop NSE service at the peer set this to 1
88    * or -1
89    */
90   int delta;
91
92   /**
93    * Index of the regarding peer
94    */
95   unsigned int index;
96 };
97
98 /**
99  * OpList DLL head
100  */
101 static struct OpListEntry *oplist_head;
102
103 /**
104  * OpList DLL tail
105  */
106 static struct OpListEntry *oplist_tail;
107
108
109 /**
110  * Information we track for each peer.
111  */
112 struct RPSPeer
113 {
114   /**
115    * Index of the peer.
116    */
117   unsigned int index;
118
119   /**
120    * Handle for RPS connect operation.
121    */
122   struct GNUNET_TESTBED_Operation *op;
123
124   /**
125    * Handle to RPS service.
126    */
127   struct GNUNET_RPS_Handle *rps_handle;
128
129   /**
130    * ID of the peer.
131    */
132   struct GNUNET_PeerIdentity *peer_id;
133
134   /**
135    * A request handle to check for an request
136    */
137   //struct GNUNET_RPS_Request_Handle *req_handle;
138
139   /**
140    * Peer on- or offline?
141    */
142   int online;
143
144   /**
145    * Received PeerIDs
146    */
147   struct GNUNET_PeerIdentity *rec_ids;
148
149   /**
150    * Number of received PeerIDs
151    */
152   unsigned int num_rec_ids;
153 };
154
155
156 /**
157  * Information for all the peers.
158  */
159 static struct RPSPeer *rps_peers;
160
161 /**
162  * IDs of the peers.
163  */
164 static struct GNUNET_PeerIdentity *rps_peer_ids;
165
166 /**
167  * Number of online peers.
168  */
169 static unsigned int num_peers_online;
170
171 /**
172  * Return value from 'main'.
173  */
174 static int ok;
175
176
177 /**
178  * Identifier for the churn task that runs periodically
179  */
180 static struct GNUNET_SCHEDULER_Task *churn_task;
181
182
183 /**
184  * Called directly after connecting to the service
185  */
186 typedef void (*PreTest) (void *cls, struct GNUNET_RPS_Handle *h);
187
188 /**
189  * Called from within #rps_connect_complete_cb ()
190  * Executes functions to test the api/service
191  */
192 typedef void (*MainTest) (struct RPSPeer *rps_peer);
193
194 /**
195  * Callback called once the requested random peers are available
196  */
197 typedef void (*ReplyHandle) (void *cls,
198                              uint64_t n,
199                              const struct GNUNET_PeerIdentity *recv_peers);
200
201 /**
202  * Called directly before disconnecting from the service
203  */
204 typedef void (*PostTest) (void *cls, struct GNUNET_RPS_Handle *h);
205
206 /**
207  * Function called after disconnect to evaluate test success
208  */
209 typedef int (*EvaluationCallback) (void);
210
211
212 /**
213  * Structure to define a single test
214  */
215 struct SingleTestRun
216 {
217   /**
218    * Name of the test
219    */
220   char *name;
221
222   /**
223    * Called directly after connecting to the service
224    */
225   PreTest pre_test;
226
227   /**
228    * Function to execute the functions to be tested
229    */
230   MainTest main_test;
231
232   /**
233    * Callback called once the requested peers are available
234    */
235   ReplyHandle reply_handle;
236
237   /**
238    * Called directly before disconnecting from the service
239    */
240   PostTest post_test;
241
242   /**
243    * Function to evaluate the test results
244    */
245   EvaluationCallback eval_cb;
246
247   /**
248    * Request interval
249    */
250   uint32_t request_interval;
251
252   /**
253    * Number of Requests to make.
254    */
255   uint32_t num_requests;
256 } cur_test_run;
257
258
259 /**
260  * Append arguments to file
261  */
262 static void
263 tofile_ (const char *file_name, char *line)
264 {
265   struct GNUNET_DISK_FileHandle *f;
266   /* char output_buffer[512]; */
267   size_t size;
268   /* int size; */
269   size_t size2;
270
271   if (NULL == (f = GNUNET_DISK_file_open (file_name,
272                                           GNUNET_DISK_OPEN_APPEND |
273                                           GNUNET_DISK_OPEN_WRITE |
274                                           GNUNET_DISK_OPEN_CREATE,
275                                           GNUNET_DISK_PERM_USER_READ |
276                                           GNUNET_DISK_PERM_USER_WRITE |
277                                           GNUNET_DISK_PERM_GROUP_READ |
278                                           GNUNET_DISK_PERM_OTHER_READ)))
279   {
280     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
281                 "Not able to open file %s\n",
282                 file_name);
283     return;
284   }
285   /* size = GNUNET_snprintf (output_buffer,
286                           sizeof (output_buffer),
287                           "%llu %s\n",
288                           GNUNET_TIME_absolute_get ().abs_value_us,
289                           line);
290   if (0 > size)
291   {
292     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
293                 "Failed to write string to buffer (size: %i)\n",
294                 size);
295     return;
296   } */
297
298   size = strlen (line) * sizeof (char);
299
300   size2 = GNUNET_DISK_file_write (f, line, size);
301   if (size != size2)
302   {
303     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
304                 "Unable to write to file! (Size: %u, size2: %u)\n",
305                 size,
306                 size2);
307     return;
308   }
309
310   if (GNUNET_YES != GNUNET_DISK_file_close (f))
311     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
312                 "Unable to close file\n");
313 }
314
315 /**
316  * This function is used to facilitate writing important information to disk
317  */
318 #define tofile(file_name, ...) do {\
319   char tmp_buf[512];\
320     int size;\
321     size = GNUNET_snprintf(tmp_buf,sizeof(tmp_buf),__VA_ARGS__);\
322     if (0 > size)\
323       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,\
324                      "Failed to create tmp_buf\n");\
325     else\
326       tofile_(file_name,tmp_buf);\
327   } while (0);
328
329 /**
330  * Write the ids and their according index in the given array to a file 
331  * Unused
332  */
333 /* static void
334 ids_to_file (char *file_name,
335              struct GNUNET_PeerIdentity *peer_ids,
336              unsigned int num_peer_ids)
337 {
338   unsigned int i;
339
340   for (i=0 ; i < num_peer_ids ; i++)
341   {
342     to_file (file_name,
343              "%u\t%s",
344              i,
345              GNUNET_i2s_full (&peer_ids[i]));
346   }
347 } */
348
349 /**
350  * Test the success of a single test
351  */
352 static int
353 evaluate (struct RPSPeer *loc_rps_peers,
354           unsigned int num_loc_rps_peers,
355           unsigned int expected_recv)
356 {
357   unsigned int i;
358   int tmp_ok;
359
360   tmp_ok = (1 == loc_rps_peers[0].num_rec_ids);
361
362   for (i = 0 ; i < num_loc_rps_peers ; i++)
363   {
364     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
365                 "%u. peer [%s] received %u of %u expected peer_ids: %i\n",
366                 i,
367                 GNUNET_i2s (loc_rps_peers[i].peer_id),
368                 loc_rps_peers[i].num_rec_ids,
369                 expected_recv,
370                 (1 == loc_rps_peers[i].num_rec_ids));
371     tmp_ok &= (1 == loc_rps_peers[i].num_rec_ids);
372   }
373   return tmp_ok? 0 : 1;
374 }
375
376
377 /**
378  * Creates an oplist entry and adds it to the oplist DLL
379  */
380 static struct OpListEntry *
381 make_oplist_entry ()
382 {
383   struct OpListEntry *entry;
384
385   entry = GNUNET_new (struct OpListEntry);
386   GNUNET_CONTAINER_DLL_insert_tail (oplist_head, oplist_tail, entry);
387   return entry;
388 }
389
390
391 /**
392  * Callback to be called when RPS service is started or stopped at peers
393  *
394  * @param cls NULL
395  * @param op the operation handle
396  * @param emsg NULL on success; otherwise an error description
397  */
398 static void
399 churn_cb (void *cls,
400           struct GNUNET_TESTBED_Operation *op,
401           const char *emsg)
402 {
403   // FIXME
404   struct OpListEntry *entry = cls;
405
406   GNUNET_TESTBED_operation_done (entry->op);
407   if (NULL != emsg)
408   {
409     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start/stop RPS at a peer\n");
410     GNUNET_SCHEDULER_shutdown ();
411     return;
412   }
413   GNUNET_assert (0 != entry->delta);
414
415   num_peers_online += entry->delta;
416
417   if (0 > entry->delta)
418   { /* Peer hopefully just went offline */
419     if (GNUNET_YES != rps_peers[entry->index].online)
420     {
421       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
422                   "peer %s was expected to go offline but is still marked as online\n",
423                   GNUNET_i2s (rps_peers[entry->index].peer_id));
424       GNUNET_break (0);
425     }
426     else
427     {
428       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
429                   "peer %s probably went offline as expected\n",
430                   GNUNET_i2s (rps_peers[entry->index].peer_id));
431     }
432     rps_peers[entry->index].online = GNUNET_NO;
433   }
434
435   else if (0 < entry->delta)
436   { /* Peer hopefully just went online */
437     if (GNUNET_NO != rps_peers[entry->index].online)
438     {
439       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
440                   "peer %s was expected to go online but is still marked as offline\n",
441                   GNUNET_i2s (rps_peers[entry->index].peer_id));
442       GNUNET_break (0);
443     }
444     else
445     {
446       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
447                   "peer %s probably went online as expected\n",
448                   GNUNET_i2s (rps_peers[entry->index].peer_id));
449       if (NULL != cur_test_run.pre_test)
450       {
451         cur_test_run.pre_test (&rps_peers[entry->index],
452             rps_peers[entry->index].rps_handle);
453       }
454     }
455     rps_peers[entry->index].online = GNUNET_YES;
456   }
457
458   GNUNET_CONTAINER_DLL_remove (oplist_head, oplist_tail, entry);
459   GNUNET_free (entry);
460   //if (num_peers_in_round[current_round] == peers_running)
461   //  run_round ();
462 }
463
464
465 /**
466  * Task run on timeout to shut everything down.
467  */
468 static void
469 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
470 {
471   unsigned int i;
472
473   if (NULL != churn_task)
474     GNUNET_SCHEDULER_cancel (churn_task);
475
476   for (i = 0 ; i < num_peers ; i++)
477     GNUNET_TESTBED_operation_done (rps_peers[i].op);
478   GNUNET_SCHEDULER_shutdown ();
479 }
480
481
482 /**
483  * Seed peers.
484  */
485   void
486 seed_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
487 {
488   unsigned int amount;
489   struct RPSPeer *peer = (struct RPSPeer *) cls;
490   unsigned int i;
491
492   // TODO if malicious don't seed mal peers
493   amount = round (.5 * num_peers);
494
495   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Seeding peers:\n");
496   for (i = 0 ; i < amount ; i++)
497     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Seeding %u. peer: %s\n",
498                 i,
499                 GNUNET_i2s (&rps_peer_ids[i]));
500
501   GNUNET_RPS_seed_ids (peer->rps_handle, amount, rps_peer_ids);
502 }
503
504
505 /**
506  * Get the id of peer i.
507  */
508   void
509 info_cb (void *cb_cls,
510          struct GNUNET_TESTBED_Operation *op,
511          const struct GNUNET_TESTBED_PeerInformation *pinfo,
512          const char *emsg)
513 {
514   struct OpListEntry *entry = (struct OpListEntry *) cb_cls;
515
516   if (NULL == pinfo || NULL != emsg)
517   {
518     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Got Error: %s\n", emsg);
519     return;
520   }
521
522   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
523               "Peer %u is %s\n",
524               entry->index,
525               GNUNET_i2s (pinfo->result.id));
526
527   rps_peer_ids[entry->index] = *(pinfo->result.id);
528   rps_peers[entry->index].peer_id = &rps_peer_ids[entry->index];
529   rps_peers[entry->index].rec_ids = NULL;
530   rps_peers[entry->index].num_rec_ids = 0;
531
532   tofile ("/tmp/rps/peer_ids",
533            "%u\t%s\n",
534            entry->index,
535            GNUNET_i2s_full (&rps_peer_ids[entry->index]));
536
537   GNUNET_TESTBED_operation_done (entry->op);
538
539   GNUNET_CONTAINER_DLL_remove (oplist_head, oplist_tail, entry);
540   GNUNET_free (entry);
541 }
542
543
544 /**
545  * Callback to be called when RPS service connect operation is completed
546  *
547  * @param cls the callback closure from functions generating an operation
548  * @param op the operation that has been finished
549  * @param ca_result the RPS service handle returned from rps_connect_adapter
550  * @param emsg error message in case the operation has failed; will be NULL if
551  *          operation has executed successfully.
552  */
553 static void
554 rps_connect_complete_cb (void *cls,
555                          struct GNUNET_TESTBED_Operation *op,
556                          void *ca_result,
557                          const char *emsg)
558 {
559   struct RPSPeer *rps_peer = cls;
560   struct GNUNET_RPS_Handle *rps = ca_result;
561
562   rps_peer->rps_handle = rps;
563   rps_peer->online = GNUNET_YES;
564   num_peers_online++;
565
566   GNUNET_assert (op == rps_peer->op);
567   if (NULL != emsg)
568   {
569     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
570                 "Failed to connect to RPS service: %s\n",
571                 emsg);
572     ok = 1;
573     GNUNET_SCHEDULER_shutdown ();
574     return;
575   }
576
577   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started client successfully\n");
578
579   cur_test_run.main_test (rps_peer);
580 }
581
582
583 /**
584  * Adapter function called to establish a connection to
585  * the RPS service.
586  *
587  * @param cls closure
588  * @param cfg configuration of the peer to connect to; will be available until
589  *          GNUNET_TESTBED_operation_done() is called on the operation returned
590  *          from GNUNET_TESTBED_service_connect()
591  * @return service handle to return in 'op_result', NULL on error
592  */
593 static void *
594 rps_connect_adapter (void *cls,
595                                  const struct GNUNET_CONFIGURATION_Handle *cfg)
596 {
597   struct GNUNET_RPS_Handle *h;
598
599   h = GNUNET_RPS_connect (cfg);
600
601   if (NULL != cur_test_run.pre_test)
602     cur_test_run.pre_test (cls, h);
603
604   return h;
605 }
606
607
608 /**
609  * Adapter function called to destroy connection to
610  * RPS service.
611  *
612  * @param cls closure
613  * @param op_result service handle returned from the connect adapter
614  */
615 static void
616 rps_disconnect_adapter (void *cls,
617                                           void *op_result)
618 {
619   struct GNUNET_RPS_Handle *h = op_result;
620   GNUNET_RPS_disconnect (h);
621 }
622
623
624 /***********************************************************************
625  * Definition of tests
626 ***********************************************************************/
627
628 // TODO check whether tests can be stopped earlier
629 static int
630 default_eval_cb (void)
631 {
632   return evaluate (rps_peers, num_peers, 1);
633 }
634
635 static int
636 no_eval (void)
637 {
638   return 1;
639 }
640
641 /**
642  * Callback to call on receipt of a reply
643  *
644  * @param cls closure
645  * @param n number of peers
646  * @param recv_peers the received peers
647  */
648 static void
649 default_reply_handle (void *cls,
650                       uint64_t n,
651                       const struct GNUNET_PeerIdentity *recv_peers)
652 {
653   struct RPSPeer *rps_peer = (struct RPSPeer *) cls;
654   unsigned int i;
655
656   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
657               "[%s] got %" PRIu64 " peers:\n",
658               GNUNET_i2s (rps_peer->peer_id),
659               n);
660   
661   for (i = 0 ; i < n ; i++)
662   {
663     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
664                 "%u: %s\n",
665                 i,
666                 GNUNET_i2s (&recv_peers[i]));
667
668     GNUNET_array_append (rps_peer->rec_ids, rps_peer->num_rec_ids, recv_peers[i]);
669   }
670 }
671
672 /**
673  * Request random peers.
674  */
675 static void
676 request_peers (void *cls,
677                const struct GNUNET_SCHEDULER_TaskContext *tc)
678 {
679   struct RPSPeer *rps_peer = (struct RPSPeer *) cls;
680
681   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
682               "Requesting one peer\n");
683
684   GNUNET_free (GNUNET_RPS_request_peers (rps_peer->rps_handle,
685                                          1,
686                                          cur_test_run.reply_handle,
687                                          rps_peer));
688   //rps_peer->req_handle = GNUNET_RPS_request_peers (rps_peer->rps_handle, 1, handle_reply, rps_peer);
689 }
690
691
692 /***********************************
693  * MALICIOUS
694 ***********************************/
695 static void
696 mal_pre (void *cls, struct GNUNET_RPS_Handle *h)
697 {
698   #ifdef ENABLE_MALICIOUS
699   uint32_t num_mal_peers;
700   struct RPSPeer *rps_peer = (struct RPSPeer *) cls;
701
702   GNUNET_assert (1 >= portion
703                  && 0 <  portion);
704   num_mal_peers = round (portion * num_peers);
705
706   if (rps_peer->index < num_mal_peers)
707   {
708     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
709                 "%u. peer [%s] of %" PRIu32 " malicious peers turning malicious\n",
710                 rps_peer->index,
711                 GNUNET_i2s (rps_peer->peer_id),
712                 num_mal_peers);
713
714     GNUNET_RPS_act_malicious (h, mal_type, num_mal_peers, rps_peer_ids);
715   }
716   #endif /* ENABLE_MALICIOUS */
717 }
718
719 static void
720 mal_cb (struct RPSPeer *rps_peer)
721 {
722   uint32_t num_mal_peers;
723
724   #ifdef ENABLE_MALICIOUS
725   GNUNET_assert (1 >= portion
726                  && 0 <  portion);
727   num_mal_peers = round (portion * num_peers);
728
729   if (rps_peer->index >= num_mal_peers)
730   { /* It's useless to ask a malicious peer about a random sample -
731        it's not sampling */
732     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
733                                   seed_peers, rps_peer);
734     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
735                                   request_peers, rps_peer);
736   }
737   #endif /* ENABLE_MALICIOUS */
738 }
739
740 static int
741 mal_eval (void)
742 {
743   unsigned int num_mal_peers;
744
745   num_mal_peers = round (num_peers * portion);
746   return evaluate (&rps_peers[num_mal_peers],
747                    num_peers - (num_mal_peers),
748                    1);
749 }
750
751
752 /***********************************
753  * SINGLE_REQUEST
754 ***********************************/
755 static void
756 single_req_cb (struct RPSPeer *rps_peer)
757 {
758   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
759                                 request_peers, rps_peer);
760 }
761
762 /***********************************
763  * DELAYED_REQUESTS
764 ***********************************/
765 static void
766 delay_req_cb (struct RPSPeer *rps_peer)
767 {
768   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
769                                 request_peers, rps_peer);
770   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
771                                 request_peers, rps_peer);
772 }
773
774 /***********************************
775  * SEED
776 ***********************************/
777 static void
778 seed_cb (struct RPSPeer *rps_peer)
779 {
780   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
781                                 seed_peers, rps_peer);
782 }
783
784 /***********************************
785  * SEED_BIG
786 ***********************************/
787 static void
788 seed_big_cb (struct RPSPeer *rps_peer)
789 {
790   // TODO test seeding > GNUNET_SERVER_MAX_MESSAGE_SIZE peers
791 }
792
793 /***********************************
794  * SINGLE_PEER_SEED
795 ***********************************/
796 static void
797 single_peer_seed_cb (struct RPSPeer *rps_peer)
798 {
799   // TODO
800 }
801
802 /***********************************
803  * SEED_REQUEST
804 ***********************************/
805 static void
806 seed_req_cb (struct RPSPeer *rps_peer)
807 {
808   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
809                                 seed_peers, rps_peer);
810   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15),
811                                 request_peers, rps_peer);
812 }
813
814 //TODO start big mal
815
816 /***********************************
817  * REQUEST_CANCEL
818 ***********************************/
819 static void
820 req_cancel_cb (struct RPSPeer *rps_peer)
821 {
822   // TODO
823 }
824
825 /***********************************
826  * PROFILER
827 ***********************************/
828 static void
829 churn (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
830 {
831   struct OpListEntry *entry;
832   unsigned int i;
833   unsigned int j;
834   double portion_online;
835   unsigned int *permut;
836   double prob_go_offline;
837   double portion_go_online;
838   double portion_go_offline;
839   uint32_t prob;
840
841   /* Compute the probability for an online peer to go offline
842    * this round */
843   portion_online = num_peers_online * 1.0 / num_peers;
844   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
845               "Portion online: %f\n",
846               portion_online);
847   portion_go_online = ((1 - portion_online) * .5 * .66);
848   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
849               "Portion that should go online: %f\n",
850               portion_go_online);
851   portion_go_offline = (portion_online + portion_go_online) - .75;
852   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
853               "Portion that probably goes offline: %f\n",
854               portion_go_offline);
855   prob_go_offline = portion_go_offline / (portion_online * .5);
856   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
857               "Probability of a selected online peer to go offline: %f\n",
858               prob_go_offline);
859
860   permut = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
861                                          (unsigned int) num_peers);
862
863   /* Go over 50% randomly chosen peers */
864   for (i = 0 ; i < .5 * num_peers ; i++)
865   {
866     j = permut[i];
867
868     /* If online, shut down with certain probability */
869     if (GNUNET_YES == rps_peers[j].online)
870     {
871       prob = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
872                                        UINT32_MAX);
873       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
874                   "%u. selected peer (%u: %s) is online.\n",
875                   i,
876                   j,
877                   GNUNET_i2s (rps_peers[j].peer_id));
878       if (prob < prob_go_offline * UINT32_MAX)
879       {
880         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
881                     "%s goes offline\n",
882                     GNUNET_i2s (rps_peers[j].peer_id));
883
884         entry = make_oplist_entry ();
885         entry->delta = -1;
886         entry->index = j;
887         entry->op = GNUNET_TESTBED_peer_manage_service (NULL,
888                                                         testbed_peers[j],
889                                                         "rps",
890                                                         &churn_cb,
891                                                         entry,
892                                                         0);
893       }
894    }
895
896    /* If offline, restart with certain probability */
897    else if (GNUNET_NO == rps_peers[j].online)
898    {
899      prob = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
900                                       UINT32_MAX);
901      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
902                  "%u. selected peer (%u: %s) is offline.\n",
903                  i,
904                  j,
905                  GNUNET_i2s (rps_peers[j].peer_id));
906      if (prob < .66 * UINT32_MAX)
907      {
908        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
909                    "%s goes online\n",
910                    GNUNET_i2s (rps_peers[j].peer_id));
911
912        entry = make_oplist_entry ();
913        entry->delta = 1;
914        entry->index = j;
915        entry->op = GNUNET_TESTBED_peer_manage_service (NULL,
916                                                        testbed_peers[j],
917                                                        "rps",
918                                                        &churn_cb,
919                                                        entry,
920                                                        1);
921      }
922    }
923   }
924
925   GNUNET_free (permut);
926
927   churn_task = GNUNET_SCHEDULER_add_delayed (
928         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
929         churn,
930         NULL);
931 }
932
933
934 static void
935 profiler_pre (void *cls, struct GNUNET_RPS_Handle *h)
936 {
937   //churn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
938   //                                                                          10),
939   //                                           churn, NULL);
940   mal_pre (cls, h);
941
942   /* if (NULL == churn_task)
943   {
944     churn_task = GNUNET_SCHEDULER_add_delayed (
945           GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
946           churn,
947           NULL);
948   } */
949 }
950
951
952 /**
953  * Callback to call on receipt of a reply
954  *
955  * @param cls closure
956  * @param n number of peers
957  * @param recv_peers the received peers
958  */
959 static void
960 profiler_reply_handle (void *cls,
961                       uint64_t n,
962                       const struct GNUNET_PeerIdentity *recv_peers)
963 {
964   struct RPSPeer *rps_peer = (struct RPSPeer *) cls;
965   char *file_name;
966   unsigned int i;
967
968   file_name = "/tmp/rps/received_ids";
969
970   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
971               "[%s] got %" PRIu64 " peers:\n",
972               GNUNET_i2s (rps_peer->peer_id),
973               n);
974   
975   for (i = 0 ; i < n ; i++)
976   {
977     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
978                 "%u: %s\n",
979                 i,
980                 GNUNET_i2s (&recv_peers[i]));
981
982     /* GNUNET_array_append (rps_peer->rec_ids, rps_peer->num_rec_ids, recv_peers[i]); */
983     tofile (file_name,
984              "%s\n",
985              GNUNET_i2s_full (&recv_peers[i]));
986   }
987 }
988
989
990 static void
991 profiler_cb (struct RPSPeer *rps_peer)
992 {
993   uint32_t i;
994
995   /* Churn only at peers that do not request peers for evaluation */
996   if (NULL == churn_task &&
997       rps_peer->index != num_peers - 2)
998   {
999     churn_task = GNUNET_SCHEDULER_add_delayed (
1000           GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
1001           churn,
1002           NULL);
1003   }
1004
1005   /* Only request peer ids at one peer.
1006    * (It's the before-last because last one is target of the focussed attack.)
1007    */
1008   if (rps_peer->index == num_peers - 2)
1009   {
1010     for (i = 0 ; i < cur_test_run.num_requests ; i++)
1011     {
1012       GNUNET_SCHEDULER_add_delayed (
1013           GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
1014                                          cur_test_run.request_interval * i),
1015           request_peers,
1016           rps_peer);
1017     }
1018   }
1019 }
1020
1021 /**
1022  * Function called from #profiler_eval with a filename.
1023  *
1024  * @param cls closure
1025  * @param filename complete filename (absolute path)
1026  * @return #GNUNET_OK to continue to iterate,
1027  *  #GNUNET_NO to stop iteration with no error,
1028  *  #GNUNET_SYSERR to abort iteration with error!
1029  */
1030 int
1031 file_name_cb (void *cls, const char *filename)
1032 {
1033   if (NULL != strstr (filename, "sampler_el"))
1034   {
1035     struct RPS_SamplerElement *s_elem;
1036     struct GNUNET_CRYPTO_AuthKey auth_key;
1037     const char *key_char;
1038     uint32_t i;
1039
1040     key_char = filename + 20; /* Length of "/tmp/rps/sampler_el-" */
1041     tofile (filename, "--------------------------\n");
1042
1043     auth_key = string_to_auth_key (key_char);
1044     s_elem = RPS_sampler_elem_create ();
1045     RPS_sampler_elem_set (s_elem, auth_key);
1046
1047     for (i = 0; i < num_peers; i++)
1048     {
1049       RPS_sampler_elem_next (s_elem, &rps_peer_ids[i]);
1050     }
1051   }
1052   return GNUNET_OK;
1053 }
1054
1055 /**
1056  * This is run after the test finished.
1057  *
1058  * Compute all perfect samples.
1059  */
1060 int
1061 profiler_eval (void)
1062 {
1063   /* Compute perfect sample for each sampler element */
1064   if (-1 == GNUNET_DISK_directory_scan ("/tmp/rps/", file_name_cb, NULL))
1065   {
1066     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Scan of directory failed\n");
1067   }
1068
1069   return 0;
1070 }
1071
1072
1073 /***********************************************************************
1074  * /Definition of tests
1075 ***********************************************************************/
1076
1077
1078 /**
1079  * Actual "main" function for the testcase.
1080  *
1081  * @param cls closure
1082  * @param h the run handle
1083  * @param n_peers number of peers in 'peers'
1084  * @param peers handle to peers run in the testbed
1085  * @param links_succeeded the number of overlay link connection attempts that
1086  *          succeeded
1087  * @param links_failed the number of overlay link connection attempts that
1088  *          failed
1089  */
1090 static void
1091 run (void *cls,
1092      struct GNUNET_TESTBED_RunHandle *h,
1093      unsigned int n_peers,
1094      struct GNUNET_TESTBED_Peer **peers,
1095      unsigned int links_succeeded,
1096      unsigned int links_failed)
1097 {
1098   unsigned int i;
1099   struct OpListEntry *entry;
1100
1101   testbed_peers = peers;
1102   num_peers_online = 0;
1103
1104   for (i = 0 ; i < num_peers ; i++)
1105   {
1106     entry = make_oplist_entry ();
1107     entry->index = i;
1108     entry->op = GNUNET_TESTBED_peer_get_information (peers[i],
1109                                                      GNUNET_TESTBED_PIT_IDENTITY,
1110                                                      &info_cb,
1111                                                      entry);
1112   }
1113
1114
1115   // This seems not to work
1116   //if (NULL != strstr (cur_test_run.name, "profiler"))
1117   //{
1118   //  churn_task = GNUNET_SCHEDULER_add_delayed (
1119   //      GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
1120   //      churn,
1121   //      NULL);
1122   //}
1123
1124   GNUNET_assert (num_peers == n_peers);
1125   for (i = 0 ; i < n_peers ; i++)
1126   {
1127     rps_peers[i].index = i;
1128     rps_peers[i].op =
1129       GNUNET_TESTBED_service_connect (&rps_peers[i],
1130                                                                           peers[i],
1131                                                                           "rps",
1132                                                                           &rps_connect_complete_cb,
1133                                                                           &rps_peers[i],
1134                                                                           &rps_connect_adapter,
1135                                                                           &rps_disconnect_adapter,
1136                                                                           &rps_peers[i]);
1137   }
1138
1139   if (NULL != churn_task)
1140     GNUNET_SCHEDULER_cancel (churn_task);
1141
1142   GNUNET_SCHEDULER_add_delayed (timeout, &shutdown_task, NULL);
1143 }
1144
1145
1146 /**
1147  * Entry point for the testcase, sets up the testbed.
1148  *
1149  * @param argc unused
1150  * @param argv unused
1151  * @return 0 on success
1152  */
1153 int
1154 main (int argc, char *argv[])
1155 {
1156   cur_test_run.name = "test-rps-default";
1157   cur_test_run.pre_test = NULL;
1158   cur_test_run.reply_handle = default_reply_handle;
1159   cur_test_run.eval_cb = default_eval_cb;
1160   churn_task = NULL;
1161
1162   num_peers = 5;
1163   timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30);
1164
1165   if (strstr (argv[0], "malicious") != NULL)
1166   {
1167     cur_test_run.pre_test = mal_pre;
1168     cur_test_run.main_test = mal_cb;
1169     cur_test_run.eval_cb = mal_eval;
1170
1171     if (strstr (argv[0], "_1") != NULL)
1172     {
1173       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 1\n");
1174       cur_test_run.name = "test-rps-malicious_1";
1175       mal_type = 1;
1176     }
1177     else if (strstr (argv[0], "_2") != NULL)
1178     {
1179       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 2\n");
1180       cur_test_run.name = "test-rps-malicious_2";
1181       mal_type = 2;
1182     }
1183     else if (strstr (argv[0], "_3") != NULL)
1184     {
1185       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 3\n");
1186       cur_test_run.name = "test-rps-malicious_3";
1187       mal_type = 3;
1188     }
1189   }
1190
1191   else if (strstr (argv[0], "_single_req") != NULL)
1192   {
1193     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test single request\n");
1194     cur_test_run.name = "test-rps-single-req";
1195     cur_test_run.main_test = single_req_cb;
1196   }
1197
1198   else if (strstr (argv[0], "_delayed_reqs") != NULL)
1199   {
1200     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test delayed requests\n");
1201     cur_test_run.name = "test-rps-delayed-reqs";
1202     cur_test_run.main_test = delay_req_cb;
1203   }
1204
1205   else if (strstr (argv[0], "_seed_big") != NULL)
1206   {
1207     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding (num_peers > GNUNET_SERVER_MAX_MESSAGE_SIZE)\n");
1208     cur_test_run.name = "test-rps-seed-big";
1209     cur_test_run.main_test = seed_big_cb;
1210   }
1211
1212   else if (strstr (argv[0], "_single_peer_seed") != NULL)
1213   {
1214     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding and requesting on a single peer\n");
1215     cur_test_run.name = "test-rps-single-peer-seed";
1216     cur_test_run.main_test = single_peer_seed_cb;
1217   }
1218
1219   else if (strstr (argv[0], "_seed_request") != NULL)
1220   {
1221     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding and requesting on multiple peers\n");
1222     cur_test_run.name = "test-rps-seed-request";
1223     cur_test_run.main_test = seed_req_cb;
1224   }
1225
1226   else if (strstr (argv[0], "_seed") != NULL)
1227   {
1228     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding\n");
1229     cur_test_run.name = "test-rps-seed";
1230     cur_test_run.main_test = seed_cb;
1231     cur_test_run.eval_cb = no_eval;
1232   }
1233
1234   else if (strstr (argv[0], "_req_cancel") != NULL)
1235   {
1236     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test cancelling a request\n");
1237     cur_test_run.name = "test-rps-req-cancel";
1238     cur_test_run.main_test = req_cancel_cb;
1239   }
1240
1241   else if (strstr (argv[0], "profiler") != NULL)
1242   {
1243     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "This is the profiler\n");
1244     cur_test_run.name = "test-rps-profiler";
1245     mal_type = 3;
1246     cur_test_run.pre_test = profiler_pre;
1247     cur_test_run.main_test = profiler_cb;
1248     cur_test_run.reply_handle = profiler_reply_handle;
1249     cur_test_run.eval_cb = profiler_eval;
1250     cur_test_run.request_interval = 2;
1251     cur_test_run.num_requests = 50;
1252
1253     num_peers = 50;
1254
1255     (void) GNUNET_DISK_directory_remove ("/tmp/rps/");
1256     GNUNET_DISK_directory_create ("/tmp/rps/");
1257     timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 90);
1258   }
1259
1260   rps_peers = GNUNET_new_array (num_peers, struct RPSPeer);
1261   rps_peer_ids = GNUNET_new_array (num_peers, struct GNUNET_PeerIdentity);
1262
1263   ok = 1;
1264   (void) GNUNET_TESTBED_test_run (cur_test_run.name,
1265                                   "test_rps.conf",
1266                                   num_peers,
1267                                   0, NULL, NULL,
1268                                   &run, NULL);
1269
1270   return cur_test_run.eval_cb();
1271 }
1272
1273 /* end of test_rps_multipeer.c */