4ef97ad925da7ebd1795ed5dd5a850787cbdeb70
[oweals/gnunet.git] / src / rps / test_rps.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2012 GNUnet e.V.
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.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 static 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  * @brief Indicates whether peer should go off- or online
67  */
68 enum PEER_ONLINE_DELTA {
69   /**
70    * @brief Indicates peer going online
71    */
72   PEER_GO_ONLINE = 1,
73   /**
74    * @brief Indicates peer going offline
75    */
76   PEER_GO_OFFLINE = -1,
77 };
78
79 /**
80  * Operation map entry
81  */
82 struct OpListEntry
83 {
84   /**
85    * DLL next ptr
86    */
87   struct OpListEntry *next;
88
89   /**
90    * DLL prev ptr
91    */
92   struct OpListEntry *prev;
93
94   /**
95    * The testbed operation
96    */
97   struct GNUNET_TESTBED_Operation *op;
98
99   /**
100    * Depending on whether we start or stop RPS service at the peer, set this to
101    * #PEER_GO_ONLINE (1) or #PEER_GO_OFFLINE (-1)
102    */
103   enum PEER_ONLINE_DELTA delta;
104
105   /**
106    * Index of the regarding peer
107    */
108   unsigned int index;
109 };
110
111 /**
112  * OpList DLL head
113  */
114 static struct OpListEntry *oplist_head;
115
116 /**
117  * OpList DLL tail
118  */
119 static struct OpListEntry *oplist_tail;
120
121
122 /**
123  * A pending reply: A request was sent and the reply is pending.
124  */
125 struct PendingReply
126 {
127   /**
128    * DLL next,prev ptr
129    */
130   struct PendingReply *next;
131   struct PendingReply *prev;
132
133   /**
134    * Handle to the request we are waiting for
135    */
136   struct GNUNET_RPS_Request_Handle *req_handle;
137
138   /**
139    * The peer that requested
140    */
141   struct RPSPeer *rps_peer;
142 };
143
144
145 /**
146  * A pending request: A request was not made yet but is scheduled for later.
147  */
148 struct PendingRequest
149 {
150   /**
151    * DLL next,prev ptr
152    */
153   struct PendingRequest *next;
154   struct PendingRequest *prev;
155
156   /**
157    * Handle to the request we are waiting for
158    */
159   struct GNUNET_SCHEDULER_Task *request_task;
160
161   /**
162    * The peer that requested
163    */
164   struct RPSPeer *rps_peer;
165 };
166
167
168 /**
169  * Information we track for each peer.
170  */
171 struct RPSPeer
172 {
173   /**
174    * Index of the peer.
175    */
176   unsigned int index;
177
178   /**
179    * Handle for RPS connect operation.
180    */
181   struct GNUNET_TESTBED_Operation *op;
182
183   /**
184    * Handle to RPS service.
185    */
186   struct GNUNET_RPS_Handle *rps_handle;
187
188   /**
189    * ID of the peer.
190    */
191   struct GNUNET_PeerIdentity *peer_id;
192
193   /**
194    * A request handle to check for an request
195    */
196   //struct GNUNET_RPS_Request_Handle *req_handle;
197
198   /**
199    * Peer on- or offline?
200    */
201   int online;
202
203   /**
204    * Number of Peer IDs to request during the whole test
205    */
206   unsigned int num_ids_to_request;
207
208   /**
209    * Pending requests DLL
210    */
211   struct PendingRequest *pending_req_head;
212   struct PendingRequest *pending_req_tail;
213
214   /**
215    * Number of pending requests
216    */
217   unsigned int num_pending_reqs;
218
219   /**
220    * Pending replies DLL
221    */
222   struct PendingReply *pending_rep_head;
223   struct PendingReply *pending_rep_tail;
224
225   /**
226    * Number of pending replies
227    */
228   unsigned int num_pending_reps;
229
230   /**
231    * Number of received PeerIDs
232    */
233   unsigned int num_recv_ids;
234
235   /**
236    * Pending operation on that peer
237    */
238   const struct OpListEntry *entry_op_manage;
239
240   /**
241    * Testbed operation to connect to statistics service
242    */
243   struct GNUNET_TESTBED_Operation *stat_op;
244
245   /**
246    * Handle to the statistics service
247    */
248   struct GNUNET_STATISTICS_Handle *stats_h;
249
250   /**
251    * @brief flags to indicate which statistics values have been already
252    * collected from the statistics service.
253    * Used to check whether we are able to shutdown.
254    */
255   uint32_t stat_collected_flags;
256
257   /**
258    * @brief File name of the file the stats are finally written to
259    */
260   char *file_name_stats;
261 };
262
263 enum STAT_TYPE
264 {
265   STAT_TYPE_ROUNDS                    =    0x1, /*   1 */
266   STAT_TYPE_BLOCKS                    =    0x2, /*   2 */
267   STAT_TYPE_BLOCKS_MANY_PUSH          =    0x4, /*   3 */
268   STAT_TYPE_BLOCKS_NO_PUSH            =    0x8, /*   4 */
269   STAT_TYPE_BLOCKS_NO_PULL            =   0x10, /*   5 */
270   STAT_TYPE_BLOCKS_MANY_PUSH_NO_PULL  =   0x20, /*   6 */
271   STAT_TYPE_BLOCKS_NO_PUSH_NO_PULL    =   0x40, /*   7 */
272   STAT_TYPE_ISSUED_PUSH_SEND          =   0x80, /*   8 */
273   STAT_TYPE_ISSUED_PULL_REQ           =  0x100, /*   9 */
274   STAT_TYPE_ISSUED_PULL_REP           =  0x200, /*  10 */
275   STAT_TYPE_SENT_PUSH_SEND            =  0x400, /*  11 */
276   STAT_TYPE_SENT_PULL_REQ             =  0x800, /*  12 */
277   STAT_TYPE_SENT_PULL_REP             = 0x1000, /*  13 */
278   STAT_TYPE_RECV_PUSH_SEND            = 0x2000, /*  14 */
279   STAT_TYPE_RECV_PULL_REQ             = 0x4000, /*  15 */
280   STAT_TYPE_RECV_PULL_REP             = 0x8000, /*  16 */
281   STAT_TYPE_MAX          = 0x80000000, /*  32 */
282 };
283
284 struct STATcls
285 {
286   struct RPSPeer *rps_peer;
287   enum STAT_TYPE stat_type;
288 };
289
290
291 /**
292  * Information for all the peers.
293  */
294 static struct RPSPeer *rps_peers;
295
296 /**
297  * Peermap to get the index of a given peer ID quick.
298  */
299 static struct GNUNET_CONTAINER_MultiPeerMap *peer_map;
300
301 /**
302  * IDs of the peers.
303  */
304 static struct GNUNET_PeerIdentity *rps_peer_ids;
305
306 /**
307  * ID of the targeted peer.
308  */
309 static struct GNUNET_PeerIdentity *target_peer;
310
311 /**
312  * ID of the peer that requests for the evaluation.
313  */
314 static struct RPSPeer *eval_peer;
315
316 /**
317  * Number of online peers.
318  */
319 static unsigned int num_peers_online;
320
321 /**
322  * Return value from 'main'.
323  */
324 static int ok;
325
326 /**
327  * Identifier for the churn task that runs periodically
328  */
329 static struct GNUNET_SCHEDULER_Task *shutdown_task;
330
331 /**
332  * Identifier for the churn task that runs periodically
333  */
334 static struct GNUNET_SCHEDULER_Task *churn_task;
335
336 /**
337  * Called to initialise the given RPSPeer
338  */
339 typedef void (*InitPeer) (struct RPSPeer *rps_peer);
340
341 /**
342  * @brief Called directly after connecting to the service
343  *
344  * @param rps_peer Specific peer the function is called on
345  * @param h the handle to the rps service
346  */
347 typedef void (*PreTest) (struct RPSPeer *rps_peer, struct GNUNET_RPS_Handle *h);
348
349 /**
350  * @brief Executes functions to test the api/service for a given peer
351  *
352  * Called from within #rps_connect_complete_cb ()
353  * Implemented by #churn_test_cb, #profiler_cb, #mal_cb, #single_req_cb,
354  * #delay_req_cb, #seed_big_cb, #single_peer_seed_cb, #seed_cb, #req_cancel_cb
355  *
356  * @param rps_peer the peer the task runs on
357  */
358 typedef void (*MainTest) (struct RPSPeer *rps_peer);
359
360 /**
361  * Callback called once the requested random peers are available
362  */
363 typedef void (*ReplyHandle) (void *cls,
364                              uint64_t n,
365                              const struct GNUNET_PeerIdentity *recv_peers);
366
367 /**
368  * Called directly before disconnecting from the service
369  */
370 typedef void (*PostTest) (struct RPSPeer *peer);
371
372 /**
373  * Function called after disconnect to evaluate test success
374  */
375 typedef int (*EvaluationCallback) (void);
376
377 /**
378  * @brief Do we have Churn?
379  */
380 enum OPTION_CHURN {
381   /**
382    * @brief If we have churn this is set
383    */
384   HAVE_CHURN,
385   /**
386    * @brief If we have no churn this is set
387    */
388   HAVE_NO_CHURN,
389 };
390
391 /**
392  * @brief Is it ok to quit the test before the timeout?
393  */
394 enum OPTION_QUICK_QUIT {
395   /**
396    * @brief It is ok for the test to quit before the timeout triggers
397    */
398   HAVE_QUICK_QUIT,
399
400   /**
401    * @brief It is NOT ok for the test to quit before the timeout triggers
402    */
403   HAVE_NO_QUICK_QUIT,
404 };
405
406 /**
407  * @brief Do we collect statistics at the end?
408  */
409 enum OPTION_COLLECT_STATISTICS {
410   /**
411    * @brief We collect statistics at the end
412    */
413   COLLECT_STATISTICS,
414
415   /**
416    * @brief We do not collect statistics at the end
417    */
418   NO_COLLECT_STATISTICS,
419 };
420
421 /**
422  * Structure to define a single test
423  */
424 struct SingleTestRun
425 {
426   /**
427    * Name of the test
428    */
429   char *name;
430
431   /**
432    * Called with a single peer in order to initialise that peer
433    */
434   InitPeer init_peer;
435
436   /**
437    * Called directly after connecting to the service
438    */
439   PreTest pre_test;
440
441   /**
442    * Main function for each peer
443    */
444   MainTest main_test;
445
446   /**
447    * Callback called once the requested peers are available
448    */
449   ReplyHandle reply_handle;
450
451   /**
452    * Called directly before disconnecting from the service
453    */
454   PostTest post_test;
455
456   /**
457    * Function to evaluate the test results
458    */
459   EvaluationCallback eval_cb;
460
461   /**
462    * Request interval
463    */
464   uint32_t request_interval;
465
466   /**
467    * Number of Requests to make.
468    */
469   uint32_t num_requests;
470
471   /**
472    * Run with (-out) churn
473    */
474   enum OPTION_CHURN have_churn;
475
476   /**
477    * Quit test before timeout?
478    */
479   enum OPTION_QUICK_QUIT have_quick_quit;
480
481   /**
482    * Collect statistics at the end?
483    */
484   enum OPTION_COLLECT_STATISTICS have_collect_statistics;
485
486   /**
487    * @brief Mark which values from the statistics service to collect at the end
488    * of the run
489    */
490   uint32_t stat_collect_flags;
491 } cur_test_run;
492
493 /**
494  * Are we shutting down?
495  */
496 static int in_shutdown;
497
498 /**
499  * Append arguments to file
500  */
501 static void
502 tofile_ (const char *file_name, const char *line)
503 {
504   struct GNUNET_DISK_FileHandle *f;
505   /* char output_buffer[512]; */
506   size_t size;
507   /* int size; */
508   size_t size2;
509
510   if (NULL == (f = GNUNET_DISK_file_open (file_name,
511                                           GNUNET_DISK_OPEN_APPEND |
512                                           GNUNET_DISK_OPEN_WRITE |
513                                           GNUNET_DISK_OPEN_CREATE,
514                                           GNUNET_DISK_PERM_USER_READ |
515                                           GNUNET_DISK_PERM_USER_WRITE |
516                                           GNUNET_DISK_PERM_GROUP_READ |
517                                           GNUNET_DISK_PERM_OTHER_READ)))
518   {
519     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
520                 "Not able to open file %s\n",
521                 file_name);
522     return;
523   }
524   /* size = GNUNET_snprintf (output_buffer,
525                           sizeof (output_buffer),
526                           "%llu %s\n",
527                           GNUNET_TIME_absolute_get ().abs_value_us,
528                           line);
529   if (0 > size)
530   {
531     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
532                 "Failed to write string to buffer (size: %i)\n",
533                 size);
534     return;
535   } */
536
537   size = strlen (line) * sizeof (char);
538
539   size2 = GNUNET_DISK_file_write (f, line, size);
540   if (size != size2)
541   {
542     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
543                 "Unable to write to file! (Size: %lu, size2: %lu)\n",
544                 size,
545                 size2);
546     if (GNUNET_YES != GNUNET_DISK_file_close (f))
547     {
548       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
549                   "Unable to close file\n");
550     }
551     return;
552   }
553
554   if (GNUNET_YES != GNUNET_DISK_file_close (f))
555   {
556     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
557                 "Unable to close file\n");
558   }
559 }
560
561 /**
562  * This function is used to facilitate writing important information to disk
563  */
564 #define tofile(file_name, ...) do {\
565   char tmp_buf[512];\
566     int size;\
567     size = GNUNET_snprintf(tmp_buf,sizeof(tmp_buf),__VA_ARGS__);\
568     if (0 > size)\
569       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,\
570                      "Failed to create tmp_buf\n");\
571     else\
572       tofile_(file_name,tmp_buf);\
573   } while (0);
574
575
576 /**
577  * Write the ids and their according index in the given array to a file
578  * Unused
579  */
580 /* static void
581 ids_to_file (char *file_name,
582              struct GNUNET_PeerIdentity *peer_ids,
583              unsigned int num_peer_ids)
584 {
585   unsigned int i;
586
587   for (i=0 ; i < num_peer_ids ; i++)
588   {
589     to_file (file_name,
590              "%u\t%s",
591              i,
592              GNUNET_i2s_full (&peer_ids[i]));
593   }
594 } */
595
596 /**
597  * Test the success of a single test
598  */
599 static int
600 evaluate (void)
601 {
602   unsigned int i;
603   int tmp_ok;
604
605   tmp_ok = 1;
606
607   for (i = 0; i < num_peers; i++)
608   {
609     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
610         "%u. peer [%s] received %u of %u expected peer_ids: %i\n",
611         i,
612         GNUNET_i2s (rps_peers[i].peer_id),
613         rps_peers[i].num_recv_ids,
614         rps_peers[i].num_ids_to_request,
615         (rps_peers[i].num_ids_to_request == rps_peers[i].num_recv_ids));
616     tmp_ok &= (rps_peers[i].num_ids_to_request == rps_peers[i].num_recv_ids);
617   }
618   return tmp_ok? 0 : 1;
619 }
620
621
622 /**
623  * Creates an oplist entry and adds it to the oplist DLL
624  */
625 static struct OpListEntry *
626 make_oplist_entry ()
627 {
628   struct OpListEntry *entry;
629
630   entry = GNUNET_new (struct OpListEntry);
631   GNUNET_CONTAINER_DLL_insert_tail (oplist_head, oplist_tail, entry);
632   return entry;
633 }
634
635
636 /**
637  * @brief Checks if given peer already received its statistics value from the
638  * statistics service.
639  *
640  * @param rps_peer the peer to check for
641  *
642  * @return #GNUNET_YES if so
643  *         #GNUNET_NO otherwise
644  */
645 static int check_statistics_collect_completed_single_peer (
646     const struct RPSPeer *rps_peer)
647 {
648   if (cur_test_run.stat_collect_flags !=
649         (cur_test_run.stat_collect_flags &
650           rps_peer->stat_collected_flags))
651   {
652     return GNUNET_NO;
653   }
654   return GNUNET_YES;
655 }
656 /**
657  * @brief Checks if all peers already received their statistics value from the
658  * statistics service.
659  *
660  * @return #GNUNET_YES if so
661  *         #GNUNET_NO otherwise
662  */
663 static int check_statistics_collect_completed ()
664 {
665   uint32_t i;
666
667   for (i = 0; i < num_peers; i++)
668   {
669     if (GNUNET_NO == check_statistics_collect_completed_single_peer (&rps_peers[i]))
670     {
671       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
672           "At least Peer %" PRIu32 " did not yet receive all statistics values\n",
673           i);
674       return GNUNET_NO;
675     }
676   }
677   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
678       "All peers received their statistics values\n");
679   return GNUNET_YES;
680 }
681
682 /**
683  * Task run on timeout to shut everything down.
684  */
685 static void
686 shutdown_op (void *cls)
687 {
688   unsigned int i;
689
690   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
691               "Shutdown task scheduled, going down.\n");
692   in_shutdown = GNUNET_YES;
693   if (NULL != churn_task)
694   {
695     GNUNET_SCHEDULER_cancel (churn_task);
696     churn_task = NULL;
697   }
698   for (i = 0; i < num_peers; i++)
699   {
700     if (NULL != rps_peers[i].op)
701       GNUNET_TESTBED_operation_done (rps_peers[i].op);
702     if (NULL != cur_test_run.post_test)
703     {
704       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing post_test for peer %u\n", i);
705       cur_test_run.post_test (&rps_peers[i]);
706     }
707   }
708   /* If we do not collect statistics, shut down directly */
709   if (NO_COLLECT_STATISTICS == cur_test_run.have_collect_statistics ||
710       GNUNET_YES == check_statistics_collect_completed())
711   {
712     GNUNET_SCHEDULER_shutdown ();
713   }
714 }
715
716
717 /**
718  * Seed peers.
719  */
720 static void
721 seed_peers (void *cls)
722 {
723   struct RPSPeer *peer = cls;
724   unsigned int amount;
725   unsigned int i;
726
727   // TODO if malicious don't seed mal peers
728   amount = round (.5 * num_peers);
729
730   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Seeding peers:\n");
731   for (i = 0 ; i < amount ; i++)
732     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Seeding %u. peer: %s\n",
733                 i,
734                 GNUNET_i2s (&rps_peer_ids[i]));
735
736   GNUNET_RPS_seed_ids (peer->rps_handle, amount, rps_peer_ids);
737 }
738
739
740 /**
741  * Seed peers.
742  */
743 static void
744 seed_peers_big (void *cls)
745 {
746   struct RPSPeer *peer = cls;
747   unsigned int seed_msg_size;
748   uint32_t num_peers_max;
749   unsigned int amount;
750   unsigned int i;
751
752   seed_msg_size = 8; /* sizeof (struct GNUNET_RPS_CS_SeedMessage) */
753   num_peers_max = (GNUNET_MAX_MESSAGE_SIZE - seed_msg_size) /
754     sizeof (struct GNUNET_PeerIdentity);
755   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
756       "Peers that fit in one seed msg; %u\n",
757       num_peers_max);
758   amount = num_peers_max + (0.5 * num_peers_max);
759   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
760       "Seeding many (%u) peers:\n",
761       amount);
762   struct GNUNET_PeerIdentity ids_to_seed[amount];
763   for (i = 0; i < amount; i++)
764   {
765     ids_to_seed[i] = *peer->peer_id;
766     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Seeding %u. peer: %s\n",
767                 i,
768                 GNUNET_i2s (&ids_to_seed[i]));
769   }
770
771   GNUNET_RPS_seed_ids (peer->rps_handle, amount, ids_to_seed);
772 }
773
774 /**
775  * Get the id of peer i.
776  */
777   void
778 info_cb (void *cb_cls,
779          struct GNUNET_TESTBED_Operation *op,
780          const struct GNUNET_TESTBED_PeerInformation *pinfo,
781          const char *emsg)
782 {
783   struct OpListEntry *entry = (struct OpListEntry *) cb_cls;
784
785   if (GNUNET_YES == in_shutdown)
786   {
787     return;
788   }
789
790   if (NULL == pinfo || NULL != emsg)
791   {
792     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Got Error: %s\n", emsg);
793     GNUNET_TESTBED_operation_done (entry->op);
794     return;
795   }
796
797   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
798               "Peer %u is %s\n",
799               entry->index,
800               GNUNET_i2s (pinfo->result.id));
801
802   rps_peer_ids[entry->index] = *(pinfo->result.id);
803   rps_peers[entry->index].peer_id = &rps_peer_ids[entry->index];
804
805   GNUNET_assert (GNUNET_OK ==
806       GNUNET_CONTAINER_multipeermap_put (peer_map,
807         &rps_peer_ids[entry->index],
808         &rps_peers[entry->index],
809         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
810   tofile ("/tmp/rps/peer_ids",
811            "%u\t%s\n",
812            entry->index,
813            GNUNET_i2s_full (&rps_peer_ids[entry->index]));
814
815   GNUNET_CONTAINER_DLL_remove (oplist_head, oplist_tail, entry);
816   GNUNET_TESTBED_operation_done (entry->op);
817   GNUNET_free (entry);
818 }
819
820
821 /**
822  * Callback to be called when RPS service connect operation is completed
823  *
824  * @param cls the callback closure from functions generating an operation
825  * @param op the operation that has been finished
826  * @param ca_result the RPS service handle returned from rps_connect_adapter
827  * @param emsg error message in case the operation has failed; will be NULL if
828  *          operation has executed successfully.
829  */
830 static void
831 rps_connect_complete_cb (void *cls,
832                          struct GNUNET_TESTBED_Operation *op,
833                          void *ca_result,
834                          const char *emsg)
835 {
836   struct RPSPeer *rps_peer = cls;
837   struct GNUNET_RPS_Handle *rps = ca_result;
838
839   if (GNUNET_YES == in_shutdown)
840   {
841     return;
842   }
843
844   rps_peer->rps_handle = rps;
845   rps_peer->online = GNUNET_YES;
846   num_peers_online++;
847
848   GNUNET_assert (op == rps_peer->op);
849   if (NULL != emsg)
850   {
851     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
852                 "Failed to connect to RPS service: %s\n",
853                 emsg);
854     ok = 1;
855     GNUNET_SCHEDULER_shutdown ();
856     return;
857   }
858
859   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started client successfully\n");
860
861   cur_test_run.main_test (rps_peer);
862 }
863
864
865 /**
866  * Adapter function called to establish a connection to
867  * the RPS service.
868  *
869  * @param cls closure
870  * @param cfg configuration of the peer to connect to; will be available until
871  *          GNUNET_TESTBED_operation_done() is called on the operation returned
872  *          from GNUNET_TESTBED_service_connect()
873  * @return service handle to return in 'op_result', NULL on error
874  */
875 static void *
876 rps_connect_adapter (void *cls,
877                                  const struct GNUNET_CONFIGURATION_Handle *cfg)
878 {
879   struct GNUNET_RPS_Handle *h;
880
881   h = GNUNET_RPS_connect (cfg);
882
883   if (NULL != cur_test_run.pre_test)
884     cur_test_run.pre_test (cls, h);
885
886   return h;
887 }
888
889 /**
890  * Called to open a connection to the peer's statistics
891  *
892  * @param cls peer context
893  * @param cfg configuration of the peer to connect to; will be available until
894  *          GNUNET_TESTBED_operation_done() is called on the operation returned
895  *          from GNUNET_TESTBED_service_connect()
896  * @return service handle to return in 'op_result', NULL on error
897  */
898 static void *
899 stat_connect_adapter (void *cls,
900                       const struct GNUNET_CONFIGURATION_Handle *cfg)
901 {
902   struct RPSPeer *peer = cls;
903
904   peer->stats_h = GNUNET_STATISTICS_create ("rps-profiler", cfg);
905   return peer->stats_h;
906 }
907
908 /**
909  * Called to disconnect from peer's statistics service
910  *
911  * @param cls peer context
912  * @param op_result service handle returned from the connect adapter
913  */
914 static void
915 stat_disconnect_adapter (void *cls, void *op_result)
916 {
917   struct RPSPeer *peer = cls;
918
919   //GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch_cancel
920   //              (peer->stats_h, "core", "# peers connected",
921   //               stat_iterator, peer));
922   //GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch_cancel
923   //              (peer->stats_h, "nse", "# peers connected",
924   //               stat_iterator, peer));
925   GNUNET_STATISTICS_destroy (op_result, GNUNET_NO);
926   peer->stats_h = NULL;
927 }
928
929 /**
930  * Called after successfully opening a connection to a peer's statistics
931  * service; we register statistics monitoring for CORE and NSE here.
932  *
933  * @param cls the callback closure from functions generating an operation
934  * @param op the operation that has been finished
935  * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter()
936  * @param emsg error message in case the operation has failed; will be NULL if
937  *          operation has executed successfully.
938  */
939 static void
940 stat_complete_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
941                   void *ca_result, const char *emsg )
942 {
943   //struct GNUNET_STATISTICS_Handle *sh = ca_result;
944   //struct RPSPeer *peer = (struct RPSPeer *) cls;
945
946   if (NULL != emsg)
947   {
948     GNUNET_break (0);
949     return;
950   }
951   //GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch
952   //              (sh, "core", "# peers connected",
953   //               stat_iterator, peer));
954   //GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch
955   //              (sh, "nse", "# peers connected",
956   //               stat_iterator, peer));
957 }
958
959
960 /**
961  * Adapter function called to destroy connection to
962  * RPS service.
963  *
964  * @param cls closure
965  * @param op_result service handle returned from the connect adapter
966  */
967 static void
968 rps_disconnect_adapter (void *cls,
969                                           void *op_result)
970 {
971   struct RPSPeer *peer = cls;
972   struct GNUNET_RPS_Handle *h = op_result;
973   GNUNET_assert (NULL != peer);
974   GNUNET_RPS_disconnect (h);
975   peer->rps_handle = NULL;
976 }
977
978
979 /***********************************************************************
980  * Definition of tests
981 ***********************************************************************/
982
983 // TODO check whether tests can be stopped earlier
984 static int
985 default_eval_cb (void)
986 {
987   return evaluate ();
988 }
989
990 static int
991 no_eval (void)
992 {
993   return 0;
994 }
995
996 /**
997  * Initialise given RPSPeer
998  */
999 static void default_init_peer (struct RPSPeer *rps_peer)
1000 {
1001   rps_peer->num_ids_to_request = 1;
1002 }
1003
1004 /**
1005  * Callback to call on receipt of a reply
1006  *
1007  * @param cls closure
1008  * @param n number of peers
1009  * @param recv_peers the received peers
1010  */
1011 static void
1012 default_reply_handle (void *cls,
1013                       uint64_t n,
1014                       const struct GNUNET_PeerIdentity *recv_peers)
1015 {
1016   struct RPSPeer *rps_peer;
1017   struct PendingReply *pending_rep = (struct PendingReply *) cls;
1018   unsigned int i;
1019
1020   rps_peer = pending_rep->rps_peer;
1021   GNUNET_CONTAINER_DLL_remove (rps_peer->pending_rep_head,
1022                                rps_peer->pending_rep_tail,
1023                                pending_rep);
1024   rps_peer->num_pending_reps--;
1025   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1026               "[%s] got %" PRIu64 " peers:\n",
1027               GNUNET_i2s (rps_peer->peer_id),
1028               n);
1029
1030   for (i = 0; i < n; i++)
1031   {
1032     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1033                 "%u: %s\n",
1034                 i,
1035                 GNUNET_i2s (&recv_peers[i]));
1036
1037     rps_peer->num_recv_ids++;
1038   }
1039
1040   if (0 == evaluate () && HAVE_QUICK_QUIT == cur_test_run.have_quick_quit)
1041   {
1042     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test succeeded before timeout\n");
1043     GNUNET_assert (NULL != shutdown_task);
1044     GNUNET_SCHEDULER_cancel (shutdown_task);
1045     shutdown_task = GNUNET_SCHEDULER_add_now (&shutdown_op, NULL);
1046     GNUNET_assert (NULL!= shutdown_task);
1047   }
1048 }
1049
1050 /**
1051  * Request random peers.
1052  */
1053 static void
1054 request_peers (void *cls)
1055 {
1056   struct PendingRequest *pending_req = cls;
1057   struct RPSPeer *rps_peer;
1058   struct PendingReply *pending_rep;
1059
1060   if (GNUNET_YES == in_shutdown)
1061     return;
1062   rps_peer = pending_req->rps_peer;
1063   GNUNET_assert (1 <= rps_peer->num_pending_reqs);
1064   GNUNET_CONTAINER_DLL_remove (rps_peer->pending_req_head,
1065                                rps_peer->pending_req_tail,
1066                                pending_req);
1067   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1068               "Requesting one peer\n");
1069   pending_rep = GNUNET_new (struct PendingReply);
1070   pending_rep->rps_peer = rps_peer;
1071   pending_rep->req_handle = GNUNET_RPS_request_peers (rps_peer->rps_handle,
1072       1,
1073       cur_test_run.reply_handle,
1074       pending_rep);
1075   GNUNET_CONTAINER_DLL_insert_tail (rps_peer->pending_rep_head,
1076                                     rps_peer->pending_rep_tail,
1077                                     pending_rep);
1078   rps_peer->num_pending_reps++;
1079   rps_peer->num_pending_reqs--;
1080 }
1081
1082 static void
1083 cancel_pending_req (struct PendingRequest *pending_req)
1084 {
1085   struct RPSPeer *rps_peer;
1086
1087   rps_peer = pending_req->rps_peer;
1088   GNUNET_CONTAINER_DLL_remove (rps_peer->pending_req_head,
1089                                rps_peer->pending_req_tail,
1090                                pending_req);
1091   rps_peer->num_pending_reqs--;
1092   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1093               "Cancelling pending request\n");
1094   GNUNET_SCHEDULER_cancel (pending_req->request_task);
1095   GNUNET_free (pending_req);
1096 }
1097
1098 static void
1099 cancel_request (struct PendingReply *pending_rep)
1100 {
1101   struct RPSPeer *rps_peer;
1102
1103   rps_peer = pending_rep->rps_peer;
1104   GNUNET_CONTAINER_DLL_remove (rps_peer->pending_rep_head,
1105                                rps_peer->pending_rep_tail,
1106                                pending_rep);
1107   rps_peer->num_pending_reps--;
1108   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1109               "Cancelling request\n");
1110   GNUNET_RPS_request_cancel (pending_rep->req_handle);
1111   GNUNET_free (pending_rep);
1112 }
1113
1114 /**
1115  * Cancel a request.
1116  */
1117 static void
1118 cancel_request_cb (void *cls)
1119 {
1120   struct RPSPeer *rps_peer = cls;
1121   struct PendingReply *pending_rep;
1122
1123   if (GNUNET_YES == in_shutdown)
1124     return;
1125   pending_rep = rps_peer->pending_rep_head;
1126   GNUNET_assert (1 <= rps_peer->num_pending_reps);
1127   cancel_request (pending_rep);
1128 }
1129
1130
1131 /**
1132  * Schedule requests for peer @a rps_peer that have neither been scheduled, nor
1133  * issued, nor replied
1134  */
1135 void
1136 schedule_missing_requests (struct RPSPeer *rps_peer)
1137 {
1138   unsigned int i;
1139   struct PendingRequest *pending_req;
1140
1141   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1142       "Scheduling %u - %u missing requests\n",
1143       rps_peer->num_ids_to_request,
1144       rps_peer->num_pending_reqs + rps_peer->num_pending_reps);
1145   GNUNET_assert (rps_peer->num_pending_reqs + rps_peer->num_pending_reps <=
1146       rps_peer->num_ids_to_request);
1147   for (i = rps_peer->num_pending_reqs + rps_peer->num_pending_reps;
1148        i < rps_peer->num_ids_to_request; i++)
1149   {
1150     pending_req = GNUNET_new (struct PendingRequest);
1151     pending_req->rps_peer = rps_peer;
1152     pending_req->request_task = GNUNET_SCHEDULER_add_delayed (
1153         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
1154           cur_test_run.request_interval * i),
1155         request_peers,
1156         pending_req);
1157     GNUNET_CONTAINER_DLL_insert_tail (rps_peer->pending_req_head,
1158                                       rps_peer->pending_req_tail,
1159                                       pending_req);
1160     rps_peer->num_pending_reqs++;
1161   }
1162 }
1163
1164 void
1165 cancel_pending_req_rep (struct RPSPeer *rps_peer)
1166 {
1167   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1168       "Cancelling all (pending) requests.\n");
1169   while (NULL != rps_peer->pending_req_head)
1170     cancel_pending_req (rps_peer->pending_req_head);
1171   GNUNET_assert (0 == rps_peer->num_pending_reqs);
1172   while (NULL != rps_peer->pending_rep_head)
1173     cancel_request (rps_peer->pending_rep_head);
1174   GNUNET_assert (0 == rps_peer->num_pending_reps);
1175 }
1176
1177 /***********************************
1178  * MALICIOUS
1179 ***********************************/
1180
1181 /**
1182  * Initialise only non-mal RPSPeers
1183  */
1184 static void mal_init_peer (struct RPSPeer *rps_peer)
1185 {
1186   if (rps_peer->index >= round (portion * num_peers))
1187     rps_peer->num_ids_to_request = 1;
1188 }
1189
1190
1191 /**
1192  * @brief Set peers to (non-)malicious before execution
1193  *
1194  * Of signature #PreTest
1195  *
1196  * @param rps_peer the peer to set (non-) malicious
1197  * @param h the handle to the service
1198  */
1199 static void
1200 mal_pre (struct RPSPeer *rps_peer, struct GNUNET_RPS_Handle *h)
1201 {
1202   #ifdef ENABLE_MALICIOUS
1203   uint32_t num_mal_peers;
1204
1205   GNUNET_assert ( (1 >= portion) &&
1206                   (0 <  portion) );
1207   num_mal_peers = round (portion * num_peers);
1208
1209   if (rps_peer->index < num_mal_peers)
1210   {
1211     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1212                 "%u. peer [%s] of %" PRIu32 " malicious peers turning malicious\n",
1213                 rps_peer->index,
1214                 GNUNET_i2s (rps_peer->peer_id),
1215                 num_mal_peers);
1216
1217     GNUNET_RPS_act_malicious (h, mal_type, num_mal_peers,
1218                               rps_peer_ids, target_peer);
1219   }
1220   #endif /* ENABLE_MALICIOUS */
1221 }
1222
1223 static void
1224 mal_cb (struct RPSPeer *rps_peer)
1225 {
1226   uint32_t num_mal_peers;
1227
1228   if (GNUNET_YES == in_shutdown)
1229   {
1230     return;
1231   }
1232
1233   #ifdef ENABLE_MALICIOUS
1234   GNUNET_assert ( (1 >= portion) &&
1235                   (0 <  portion) );
1236   num_mal_peers = round (portion * num_peers);
1237
1238   if (rps_peer->index >= num_mal_peers)
1239   { /* It's useless to ask a malicious peer about a random sample -
1240        it's not sampling */
1241     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
1242                                   seed_peers, rps_peer);
1243     schedule_missing_requests (rps_peer);
1244   }
1245   #endif /* ENABLE_MALICIOUS */
1246 }
1247
1248
1249 /***********************************
1250  * SINGLE_REQUEST
1251 ***********************************/
1252 static void
1253 single_req_cb (struct RPSPeer *rps_peer)
1254 {
1255   if (GNUNET_YES == in_shutdown)
1256   {
1257     return;
1258   }
1259
1260   schedule_missing_requests (rps_peer);
1261 }
1262
1263 /***********************************
1264  * DELAYED_REQUESTS
1265 ***********************************/
1266 static void
1267 delay_req_cb (struct RPSPeer *rps_peer)
1268 {
1269   if (GNUNET_YES == in_shutdown)
1270   {
1271     return;
1272   }
1273
1274   schedule_missing_requests (rps_peer);
1275 }
1276
1277 /***********************************
1278  * SEED
1279 ***********************************/
1280 static void
1281 seed_cb (struct RPSPeer *rps_peer)
1282 {
1283   if (GNUNET_YES == in_shutdown)
1284   {
1285     return;
1286   }
1287
1288   GNUNET_SCHEDULER_add_delayed (
1289       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
1290       seed_peers, rps_peer);
1291 }
1292
1293 /***********************************
1294  * SEED_BIG
1295 ***********************************/
1296 static void
1297 seed_big_cb (struct RPSPeer *rps_peer)
1298 {
1299   if (GNUNET_YES == in_shutdown)
1300   {
1301     return;
1302   }
1303
1304   // TODO test seeding > GNUNET_MAX_MESSAGE_SIZE peers
1305   GNUNET_SCHEDULER_add_delayed (
1306       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
1307       seed_peers_big, rps_peer);
1308 }
1309
1310 /***********************************
1311  * SINGLE_PEER_SEED
1312 ***********************************/
1313 static void
1314 single_peer_seed_cb (struct RPSPeer *rps_peer)
1315 {
1316   // TODO
1317 }
1318
1319 /***********************************
1320  * SEED_REQUEST
1321 ***********************************/
1322 static void
1323 seed_req_cb (struct RPSPeer *rps_peer)
1324 {
1325   if (GNUNET_YES == in_shutdown)
1326   {
1327     return;
1328   }
1329
1330   GNUNET_SCHEDULER_add_delayed (
1331       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
1332       seed_peers, rps_peer);
1333   schedule_missing_requests (rps_peer);
1334 }
1335
1336 //TODO start big mal
1337
1338 /***********************************
1339  * REQUEST_CANCEL
1340 ***********************************/
1341 static void
1342 req_cancel_cb (struct RPSPeer *rps_peer)
1343 {
1344   if (GNUNET_YES == in_shutdown)
1345   {
1346     return;
1347   }
1348
1349   schedule_missing_requests (rps_peer);
1350   GNUNET_SCHEDULER_add_delayed (
1351       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
1352                                      (cur_test_run.request_interval + 1)),
1353       cancel_request_cb, rps_peer);
1354 }
1355
1356 /***********************************
1357  * CHURN
1358 ***********************************/
1359
1360 static void
1361 churn (void *cls);
1362
1363 /**
1364  * @brief Starts churn
1365  *
1366  * Has signature of #MainTest
1367  *
1368  * This is not implemented too nicely as this is called for each peer, but we
1369  * only need to call it once. (Yes we check that we only schedule the task
1370  * once.)
1371  *
1372  * @param rps_peer The peer it's called for
1373  */
1374 static void
1375 churn_test_cb (struct RPSPeer *rps_peer)
1376 {
1377   if (GNUNET_YES == in_shutdown)
1378   {
1379     return;
1380   }
1381
1382   /* Start churn */
1383   if (HAVE_CHURN == cur_test_run.have_churn && NULL == churn_task)
1384   {
1385     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1386                 "Starting churn task\n");
1387     churn_task = GNUNET_SCHEDULER_add_delayed (
1388           GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
1389           churn,
1390           NULL);
1391   } else {
1392     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1393                 "Not starting churn task\n");
1394   }
1395
1396   schedule_missing_requests (rps_peer);
1397 }
1398
1399 /***********************************
1400  * PROFILER
1401 ***********************************/
1402
1403 /**
1404  * Callback to be called when RPS service is started or stopped at peers
1405  *
1406  * @param cls NULL
1407  * @param op the operation handle
1408  * @param emsg NULL on success; otherwise an error description
1409  */
1410 static void
1411 churn_cb (void *cls,
1412           struct GNUNET_TESTBED_Operation *op,
1413           const char *emsg)
1414 {
1415   // FIXME
1416   struct OpListEntry *entry = cls;
1417
1418   if (GNUNET_YES == in_shutdown)
1419   {
1420     return;
1421   }
1422
1423   GNUNET_TESTBED_operation_done (entry->op);
1424   if (NULL != emsg)
1425   {
1426     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start/stop RPS at a peer\n");
1427     GNUNET_SCHEDULER_shutdown ();
1428     return;
1429   }
1430   GNUNET_assert (0 != entry->delta);
1431
1432   num_peers_online += entry->delta;
1433
1434   if (PEER_GO_OFFLINE == entry->delta)
1435   { /* Peer hopefully just went offline */
1436     if (GNUNET_YES != rps_peers[entry->index].online)
1437     {
1438       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1439                   "peer %s was expected to go offline but is still marked as online\n",
1440                   GNUNET_i2s (rps_peers[entry->index].peer_id));
1441       GNUNET_break (0);
1442     }
1443     else
1444     {
1445       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1446                   "peer %s probably went offline as expected\n",
1447                   GNUNET_i2s (rps_peers[entry->index].peer_id));
1448     }
1449     rps_peers[entry->index].online = GNUNET_NO;
1450   }
1451
1452   else if (PEER_GO_ONLINE < entry->delta)
1453   { /* Peer hopefully just went online */
1454     if (GNUNET_NO != rps_peers[entry->index].online)
1455     {
1456       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1457                   "peer %s was expected to go online but is still marked as offline\n",
1458                   GNUNET_i2s (rps_peers[entry->index].peer_id));
1459       GNUNET_break (0);
1460     }
1461     else
1462     {
1463       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1464                   "peer %s probably went online as expected\n",
1465                   GNUNET_i2s (rps_peers[entry->index].peer_id));
1466       if (NULL != cur_test_run.pre_test)
1467       {
1468         cur_test_run.pre_test (&rps_peers[entry->index],
1469             rps_peers[entry->index].rps_handle);
1470         schedule_missing_requests (&rps_peers[entry->index]);
1471       }
1472     }
1473     rps_peers[entry->index].online = GNUNET_YES;
1474   }
1475   else
1476   {
1477     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1478         "Invalid value for delta: %i\n", entry->delta);
1479     GNUNET_break (0);
1480   }
1481
1482   GNUNET_CONTAINER_DLL_remove (oplist_head, oplist_tail, entry);
1483   rps_peers[entry->index].entry_op_manage = NULL;
1484   GNUNET_free (entry);
1485   //if (num_peers_in_round[current_round] == peers_running)
1486   //  run_round ();
1487 }
1488
1489 /**
1490  * @brief Set the rps-service up or down for a specific peer
1491  *
1492  * @param i index of action
1493  * @param j index of peer
1494  * @param delta (#PEER_ONLINE_DELTA) down (-1) or up (1)
1495  * @param prob_go_on_off the probability of the action
1496  */
1497 static void
1498 manage_service_wrapper (unsigned int i, unsigned int j,
1499                         enum PEER_ONLINE_DELTA delta,
1500                         double prob_go_on_off)
1501 {
1502   struct OpListEntry *entry = NULL;
1503   uint32_t prob;
1504
1505   /* make sure that management operation is not already scheduled */
1506   if (NULL != rps_peers[j].entry_op_manage)
1507   {
1508     return;
1509   }
1510
1511   prob = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1512                                    UINT32_MAX);
1513   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1514               "%u. selected peer (%u: %s) is %s.\n",
1515               i,
1516               j,
1517               GNUNET_i2s (rps_peers[j].peer_id),
1518               (PEER_GO_ONLINE == delta) ? "online" : "offline");
1519   if (prob < prob_go_on_off * UINT32_MAX)
1520   {
1521     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1522                 "%s goes %s\n",
1523                 GNUNET_i2s (rps_peers[j].peer_id),
1524                 (PEER_GO_OFFLINE == delta) ? "offline" : "online");
1525
1526     if (PEER_GO_OFFLINE == delta)
1527       cancel_pending_req_rep (&rps_peers[j]);
1528     entry = make_oplist_entry ();
1529     entry->delta = delta;
1530     entry->index = j;
1531     entry->op = GNUNET_TESTBED_peer_manage_service (NULL,
1532                                                     testbed_peers[j],
1533                                                     "rps",
1534                                                     &churn_cb,
1535                                                     entry,
1536                                                     (PEER_GO_OFFLINE == delta) ? 0 : 1);
1537     rps_peers[j].entry_op_manage = entry;
1538   }
1539 }
1540
1541
1542 static void
1543 churn (void *cls)
1544 {
1545   unsigned int i;
1546   unsigned int j;
1547   double portion_online;
1548   unsigned int *permut;
1549   double prob_go_offline;
1550   double portion_go_online;
1551   double portion_go_offline;
1552
1553   if (GNUNET_YES == in_shutdown)
1554   {
1555     return;
1556   }
1557   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1558               "Churn function executing\n");
1559
1560   churn_task = NULL; /* Should be invalid by now */
1561
1562   /* Compute the probability for an online peer to go offline
1563    * this round */
1564   portion_online = num_peers_online * 1.0 / num_peers;
1565   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1566               "Portion online: %f\n",
1567               portion_online);
1568   portion_go_online = ((1 - portion_online) * .5 * .66);
1569   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1570               "Portion that should go online: %f\n",
1571               portion_go_online);
1572   portion_go_offline = (portion_online + portion_go_online) - .75;
1573   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1574               "Portion that probably goes offline: %f\n",
1575               portion_go_offline);
1576   prob_go_offline = portion_go_offline / (portion_online * .5);
1577   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1578               "Probability of a selected online peer to go offline: %f\n",
1579               prob_go_offline);
1580
1581   permut = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
1582                                          (unsigned int) num_peers);
1583
1584   /* Go over 50% randomly chosen peers */
1585   for (i = 0; i < .5 * num_peers; i++)
1586   {
1587     j = permut[i];
1588
1589     /* If online, shut down with certain probability */
1590     if (GNUNET_YES == rps_peers[j].online)
1591     {
1592       manage_service_wrapper (i, j, -1, prob_go_offline);
1593     }
1594
1595     /* If offline, restart with certain probability */
1596     else if (GNUNET_NO == rps_peers[j].online)
1597     {
1598       manage_service_wrapper (i, j, 1, 0.66);
1599     }
1600   }
1601
1602   GNUNET_free (permut);
1603
1604   churn_task = GNUNET_SCHEDULER_add_delayed (
1605         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
1606         churn,
1607         NULL);
1608 }
1609
1610
1611 /**
1612  * Initialise given RPSPeer
1613  */
1614 static void profiler_init_peer (struct RPSPeer *rps_peer)
1615 {
1616   if (num_peers - 1 == rps_peer->index)
1617     rps_peer->num_ids_to_request = cur_test_run.num_requests;
1618 }
1619
1620
1621 /**
1622  * Callback to call on receipt of a reply
1623  *
1624  * @param cls closure
1625  * @param n number of peers
1626  * @param recv_peers the received peers
1627  */
1628 static void
1629 profiler_reply_handle (void *cls,
1630                       uint64_t n,
1631                       const struct GNUNET_PeerIdentity *recv_peers)
1632 {
1633   struct RPSPeer *rps_peer;
1634   struct RPSPeer *rcv_rps_peer;
1635   char *file_name;
1636   char *file_name_dh;
1637   unsigned int i;
1638   struct PendingReply *pending_rep = (struct PendingReply *) cls;
1639
1640   rps_peer = pending_rep->rps_peer;
1641   file_name = "/tmp/rps/received_ids";
1642   file_name_dh = "/tmp/rps/diehard_input";
1643   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1644               "[%s] got %" PRIu64 " peers:\n",
1645               GNUNET_i2s (rps_peer->peer_id),
1646               n);
1647   for (i = 0; i < n; i++)
1648   {
1649     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1650                 "%u: %s\n",
1651                 i,
1652                 GNUNET_i2s (&recv_peers[i]));
1653     tofile (file_name,
1654              "%s\n",
1655              GNUNET_i2s_full (&recv_peers[i]));
1656     rcv_rps_peer = GNUNET_CONTAINER_multipeermap_get (peer_map, &recv_peers[i]);
1657     GNUNET_assert (NULL != rcv_rps_peer);
1658     tofile (file_name_dh,
1659              "%" PRIu32 "\n",
1660              (uint32_t) rcv_rps_peer->index);
1661   }
1662   default_reply_handle (cls, n, recv_peers);
1663 }
1664
1665
1666 static void
1667 profiler_cb (struct RPSPeer *rps_peer)
1668 {
1669   if (GNUNET_YES == in_shutdown)
1670   {
1671     return;
1672   }
1673
1674   /* Start churn */
1675   if (HAVE_CHURN == cur_test_run.have_churn && NULL == churn_task)
1676   {
1677     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1678                 "Starting churn task\n");
1679     churn_task = GNUNET_SCHEDULER_add_delayed (
1680           GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
1681           churn,
1682           NULL);
1683   } else {
1684     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1685                 "Not starting churn task\n");
1686   }
1687
1688   /* Only request peer ids at one peer.
1689    * (It's the before-last because last one is target of the focussed attack.)
1690    */
1691   if (eval_peer == rps_peer)
1692     schedule_missing_requests (rps_peer);
1693 }
1694
1695 /**
1696  * Function called from #profiler_eval with a filename.
1697  *
1698  * @param cls closure
1699  * @param filename complete filename (absolute path)
1700  * @return #GNUNET_OK to continue to iterate,
1701  *  #GNUNET_NO to stop iteration with no error,
1702  *  #GNUNET_SYSERR to abort iteration with error!
1703  */
1704 int
1705 file_name_cb (void *cls, const char *filename)
1706 {
1707   if (NULL != strstr (filename, "sampler_el"))
1708   {
1709     struct RPS_SamplerElement *s_elem;
1710     struct GNUNET_CRYPTO_AuthKey auth_key;
1711     const char *key_char;
1712     uint32_t i;
1713
1714     key_char = filename + 20; /* Length of "/tmp/rps/sampler_el-" */
1715     tofile (filename, "--------------------------\n");
1716
1717     auth_key = string_to_auth_key (key_char);
1718     s_elem = RPS_sampler_elem_create ();
1719     RPS_sampler_elem_set (s_elem, auth_key);
1720
1721     for (i = 0; i < num_peers; i++)
1722     {
1723       RPS_sampler_elem_next (s_elem, &rps_peer_ids[i]);
1724     }
1725     RPS_sampler_elem_destroy (s_elem);
1726   }
1727   return GNUNET_OK;
1728 }
1729
1730 /**
1731  * This is run after the test finished.
1732  *
1733  * Compute all perfect samples.
1734  */
1735 int
1736 profiler_eval (void)
1737 {
1738   /* Compute perfect sample for each sampler element */
1739   if (-1 == GNUNET_DISK_directory_scan ("/tmp/rps/", file_name_cb, NULL))
1740   {
1741     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Scan of directory failed\n");
1742   }
1743
1744   return evaluate ();
1745 }
1746
1747 /**
1748  * @brief Try to ensure that `/tmp/rps` exists.
1749  *
1750  * @return #GNUNET_YES on success
1751  *         #GNUNET_SYSERR on failure
1752  */
1753 static int ensure_folder_exist (void)
1754 {
1755   if (GNUNET_NO == GNUNET_DISK_directory_test ("/tmp/rps/", GNUNET_NO))
1756   {
1757     GNUNET_DISK_directory_create ("/tmp/rps");
1758   }
1759   if (GNUNET_YES != GNUNET_DISK_directory_test ("/tmp/rps/", GNUNET_NO))
1760   {
1761     return GNUNET_SYSERR;
1762   }
1763   return GNUNET_YES;
1764 }
1765
1766 static void
1767 store_stats_file_name (struct RPSPeer *rps_peer)
1768 {
1769   unsigned int len_file_name;
1770   unsigned int out_size;
1771   char *file_name;
1772
1773   if (GNUNET_SYSERR == ensure_folder_exist()) return;
1774   len_file_name = (14 + strlen (GNUNET_i2s_full (rps_peer->peer_id)) + 1) * sizeof (char);
1775   file_name = GNUNET_malloc (len_file_name);
1776   out_size = GNUNET_snprintf (file_name,
1777                               len_file_name,
1778                               "/tmp/rps/stat-%s",
1779                               GNUNET_i2s_full (rps_peer->peer_id));
1780   if (len_file_name < out_size ||
1781       0 > out_size)
1782   {
1783     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1784                "Failed to write string to buffer (size: %i, out_size: %i)\n",
1785                len_file_name,
1786                out_size);
1787   }
1788   rps_peer->file_name_stats = file_name;
1789 }
1790
1791 /**
1792  * Continuation called by #GNUNET_STATISTICS_get() functions.
1793  *
1794  * Remembers that this specific statistics value was received for this peer.
1795  * Checks whether all peers received their statistics yet.
1796  * Issues the shutdown.
1797  *
1798  * @param cls closure
1799  * @param success #GNUNET_OK if statistics were
1800  *        successfully obtained, #GNUNET_SYSERR if not.
1801  */
1802 void
1803 post_test_shutdown_ready_cb (void *cls,
1804                              int success)
1805 {
1806   struct STATcls *stat_cls = (struct STATcls *) cls;
1807   struct RPSPeer *rps_peer = stat_cls->rps_peer;
1808   if (GNUNET_OK == success)
1809   {
1810     /* set flag that we we got the value */
1811     rps_peer->stat_collected_flags |= stat_cls->stat_type;
1812   } else {
1813     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1814         "Peer %u did not receive statistics value\n",
1815         rps_peer->index);
1816     GNUNET_free (stat_cls);
1817     GNUNET_break (0);
1818   }
1819
1820   if (NULL != rps_peer->stat_op &&
1821       GNUNET_YES == check_statistics_collect_completed_single_peer (rps_peer))
1822   {
1823     GNUNET_TESTBED_operation_done (rps_peer->stat_op);
1824   }
1825
1826   if (GNUNET_YES == check_statistics_collect_completed())
1827   {
1828     GNUNET_free (stat_cls);
1829     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1830         "Shutting down\n");
1831     GNUNET_SCHEDULER_shutdown ();
1832   } else {
1833     GNUNET_free (stat_cls);
1834   }
1835 }
1836
1837 /**
1838  * @brief Converts #STAT_TYPE enum to the equivalent string representation that
1839  * is stored with the statistics service.
1840  *
1841  * @param stat_type #STAT_TYPE enum
1842  *
1843  * @return string representation that matches statistics value
1844  */
1845 char* stat_type_2_str (enum STAT_TYPE stat_type)
1846 {
1847   switch (stat_type)
1848   {
1849     case STAT_TYPE_ROUNDS:
1850       return "# rounds";
1851     case STAT_TYPE_BLOCKS:
1852       return "# rounds blocked";
1853     case STAT_TYPE_BLOCKS_MANY_PUSH:
1854       return "# rounds blocked - too many pushes";
1855     case STAT_TYPE_BLOCKS_NO_PUSH:
1856       return "# rounds blocked - no pushes";
1857     case STAT_TYPE_BLOCKS_NO_PULL:
1858       return "# rounds blocked - no pull replies";
1859     case STAT_TYPE_BLOCKS_MANY_PUSH_NO_PULL:
1860       return "# rounds blocked - too many pushes, no pull replies";
1861     case STAT_TYPE_BLOCKS_NO_PUSH_NO_PULL:
1862       return "# rounds blocked - no pushes, no pull replies";
1863     case STAT_TYPE_ISSUED_PUSH_SEND:
1864       return "# push send issued";
1865     case STAT_TYPE_ISSUED_PULL_REQ:
1866       return "# pull request send issued";
1867     case STAT_TYPE_ISSUED_PULL_REP:
1868       return "# pull reply send issued";
1869     case STAT_TYPE_SENT_PUSH_SEND:
1870       return "# pushes sent";
1871     case STAT_TYPE_SENT_PULL_REQ:
1872       return "# pull requests sent";
1873     case STAT_TYPE_SENT_PULL_REP:
1874       return "# pull replys sent";
1875     case STAT_TYPE_RECV_PUSH_SEND:
1876       return "# push message received";
1877     case STAT_TYPE_RECV_PULL_REQ:
1878       return "# pull request message received";
1879     case STAT_TYPE_RECV_PULL_REP:
1880       return "# pull reply messages received";
1881     case STAT_TYPE_MAX:
1882     default:
1883       return "ERROR";
1884       ;
1885   }
1886 }
1887
1888 /**
1889  * Callback function to process statistic values.
1890  *
1891  * @param cls closure
1892  * @param subsystem name of subsystem that created the statistic
1893  * @param name the name of the datum
1894  * @param value the current value
1895  * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
1896  * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
1897  */
1898 int
1899 stat_iterator (void *cls,
1900                const char *subsystem,
1901                const char *name,
1902                uint64_t value,
1903                int is_persistent)
1904 {
1905   const struct STATcls *stat_cls = (const struct STATcls *) cls;
1906   const struct RPSPeer *rps_peer = (const struct RPSPeer *) stat_cls->rps_peer;
1907   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got stat value: %s - %" PRIu64 "\n",
1908       //stat_type_2_str (stat_cls->stat_type),
1909       name,
1910       value);
1911   to_file (rps_peer->file_name_stats,
1912           "%s: %" PRIu64 "\n",
1913           name,
1914           value);
1915   return GNUNET_OK;
1916 }
1917
1918 void post_profiler (struct RPSPeer *rps_peer)
1919 {
1920   if (COLLECT_STATISTICS != cur_test_run.have_collect_statistics)
1921   {
1922     return;
1923   }
1924
1925   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1926       "Going to request statistic values with mask 0x%" PRIx32 "\n",
1927       cur_test_run.stat_collect_flags);
1928
1929   struct STATcls *stat_cls;
1930   uint32_t stat_type;
1931   for (stat_type = STAT_TYPE_ROUNDS;
1932       stat_type < STAT_TYPE_MAX;
1933       stat_type = stat_type <<1)
1934   {
1935     if (stat_type & cur_test_run.stat_collect_flags)
1936     {
1937       stat_cls = GNUNET_malloc (sizeof (struct STATcls));
1938       stat_cls->rps_peer = rps_peer;
1939       stat_cls->stat_type = stat_type;
1940       store_stats_file_name (rps_peer);
1941       GNUNET_STATISTICS_get (rps_peer->stats_h,
1942                              "rps",
1943                              stat_type_2_str (stat_type),
1944                              post_test_shutdown_ready_cb,
1945                              stat_iterator,
1946                              (struct STATcls *) stat_cls);
1947       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1948           "Requested statistics for %s (peer %" PRIu32 ")\n",
1949           stat_type_2_str (stat_type),
1950           rps_peer->index);
1951     }
1952   }
1953 }
1954
1955
1956 /***********************************************************************
1957  * /Definition of tests
1958 ***********************************************************************/
1959
1960
1961 /**
1962  * Actual "main" function for the testcase.
1963  *
1964  * @param cls closure
1965  * @param h the run handle
1966  * @param n_peers number of peers in 'peers'
1967  * @param peers handle to peers run in the testbed
1968  * @param links_succeeded the number of overlay link connection attempts that
1969  *          succeeded
1970  * @param links_failed the number of overlay link connection attempts that
1971  *          failed
1972  */
1973 static void
1974 run (void *cls,
1975      struct GNUNET_TESTBED_RunHandle *h,
1976      unsigned int n_peers,
1977      struct GNUNET_TESTBED_Peer **peers,
1978      unsigned int links_succeeded,
1979      unsigned int links_failed)
1980 {
1981   unsigned int i;
1982   struct OpListEntry *entry;
1983   uint32_t num_mal_peers;
1984
1985   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "RUN was called\n");
1986
1987   /* Check whether we timed out */
1988   if (n_peers != num_peers ||
1989       NULL == peers ||
1990       0 == links_succeeded)
1991   {
1992     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Going down due to args (eg. timeout)\n");
1993     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\tn_peers: %u\n", n_peers);
1994     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\tnum_peers: %" PRIu32 "\n", num_peers);
1995     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\tpeers: %p\n", peers);
1996     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\tlinks_succeeded: %u\n", links_succeeded);
1997     GNUNET_SCHEDULER_shutdown ();
1998     return;
1999   }
2000
2001
2002   /* Initialize peers */
2003   testbed_peers = peers;
2004   num_peers_online = 0;
2005   for (i = 0; i < num_peers; i++)
2006   {
2007     entry = make_oplist_entry ();
2008     entry->index = i;
2009     rps_peers[i].index = i;
2010     if (NULL != cur_test_run.init_peer)
2011       cur_test_run.init_peer (&rps_peers[i]);
2012     entry->op = GNUNET_TESTBED_peer_get_information (peers[i],
2013                                                      GNUNET_TESTBED_PIT_IDENTITY,
2014                                                      &info_cb,
2015                                                      entry);
2016   }
2017
2018   /* Bring peers up */
2019   num_mal_peers = round (portion * num_peers);
2020   GNUNET_assert (num_peers == n_peers);
2021   for (i = 0; i < n_peers; i++)
2022   {
2023     rps_peers[i].index = i;
2024     if ( (rps_peers[i].num_recv_ids < rps_peers[i].num_ids_to_request) ||
2025          (i < num_mal_peers) )
2026     {
2027       rps_peers[i].op =
2028         GNUNET_TESTBED_service_connect (&rps_peers[i],
2029                                         peers[i],
2030                                         "rps",
2031                                         &rps_connect_complete_cb,
2032                                         &rps_peers[i],
2033                                         &rps_connect_adapter,
2034                                         &rps_disconnect_adapter,
2035                                         &rps_peers[i]);
2036     }
2037     /* Connect all peers to statistics service */
2038     if (COLLECT_STATISTICS == cur_test_run.have_collect_statistics)
2039     {
2040       rps_peers[i].stat_op =
2041         GNUNET_TESTBED_service_connect (NULL,
2042                                         peers[i],
2043                                         "statistics",
2044                                         stat_complete_cb,
2045                                         &rps_peers[i],
2046                                         &stat_connect_adapter,
2047                                         &stat_disconnect_adapter,
2048                                         &rps_peers[i]);
2049     }
2050   }
2051
2052   if (NULL != churn_task)
2053     GNUNET_SCHEDULER_cancel (churn_task);
2054   shutdown_task = GNUNET_SCHEDULER_add_delayed (timeout, &shutdown_op, NULL);
2055 }
2056
2057
2058 /**
2059  * Entry point for the testcase, sets up the testbed.
2060  *
2061  * @param argc unused
2062  * @param argv unused
2063  * @return 0 on success
2064  */
2065 int
2066 main (int argc, char *argv[])
2067 {
2068   int ret_value;
2069
2070   num_peers = 5;
2071   cur_test_run.name = "test-rps-default";
2072   cur_test_run.init_peer = default_init_peer;
2073   cur_test_run.pre_test = NULL;
2074   cur_test_run.reply_handle = default_reply_handle;
2075   cur_test_run.eval_cb = default_eval_cb;
2076   cur_test_run.post_test = NULL;
2077   cur_test_run.have_churn = HAVE_CHURN;
2078   cur_test_run.have_collect_statistics = NO_COLLECT_STATISTICS;
2079   cur_test_run.stat_collect_flags = 0;
2080   churn_task = NULL;
2081   timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30);
2082
2083   if (strstr (argv[0], "malicious") != NULL)
2084   {
2085     cur_test_run.pre_test = mal_pre;
2086     cur_test_run.main_test = mal_cb;
2087     cur_test_run.init_peer = mal_init_peer;
2088
2089     if (strstr (argv[0], "_1") != NULL)
2090     {
2091       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 1\n");
2092       cur_test_run.name = "test-rps-malicious_1";
2093       mal_type = 1;
2094     }
2095     else if (strstr (argv[0], "_2") != NULL)
2096     {
2097       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 2\n");
2098       cur_test_run.name = "test-rps-malicious_2";
2099       mal_type = 2;
2100     }
2101     else if (strstr (argv[0], "_3") != NULL)
2102     {
2103       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 3\n");
2104       cur_test_run.name = "test-rps-malicious_3";
2105       mal_type = 3;
2106     }
2107   }
2108
2109   else if (strstr (argv[0], "_single_req") != NULL)
2110   {
2111     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test single request\n");
2112     cur_test_run.name = "test-rps-single-req";
2113     cur_test_run.main_test = single_req_cb;
2114     cur_test_run.have_churn = HAVE_NO_CHURN;
2115   }
2116
2117   else if (strstr (argv[0], "_delayed_reqs") != NULL)
2118   {
2119     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test delayed requests\n");
2120     cur_test_run.name = "test-rps-delayed-reqs";
2121     cur_test_run.main_test = delay_req_cb;
2122     cur_test_run.have_churn = HAVE_NO_CHURN;
2123   }
2124
2125   else if (strstr (argv[0], "_seed_big") != NULL)
2126   {
2127     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding (num_peers > GNUNET_MAX_MESSAGE_SIZE)\n");
2128     num_peers = 1;
2129     cur_test_run.name = "test-rps-seed-big";
2130     cur_test_run.main_test = seed_big_cb;
2131     cur_test_run.eval_cb = no_eval;
2132     cur_test_run.have_churn = HAVE_NO_CHURN;
2133     timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10);
2134   }
2135
2136   else if (strstr (argv[0], "_single_peer_seed") != NULL)
2137   {
2138     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding and requesting on a single peer\n");
2139     cur_test_run.name = "test-rps-single-peer-seed";
2140     cur_test_run.main_test = single_peer_seed_cb;
2141     cur_test_run.have_churn = HAVE_NO_CHURN;
2142   }
2143
2144   else if (strstr (argv[0], "_seed_request") != NULL)
2145   {
2146     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding and requesting on multiple peers\n");
2147     cur_test_run.name = "test-rps-seed-request";
2148     cur_test_run.main_test = seed_req_cb;
2149     cur_test_run.have_churn = HAVE_NO_CHURN;
2150   }
2151
2152   else if (strstr (argv[0], "_seed") != NULL)
2153   {
2154     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding\n");
2155     cur_test_run.name = "test-rps-seed";
2156     cur_test_run.main_test = seed_cb;
2157     cur_test_run.eval_cb = no_eval;
2158     cur_test_run.have_churn = HAVE_NO_CHURN;
2159   }
2160
2161   else if (strstr (argv[0], "_req_cancel") != NULL)
2162   {
2163     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test cancelling a request\n");
2164     cur_test_run.name = "test-rps-req-cancel";
2165     num_peers = 1;
2166     cur_test_run.main_test = req_cancel_cb;
2167     cur_test_run.eval_cb = no_eval;
2168     cur_test_run.have_churn = HAVE_NO_CHURN;
2169     timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10);
2170   }
2171
2172   else if (strstr (argv[0], "_churn") != NULL)
2173   {
2174     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test churn\n");
2175     cur_test_run.name = "test-rps-churn";
2176     num_peers = 5;
2177     cur_test_run.init_peer = default_init_peer;
2178     cur_test_run.main_test = churn_test_cb;
2179     cur_test_run.reply_handle = default_reply_handle;
2180     cur_test_run.eval_cb = default_eval_cb;
2181     cur_test_run.have_churn = HAVE_CHURN;
2182     cur_test_run.have_quick_quit = HAVE_NO_QUICK_QUIT;
2183     timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10);
2184   }
2185
2186   else if (strstr (argv[0], "profiler") != NULL)
2187   {
2188     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "This is the profiler\n");
2189     cur_test_run.name = "test-rps-profiler";
2190     num_peers = 10;
2191     mal_type = 3;
2192     cur_test_run.init_peer = profiler_init_peer;
2193     cur_test_run.pre_test = mal_pre;
2194     cur_test_run.main_test = profiler_cb;
2195     cur_test_run.reply_handle = profiler_reply_handle;
2196     cur_test_run.eval_cb = profiler_eval;
2197     cur_test_run.post_test = post_profiler;
2198     cur_test_run.request_interval = 2;
2199     cur_test_run.num_requests = 5;
2200     cur_test_run.have_churn = HAVE_CHURN;
2201     cur_test_run.have_quick_quit = HAVE_NO_QUICK_QUIT;
2202     cur_test_run.have_collect_statistics = COLLECT_STATISTICS;
2203     cur_test_run.stat_collect_flags = STAT_TYPE_ROUNDS |
2204                                       STAT_TYPE_BLOCKS |
2205                                       STAT_TYPE_BLOCKS_MANY_PUSH |
2206                                       STAT_TYPE_BLOCKS_NO_PUSH |
2207                                       STAT_TYPE_BLOCKS_NO_PULL |
2208                                       STAT_TYPE_BLOCKS_MANY_PUSH_NO_PULL |
2209                                       STAT_TYPE_BLOCKS_NO_PUSH_NO_PULL |
2210                                       STAT_TYPE_ISSUED_PUSH_SEND |
2211                                       STAT_TYPE_ISSUED_PULL_REQ |
2212                                       STAT_TYPE_ISSUED_PULL_REP |
2213                                       STAT_TYPE_SENT_PUSH_SEND |
2214                                       STAT_TYPE_SENT_PULL_REQ |
2215                                       STAT_TYPE_SENT_PULL_REP |
2216                                       STAT_TYPE_RECV_PUSH_SEND |
2217                                       STAT_TYPE_RECV_PULL_REQ |
2218                                       STAT_TYPE_RECV_PULL_REP;
2219     timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300);
2220
2221     /* 'Clean' directory */
2222     (void) GNUNET_DISK_directory_remove ("/tmp/rps/");
2223     GNUNET_DISK_directory_create ("/tmp/rps/");
2224   }
2225
2226   rps_peers = GNUNET_new_array (num_peers, struct RPSPeer);
2227   peer_map = GNUNET_CONTAINER_multipeermap_create (num_peers, GNUNET_NO);
2228   rps_peer_ids = GNUNET_new_array (num_peers, struct GNUNET_PeerIdentity);
2229   if ( (2 == mal_type) ||
2230        (3 == mal_type))
2231     target_peer = &rps_peer_ids[num_peers - 2];
2232   if (profiler_eval == cur_test_run.eval_cb)
2233     eval_peer = &rps_peers[num_peers - 1];    /* FIXME: eval_peer could be a
2234                                                  malicious peer if not careful
2235                                                  with the malicious portion */
2236
2237   ok = 1;
2238   ret_value = GNUNET_TESTBED_test_run (cur_test_run.name,
2239                                        "test_rps.conf",
2240                                        num_peers,
2241                                        0, NULL, NULL,
2242                                        &run, NULL);
2243   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2244               "_test_run returned.\n");
2245   if (GNUNET_OK != ret_value)
2246   {
2247     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2248                 "Test did not run successfully!\n");
2249   }
2250
2251   ret_value = cur_test_run.eval_cb();
2252   GNUNET_free (rps_peers);
2253   GNUNET_free (rps_peer_ids);
2254   GNUNET_CONTAINER_multipeermap_destroy (peer_map);
2255   return ret_value;
2256 }
2257
2258 /* end of test_rps.c */