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