rps tests: proper implementation of flags for tests
[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
242 /**
243  * Information for all the peers.
244  */
245 static struct RPSPeer *rps_peers;
246
247 /**
248  * Peermap to get the index of a given peer ID quick.
249  */
250 static struct GNUNET_CONTAINER_MultiPeerMap *peer_map;
251
252 /**
253  * IDs of the peers.
254  */
255 static struct GNUNET_PeerIdentity *rps_peer_ids;
256
257 /**
258  * ID of the targeted peer.
259  */
260 static struct GNUNET_PeerIdentity *target_peer;
261
262 /**
263  * ID of the peer that requests for the evaluation.
264  */
265 static struct RPSPeer *eval_peer;
266
267 /**
268  * Number of online peers.
269  */
270 static unsigned int num_peers_online;
271
272 /**
273  * Return value from 'main'.
274  */
275 static int ok;
276
277 /**
278  * Identifier for the churn task that runs periodically
279  */
280 static struct GNUNET_SCHEDULER_Task *shutdown_task;
281
282 /**
283  * Identifier for the churn task that runs periodically
284  */
285 static struct GNUNET_SCHEDULER_Task *churn_task;
286
287 /**
288  * Called to initialise the given RPSPeer
289  */
290 typedef void (*InitPeer) (struct RPSPeer *rps_peer);
291
292 /**
293  * @brief Called directly after connecting to the service
294  *
295  * @param rps_peer Specific peer the function is called on
296  * @param h the handle to the rps service
297  */
298 typedef void (*PreTest) (struct RPSPeer *rps_peer, struct GNUNET_RPS_Handle *h);
299
300 /**
301  * @brief Executes functions to test the api/service for a given peer
302  *
303  * Called from within #rps_connect_complete_cb ()
304  * Implemented by #churn_test_cb, #profiler_cb, #mal_cb, #single_req_cb,
305  * #delay_req_cb, #seed_big_cb, #single_peer_seed_cb, #seed_cb, #req_cancel_cb
306  *
307  * @param rps_peer the peer the task runs on
308  */
309 typedef void (*MainTest) (struct RPSPeer *rps_peer);
310
311 /**
312  * Callback called once the requested random peers are available
313  */
314 typedef void (*ReplyHandle) (void *cls,
315                              uint64_t n,
316                              const struct GNUNET_PeerIdentity *recv_peers);
317
318 /**
319  * Called directly before disconnecting from the service
320  */
321 typedef void (*PostTest) (void *cls, struct GNUNET_RPS_Handle *h);
322
323 /**
324  * Function called after disconnect to evaluate test success
325  */
326 typedef int (*EvaluationCallback) (void);
327
328 /**
329  * @brief Do we have Churn?
330  */
331 enum OPTION_CHURN {
332   /**
333    * @brief If we have churn this is set
334    */
335   HAVE_CHURN,
336   /**
337    * @brief If we have no churn this is set
338    */
339   HAVE_NO_CHURN,
340 };
341
342 /**
343  * @brief Is it ok to quit the test before the timeout?
344  */
345 enum OPTION_QUICK_QUIT {
346   /**
347    * @brief It is ok for the test to quit before the timeout triggers
348    */
349   HAVE_QUICK_QUIT,
350
351   /**
352    * @brief It is NOT ok for the test to quit before the timeout triggers
353    */
354   HAVE_NO_QUICK_QUIT,
355 };
356
357 /**
358  * Structure to define a single test
359  */
360 struct SingleTestRun
361 {
362   /**
363    * Name of the test
364    */
365   char *name;
366
367   /**
368    * Called with a single peer in order to initialise that peer
369    */
370   InitPeer init_peer;
371
372   /**
373    * Called directly after connecting to the service
374    */
375   PreTest pre_test;
376
377   /**
378    * Main function for each peer
379    */
380   MainTest main_test;
381
382   /**
383    * Callback called once the requested peers are available
384    */
385   ReplyHandle reply_handle;
386
387   /**
388    * Called directly before disconnecting from the service
389    */
390   PostTest post_test;
391
392   /**
393    * Function to evaluate the test results
394    */
395   EvaluationCallback eval_cb;
396
397   /**
398    * Request interval
399    */
400   uint32_t request_interval;
401
402   /**
403    * Number of Requests to make.
404    */
405   uint32_t num_requests;
406
407   /**
408    * Run with (-out) churn
409    */
410   enum OPTION_CHURN have_churn;
411
412   /**
413    * Quit test before timeout?
414    */
415   enum OPTION_QUICK_QUIT have_quick_quit;
416 } cur_test_run;
417
418 /**
419  * Are we shutting down?
420  */
421 static int in_shutdown;
422
423 /**
424  * Append arguments to file
425  */
426 static void
427 tofile_ (const char *file_name, const char *line)
428 {
429   struct GNUNET_DISK_FileHandle *f;
430   /* char output_buffer[512]; */
431   size_t size;
432   /* int size; */
433   size_t size2;
434
435   if (NULL == (f = GNUNET_DISK_file_open (file_name,
436                                           GNUNET_DISK_OPEN_APPEND |
437                                           GNUNET_DISK_OPEN_WRITE |
438                                           GNUNET_DISK_OPEN_CREATE,
439                                           GNUNET_DISK_PERM_USER_READ |
440                                           GNUNET_DISK_PERM_USER_WRITE |
441                                           GNUNET_DISK_PERM_GROUP_READ |
442                                           GNUNET_DISK_PERM_OTHER_READ)))
443   {
444     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
445                 "Not able to open file %s\n",
446                 file_name);
447     return;
448   }
449   /* size = GNUNET_snprintf (output_buffer,
450                           sizeof (output_buffer),
451                           "%llu %s\n",
452                           GNUNET_TIME_absolute_get ().abs_value_us,
453                           line);
454   if (0 > size)
455   {
456     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
457                 "Failed to write string to buffer (size: %i)\n",
458                 size);
459     return;
460   } */
461
462   size = strlen (line) * sizeof (char);
463
464   size2 = GNUNET_DISK_file_write (f, line, size);
465   if (size != size2)
466   {
467     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
468                 "Unable to write to file! (Size: %lu, size2: %lu)\n",
469                 size,
470                 size2);
471     if (GNUNET_YES != GNUNET_DISK_file_close (f))
472     {
473       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
474                   "Unable to close file\n");
475     }
476     return;
477   }
478
479   if (GNUNET_YES != GNUNET_DISK_file_close (f))
480   {
481     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
482                 "Unable to close file\n");
483   }
484 }
485
486 /**
487  * This function is used to facilitate writing important information to disk
488  */
489 #define tofile(file_name, ...) do {\
490   char tmp_buf[512];\
491     int size;\
492     size = GNUNET_snprintf(tmp_buf,sizeof(tmp_buf),__VA_ARGS__);\
493     if (0 > size)\
494       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,\
495                      "Failed to create tmp_buf\n");\
496     else\
497       tofile_(file_name,tmp_buf);\
498   } while (0);
499
500
501 /**
502  * Write the ids and their according index in the given array to a file
503  * Unused
504  */
505 /* static void
506 ids_to_file (char *file_name,
507              struct GNUNET_PeerIdentity *peer_ids,
508              unsigned int num_peer_ids)
509 {
510   unsigned int i;
511
512   for (i=0 ; i < num_peer_ids ; i++)
513   {
514     to_file (file_name,
515              "%u\t%s",
516              i,
517              GNUNET_i2s_full (&peer_ids[i]));
518   }
519 } */
520
521 /**
522  * Test the success of a single test
523  */
524 static int
525 evaluate (void)
526 {
527   unsigned int i;
528   int tmp_ok;
529
530   tmp_ok = 1;
531
532   for (i = 0; i < num_peers; i++)
533   {
534     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
535         "%u. peer [%s] received %u of %u expected peer_ids: %i\n",
536         i,
537         GNUNET_i2s (rps_peers[i].peer_id),
538         rps_peers[i].num_recv_ids,
539         rps_peers[i].num_ids_to_request,
540         (rps_peers[i].num_ids_to_request == rps_peers[i].num_recv_ids));
541     tmp_ok &= (rps_peers[i].num_ids_to_request == rps_peers[i].num_recv_ids);
542   }
543   return tmp_ok? 0 : 1;
544 }
545
546
547 /**
548  * Creates an oplist entry and adds it to the oplist DLL
549  */
550 static struct OpListEntry *
551 make_oplist_entry ()
552 {
553   struct OpListEntry *entry;
554
555   entry = GNUNET_new (struct OpListEntry);
556   GNUNET_CONTAINER_DLL_insert_tail (oplist_head, oplist_tail, entry);
557   return entry;
558 }
559
560
561 /**
562  * Task run on timeout to shut everything down.
563  */
564 static void
565 shutdown_op (void *cls)
566 {
567   unsigned int i;
568
569   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
570               "Shutdown task scheduled, going down.\n");
571   in_shutdown = GNUNET_YES;
572   if (NULL != churn_task)
573   {
574     GNUNET_SCHEDULER_cancel (churn_task);
575     churn_task = NULL;
576   }
577   for (i = 0; i < num_peers; i++)
578     if (NULL != rps_peers[i].op)
579       GNUNET_TESTBED_operation_done (rps_peers[i].op);
580   GNUNET_SCHEDULER_shutdown ();
581 }
582
583
584 /**
585  * Seed peers.
586  */
587 static void
588 seed_peers (void *cls)
589 {
590   struct RPSPeer *peer = cls;
591   unsigned int amount;
592   unsigned int i;
593
594   // TODO if malicious don't seed mal peers
595   amount = round (.5 * num_peers);
596
597   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Seeding peers:\n");
598   for (i = 0 ; i < amount ; i++)
599     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Seeding %u. peer: %s\n",
600                 i,
601                 GNUNET_i2s (&rps_peer_ids[i]));
602
603   GNUNET_RPS_seed_ids (peer->rps_handle, amount, rps_peer_ids);
604 }
605
606
607 /**
608  * Seed peers.
609  */
610 static void
611 seed_peers_big (void *cls)
612 {
613   struct RPSPeer *peer = cls;
614   unsigned int seed_msg_size;
615   uint32_t num_peers_max;
616   unsigned int amount;
617   unsigned int i;
618
619   seed_msg_size = 8; /* sizeof (struct GNUNET_RPS_CS_SeedMessage) */
620   num_peers_max = (GNUNET_MAX_MESSAGE_SIZE - seed_msg_size) /
621     sizeof (struct GNUNET_PeerIdentity);
622   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
623       "Peers that fit in one seed msg; %u\n",
624       num_peers_max);
625   amount = num_peers_max + (0.5 * num_peers_max);
626   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
627       "Seeding many (%u) peers:\n",
628       amount);
629   struct GNUNET_PeerIdentity ids_to_seed[amount];
630   for (i = 0; i < amount; i++)
631   {
632     ids_to_seed[i] = *peer->peer_id;
633     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Seeding %u. peer: %s\n",
634                 i,
635                 GNUNET_i2s (&ids_to_seed[i]));
636   }
637
638   GNUNET_RPS_seed_ids (peer->rps_handle, amount, ids_to_seed);
639 }
640
641 /**
642  * Get the id of peer i.
643  */
644   void
645 info_cb (void *cb_cls,
646          struct GNUNET_TESTBED_Operation *op,
647          const struct GNUNET_TESTBED_PeerInformation *pinfo,
648          const char *emsg)
649 {
650   struct OpListEntry *entry = (struct OpListEntry *) cb_cls;
651
652   if (GNUNET_YES == in_shutdown)
653   {
654     return;
655   }
656
657   if (NULL == pinfo || NULL != emsg)
658   {
659     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Got Error: %s\n", emsg);
660     GNUNET_TESTBED_operation_done (entry->op);
661     return;
662   }
663
664   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
665               "Peer %u is %s\n",
666               entry->index,
667               GNUNET_i2s (pinfo->result.id));
668
669   rps_peer_ids[entry->index] = *(pinfo->result.id);
670   rps_peers[entry->index].peer_id = &rps_peer_ids[entry->index];
671
672   GNUNET_assert (GNUNET_OK ==
673       GNUNET_CONTAINER_multipeermap_put (peer_map,
674         &rps_peer_ids[entry->index],
675         &rps_peers[entry->index],
676         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
677   tofile ("/tmp/rps/peer_ids",
678            "%u\t%s\n",
679            entry->index,
680            GNUNET_i2s_full (&rps_peer_ids[entry->index]));
681
682   GNUNET_CONTAINER_DLL_remove (oplist_head, oplist_tail, entry);
683   GNUNET_TESTBED_operation_done (entry->op);
684   GNUNET_free (entry);
685 }
686
687
688 /**
689  * Callback to be called when RPS service connect operation is completed
690  *
691  * @param cls the callback closure from functions generating an operation
692  * @param op the operation that has been finished
693  * @param ca_result the RPS service handle returned from rps_connect_adapter
694  * @param emsg error message in case the operation has failed; will be NULL if
695  *          operation has executed successfully.
696  */
697 static void
698 rps_connect_complete_cb (void *cls,
699                          struct GNUNET_TESTBED_Operation *op,
700                          void *ca_result,
701                          const char *emsg)
702 {
703   struct RPSPeer *rps_peer = cls;
704   struct GNUNET_RPS_Handle *rps = ca_result;
705
706   if (GNUNET_YES == in_shutdown)
707   {
708     return;
709   }
710
711   rps_peer->rps_handle = rps;
712   rps_peer->online = GNUNET_YES;
713   num_peers_online++;
714
715   GNUNET_assert (op == rps_peer->op);
716   if (NULL != emsg)
717   {
718     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
719                 "Failed to connect to RPS service: %s\n",
720                 emsg);
721     ok = 1;
722     GNUNET_SCHEDULER_shutdown ();
723     return;
724   }
725
726   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started client successfully\n");
727
728   cur_test_run.main_test (rps_peer);
729 }
730
731
732 /**
733  * Adapter function called to establish a connection to
734  * the RPS service.
735  *
736  * @param cls closure
737  * @param cfg configuration of the peer to connect to; will be available until
738  *          GNUNET_TESTBED_operation_done() is called on the operation returned
739  *          from GNUNET_TESTBED_service_connect()
740  * @return service handle to return in 'op_result', NULL on error
741  */
742 static void *
743 rps_connect_adapter (void *cls,
744                                  const struct GNUNET_CONFIGURATION_Handle *cfg)
745 {
746   struct GNUNET_RPS_Handle *h;
747
748   h = GNUNET_RPS_connect (cfg);
749
750   if (NULL != cur_test_run.pre_test)
751     cur_test_run.pre_test (cls, h);
752
753   return h;
754 }
755
756
757 /**
758  * Adapter function called to destroy connection to
759  * RPS service.
760  *
761  * @param cls closure
762  * @param op_result service handle returned from the connect adapter
763  */
764 static void
765 rps_disconnect_adapter (void *cls,
766                                           void *op_result)
767 {
768   struct RPSPeer *peer = cls;
769   struct GNUNET_RPS_Handle *h = op_result;
770   GNUNET_assert (NULL != peer);
771   GNUNET_RPS_disconnect (h);
772   peer->rps_handle = NULL;
773 }
774
775
776 /***********************************************************************
777  * Definition of tests
778 ***********************************************************************/
779
780 // TODO check whether tests can be stopped earlier
781 static int
782 default_eval_cb (void)
783 {
784   return evaluate ();
785 }
786
787 static int
788 no_eval (void)
789 {
790   return 0;
791 }
792
793 /**
794  * Initialise given RPSPeer
795  */
796 static void default_init_peer (struct RPSPeer *rps_peer)
797 {
798   rps_peer->num_ids_to_request = 1;
799 }
800
801 /**
802  * Callback to call on receipt of a reply
803  *
804  * @param cls closure
805  * @param n number of peers
806  * @param recv_peers the received peers
807  */
808 static void
809 default_reply_handle (void *cls,
810                       uint64_t n,
811                       const struct GNUNET_PeerIdentity *recv_peers)
812 {
813   struct RPSPeer *rps_peer;
814   struct PendingReply *pending_rep = (struct PendingReply *) cls;
815   unsigned int i;
816
817   rps_peer = pending_rep->rps_peer;
818   GNUNET_CONTAINER_DLL_remove (rps_peer->pending_rep_head,
819                                rps_peer->pending_rep_tail,
820                                pending_rep);
821   rps_peer->num_pending_reps--;
822   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
823               "[%s] got %" PRIu64 " peers:\n",
824               GNUNET_i2s (rps_peer->peer_id),
825               n);
826
827   for (i = 0; i < n; i++)
828   {
829     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
830                 "%u: %s\n",
831                 i,
832                 GNUNET_i2s (&recv_peers[i]));
833
834     rps_peer->num_recv_ids++;
835   }
836
837   if (0 == evaluate () && HAVE_QUICK_QUIT == cur_test_run.have_quick_quit)
838   {
839     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test succeeded before timeout\n");
840     GNUNET_assert (NULL != shutdown_task);
841     GNUNET_SCHEDULER_cancel (shutdown_task);
842     shutdown_task = GNUNET_SCHEDULER_add_now (&shutdown_op, NULL);
843     GNUNET_assert (NULL!= shutdown_task);
844   }
845 }
846
847 /**
848  * Request random peers.
849  */
850 static void
851 request_peers (void *cls)
852 {
853   struct PendingRequest *pending_req = cls;
854   struct RPSPeer *rps_peer;
855   struct PendingReply *pending_rep;
856
857   if (GNUNET_YES == in_shutdown)
858     return;
859   rps_peer = pending_req->rps_peer;
860   GNUNET_assert (1 <= rps_peer->num_pending_reqs);
861   GNUNET_CONTAINER_DLL_remove (rps_peer->pending_req_head,
862                                rps_peer->pending_req_tail,
863                                pending_req);
864   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
865               "Requesting one peer\n");
866   pending_rep = GNUNET_new (struct PendingReply);
867   pending_rep->rps_peer = rps_peer;
868   pending_rep->req_handle = GNUNET_RPS_request_peers (rps_peer->rps_handle,
869       1,
870       cur_test_run.reply_handle,
871       pending_rep);
872   GNUNET_CONTAINER_DLL_insert_tail (rps_peer->pending_rep_head,
873                                     rps_peer->pending_rep_tail,
874                                     pending_rep);
875   rps_peer->num_pending_reps++;
876   rps_peer->num_pending_reqs--;
877 }
878
879 static void
880 cancel_pending_req (struct PendingRequest *pending_req)
881 {
882   struct RPSPeer *rps_peer;
883
884   rps_peer = pending_req->rps_peer;
885   GNUNET_CONTAINER_DLL_remove (rps_peer->pending_req_head,
886                                rps_peer->pending_req_tail,
887                                pending_req);
888   rps_peer->num_pending_reqs--;
889   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
890               "Cancelling pending request\n");
891   GNUNET_SCHEDULER_cancel (pending_req->request_task);
892   GNUNET_free (pending_req);
893 }
894
895 static void
896 cancel_request (struct PendingReply *pending_rep)
897 {
898   struct RPSPeer *rps_peer;
899
900   rps_peer = pending_rep->rps_peer;
901   GNUNET_CONTAINER_DLL_remove (rps_peer->pending_rep_head,
902                                rps_peer->pending_rep_tail,
903                                pending_rep);
904   rps_peer->num_pending_reps--;
905   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
906               "Cancelling request\n");
907   GNUNET_RPS_request_cancel (pending_rep->req_handle);
908   GNUNET_free (pending_rep);
909 }
910
911 /**
912  * Cancel a request.
913  */
914 static void
915 cancel_request_cb (void *cls)
916 {
917   struct RPSPeer *rps_peer = cls;
918   struct PendingReply *pending_rep;
919
920   if (GNUNET_YES == in_shutdown)
921     return;
922   pending_rep = rps_peer->pending_rep_head;
923   GNUNET_assert (1 <= rps_peer->num_pending_reps);
924   cancel_request (pending_rep);
925 }
926
927
928 /**
929  * Schedule requests for peer @a rps_peer that have neither been scheduled, nor
930  * issued, nor replied
931  */
932 void
933 schedule_missing_requests (struct RPSPeer *rps_peer)
934 {
935   unsigned int i;
936   struct PendingRequest *pending_req;
937
938   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
939       "Scheduling %u - %u missing requests\n",
940       rps_peer->num_ids_to_request,
941       rps_peer->num_pending_reqs + rps_peer->num_pending_reps);
942   GNUNET_assert (rps_peer->num_pending_reqs + rps_peer->num_pending_reps <=
943       rps_peer->num_ids_to_request);
944   for (i = rps_peer->num_pending_reqs + rps_peer->num_pending_reps;
945        i < rps_peer->num_ids_to_request; i++)
946   {
947     pending_req = GNUNET_new (struct PendingRequest);
948     pending_req->rps_peer = rps_peer;
949     pending_req->request_task = GNUNET_SCHEDULER_add_delayed (
950         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
951           cur_test_run.request_interval * i),
952         request_peers,
953         pending_req);
954     GNUNET_CONTAINER_DLL_insert_tail (rps_peer->pending_req_head,
955                                       rps_peer->pending_req_tail,
956                                       pending_req);
957     rps_peer->num_pending_reqs++;
958   }
959 }
960
961 void
962 cancel_pending_req_rep (struct RPSPeer *rps_peer)
963 {
964   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
965       "Cancelling all (pending) requests.\n");
966   while (NULL != rps_peer->pending_req_head)
967     cancel_pending_req (rps_peer->pending_req_head);
968   GNUNET_assert (0 == rps_peer->num_pending_reqs);
969   while (NULL != rps_peer->pending_rep_head)
970     cancel_request (rps_peer->pending_rep_head);
971   GNUNET_assert (0 == rps_peer->num_pending_reps);
972 }
973
974 /***********************************
975  * MALICIOUS
976 ***********************************/
977
978 /**
979  * Initialise only non-mal RPSPeers
980  */
981 static void mal_init_peer (struct RPSPeer *rps_peer)
982 {
983   if (rps_peer->index >= round (portion * num_peers))
984     rps_peer->num_ids_to_request = 1;
985 }
986
987
988 /**
989  * @brief Set peers to (non-)malicious before execution
990  *
991  * Of signature #PreTest
992  *
993  * @param rps_peer the peer to set (non-) malicious
994  * @param h the handle to the service
995  */
996 static void
997 mal_pre (struct RPSPeer *rps_peer, struct GNUNET_RPS_Handle *h)
998 {
999   #ifdef ENABLE_MALICIOUS
1000   uint32_t num_mal_peers;
1001
1002   GNUNET_assert ( (1 >= portion) &&
1003                   (0 <  portion) );
1004   num_mal_peers = round (portion * num_peers);
1005
1006   if (rps_peer->index < num_mal_peers)
1007   {
1008     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1009                 "%u. peer [%s] of %" PRIu32 " malicious peers turning malicious\n",
1010                 rps_peer->index,
1011                 GNUNET_i2s (rps_peer->peer_id),
1012                 num_mal_peers);
1013
1014     GNUNET_RPS_act_malicious (h, mal_type, num_mal_peers,
1015                               rps_peer_ids, target_peer);
1016   }
1017   #endif /* ENABLE_MALICIOUS */
1018 }
1019
1020 static void
1021 mal_cb (struct RPSPeer *rps_peer)
1022 {
1023   uint32_t num_mal_peers;
1024
1025   if (GNUNET_YES == in_shutdown)
1026   {
1027     return;
1028   }
1029
1030   #ifdef ENABLE_MALICIOUS
1031   GNUNET_assert ( (1 >= portion) &&
1032                   (0 <  portion) );
1033   num_mal_peers = round (portion * num_peers);
1034
1035   if (rps_peer->index >= num_mal_peers)
1036   { /* It's useless to ask a malicious peer about a random sample -
1037        it's not sampling */
1038     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
1039                                   seed_peers, rps_peer);
1040     schedule_missing_requests (rps_peer);
1041   }
1042   #endif /* ENABLE_MALICIOUS */
1043 }
1044
1045
1046 /***********************************
1047  * SINGLE_REQUEST
1048 ***********************************/
1049 static void
1050 single_req_cb (struct RPSPeer *rps_peer)
1051 {
1052   if (GNUNET_YES == in_shutdown)
1053   {
1054     return;
1055   }
1056
1057   schedule_missing_requests (rps_peer);
1058 }
1059
1060 /***********************************
1061  * DELAYED_REQUESTS
1062 ***********************************/
1063 static void
1064 delay_req_cb (struct RPSPeer *rps_peer)
1065 {
1066   if (GNUNET_YES == in_shutdown)
1067   {
1068     return;
1069   }
1070
1071   schedule_missing_requests (rps_peer);
1072 }
1073
1074 /***********************************
1075  * SEED
1076 ***********************************/
1077 static void
1078 seed_cb (struct RPSPeer *rps_peer)
1079 {
1080   if (GNUNET_YES == in_shutdown)
1081   {
1082     return;
1083   }
1084
1085   GNUNET_SCHEDULER_add_delayed (
1086       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
1087       seed_peers, rps_peer);
1088 }
1089
1090 /***********************************
1091  * SEED_BIG
1092 ***********************************/
1093 static void
1094 seed_big_cb (struct RPSPeer *rps_peer)
1095 {
1096   if (GNUNET_YES == in_shutdown)
1097   {
1098     return;
1099   }
1100
1101   // TODO test seeding > GNUNET_MAX_MESSAGE_SIZE peers
1102   GNUNET_SCHEDULER_add_delayed (
1103       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
1104       seed_peers_big, rps_peer);
1105 }
1106
1107 /***********************************
1108  * SINGLE_PEER_SEED
1109 ***********************************/
1110 static void
1111 single_peer_seed_cb (struct RPSPeer *rps_peer)
1112 {
1113   // TODO
1114 }
1115
1116 /***********************************
1117  * SEED_REQUEST
1118 ***********************************/
1119 static void
1120 seed_req_cb (struct RPSPeer *rps_peer)
1121 {
1122   if (GNUNET_YES == in_shutdown)
1123   {
1124     return;
1125   }
1126
1127   GNUNET_SCHEDULER_add_delayed (
1128       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
1129       seed_peers, rps_peer);
1130   schedule_missing_requests (rps_peer);
1131 }
1132
1133 //TODO start big mal
1134
1135 /***********************************
1136  * REQUEST_CANCEL
1137 ***********************************/
1138 static void
1139 req_cancel_cb (struct RPSPeer *rps_peer)
1140 {
1141   if (GNUNET_YES == in_shutdown)
1142   {
1143     return;
1144   }
1145
1146   schedule_missing_requests (rps_peer);
1147   GNUNET_SCHEDULER_add_delayed (
1148       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
1149                                      (cur_test_run.request_interval + 1)),
1150       cancel_request_cb, rps_peer);
1151 }
1152
1153 /***********************************
1154  * CHURN
1155 ***********************************/
1156
1157 static void
1158 churn (void *cls);
1159
1160 /**
1161  * @brief Starts churn
1162  *
1163  * Has signature of #MainTest
1164  *
1165  * This is not implemented too nicely as this is called for each peer, but we
1166  * only need to call it once. (Yes we check that we only schedule the task
1167  * once.)
1168  *
1169  * @param rps_peer The peer it's called for
1170  */
1171 static void
1172 churn_test_cb (struct RPSPeer *rps_peer)
1173 {
1174   if (GNUNET_YES == in_shutdown)
1175   {
1176     return;
1177   }
1178
1179   /* Start churn */
1180   if (HAVE_CHURN == cur_test_run.have_churn && NULL == churn_task)
1181   {
1182     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1183                 "Starting churn task\n");
1184     churn_task = GNUNET_SCHEDULER_add_delayed (
1185           GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
1186           churn,
1187           NULL);
1188   } else {
1189     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1190                 "Not starting churn task\n");
1191   }
1192
1193   schedule_missing_requests (rps_peer);
1194 }
1195
1196 /***********************************
1197  * PROFILER
1198 ***********************************/
1199
1200 /**
1201  * Callback to be called when RPS service is started or stopped at peers
1202  *
1203  * @param cls NULL
1204  * @param op the operation handle
1205  * @param emsg NULL on success; otherwise an error description
1206  */
1207 static void
1208 churn_cb (void *cls,
1209           struct GNUNET_TESTBED_Operation *op,
1210           const char *emsg)
1211 {
1212   // FIXME
1213   struct OpListEntry *entry = cls;
1214
1215   if (GNUNET_YES == in_shutdown)
1216   {
1217     return;
1218   }
1219
1220   GNUNET_TESTBED_operation_done (entry->op);
1221   if (NULL != emsg)
1222   {
1223     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start/stop RPS at a peer\n");
1224     GNUNET_SCHEDULER_shutdown ();
1225     return;
1226   }
1227   GNUNET_assert (0 != entry->delta);
1228
1229   num_peers_online += entry->delta;
1230
1231   if (PEER_GO_OFFLINE == entry->delta)
1232   { /* Peer hopefully just went offline */
1233     if (GNUNET_YES != rps_peers[entry->index].online)
1234     {
1235       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1236                   "peer %s was expected to go offline but is still marked as online\n",
1237                   GNUNET_i2s (rps_peers[entry->index].peer_id));
1238       GNUNET_break (0);
1239     }
1240     else
1241     {
1242       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1243                   "peer %s probably went offline as expected\n",
1244                   GNUNET_i2s (rps_peers[entry->index].peer_id));
1245     }
1246     rps_peers[entry->index].online = GNUNET_NO;
1247   }
1248
1249   else if (PEER_GO_ONLINE < entry->delta)
1250   { /* Peer hopefully just went online */
1251     if (GNUNET_NO != rps_peers[entry->index].online)
1252     {
1253       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1254                   "peer %s was expected to go online but is still marked as offline\n",
1255                   GNUNET_i2s (rps_peers[entry->index].peer_id));
1256       GNUNET_break (0);
1257     }
1258     else
1259     {
1260       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1261                   "peer %s probably went online as expected\n",
1262                   GNUNET_i2s (rps_peers[entry->index].peer_id));
1263       if (NULL != cur_test_run.pre_test)
1264       {
1265         cur_test_run.pre_test (&rps_peers[entry->index],
1266             rps_peers[entry->index].rps_handle);
1267         schedule_missing_requests (&rps_peers[entry->index]);
1268       }
1269     }
1270     rps_peers[entry->index].online = GNUNET_YES;
1271   }
1272   else
1273   {
1274     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1275         "Invalid value for delta: %i\n", entry->delta);
1276     GNUNET_break (0);
1277   }
1278
1279   GNUNET_CONTAINER_DLL_remove (oplist_head, oplist_tail, entry);
1280   rps_peers[entry->index].entry_op_manage = NULL;
1281   GNUNET_free (entry);
1282   //if (num_peers_in_round[current_round] == peers_running)
1283   //  run_round ();
1284 }
1285
1286 /**
1287  * @brief Set the rps-service up or down for a specific peer
1288  *
1289  * @param i index of action
1290  * @param j index of peer
1291  * @param delta (#PEER_ONLINE_DELTA) down (-1) or up (1)
1292  * @param prob_go_on_off the probability of the action
1293  */
1294 static void
1295 manage_service_wrapper (unsigned int i, unsigned int j,
1296                         enum PEER_ONLINE_DELTA delta,
1297                         double prob_go_on_off)
1298 {
1299   struct OpListEntry *entry;
1300   uint32_t prob;
1301
1302   /* make sure that management operation is not already scheduled */
1303   if (NULL != rps_peers[j].entry_op_manage)
1304   {
1305     return;
1306   }
1307
1308   prob = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1309                                    UINT32_MAX);
1310   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1311               "%u. selected peer (%u: %s) is %s.\n",
1312               i,
1313               j,
1314               GNUNET_i2s (rps_peers[j].peer_id),
1315               (PEER_GO_ONLINE == delta) ? "online" : "offline");
1316   if (prob < prob_go_on_off * UINT32_MAX)
1317   {
1318     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1319                 "%s goes %s\n",
1320                 GNUNET_i2s (rps_peers[j].peer_id),
1321                 (PEER_GO_OFFLINE == delta) ? "offline" : "online");
1322
1323     if (PEER_GO_OFFLINE == delta)
1324       cancel_pending_req_rep (&rps_peers[j]);
1325     entry = make_oplist_entry ();
1326     entry->delta = delta;
1327     entry->index = j;
1328     entry->op = GNUNET_TESTBED_peer_manage_service (NULL,
1329                                                     testbed_peers[j],
1330                                                     "rps",
1331                                                     &churn_cb,
1332                                                     entry,
1333                                                     (PEER_GO_OFFLINE == delta) ? 0 : 1);
1334   }
1335   rps_peers[j].entry_op_manage = entry;
1336 }
1337
1338
1339 static void
1340 churn (void *cls)
1341 {
1342   unsigned int i;
1343   unsigned int j;
1344   double portion_online;
1345   unsigned int *permut;
1346   double prob_go_offline;
1347   double portion_go_online;
1348   double portion_go_offline;
1349
1350   if (GNUNET_YES == in_shutdown)
1351   {
1352     return;
1353   }
1354   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1355               "Churn function executing\n");
1356
1357   churn_task = NULL; /* Should be invalid by now */
1358
1359   /* Compute the probability for an online peer to go offline
1360    * this round */
1361   portion_online = num_peers_online * 1.0 / num_peers;
1362   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1363               "Portion online: %f\n",
1364               portion_online);
1365   portion_go_online = ((1 - portion_online) * .5 * .66);
1366   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1367               "Portion that should go online: %f\n",
1368               portion_go_online);
1369   portion_go_offline = (portion_online + portion_go_online) - .75;
1370   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1371               "Portion that probably goes offline: %f\n",
1372               portion_go_offline);
1373   prob_go_offline = portion_go_offline / (portion_online * .5);
1374   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1375               "Probability of a selected online peer to go offline: %f\n",
1376               prob_go_offline);
1377
1378   permut = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
1379                                          (unsigned int) num_peers);
1380
1381   /* Go over 50% randomly chosen peers */
1382   for (i = 0; i < .5 * num_peers; i++)
1383   {
1384     j = permut[i];
1385
1386     /* If online, shut down with certain probability */
1387     if (GNUNET_YES == rps_peers[j].online)
1388     {
1389       manage_service_wrapper (i, j, -1, prob_go_offline);
1390     }
1391
1392     /* If offline, restart with certain probability */
1393     else if (GNUNET_NO == rps_peers[j].online)
1394     {
1395       manage_service_wrapper (i, j, 1, 0.66);
1396     }
1397   }
1398
1399   GNUNET_free (permut);
1400
1401   churn_task = GNUNET_SCHEDULER_add_delayed (
1402         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
1403         churn,
1404         NULL);
1405 }
1406
1407
1408 /**
1409  * Initialise given RPSPeer
1410  */
1411 static void profiler_init_peer (struct RPSPeer *rps_peer)
1412 {
1413   if (num_peers - 1 == rps_peer->index)
1414     rps_peer->num_ids_to_request = cur_test_run.num_requests;
1415 }
1416
1417
1418 /**
1419  * Callback to call on receipt of a reply
1420  *
1421  * @param cls closure
1422  * @param n number of peers
1423  * @param recv_peers the received peers
1424  */
1425 static void
1426 profiler_reply_handle (void *cls,
1427                       uint64_t n,
1428                       const struct GNUNET_PeerIdentity *recv_peers)
1429 {
1430   struct RPSPeer *rps_peer;
1431   struct RPSPeer *rcv_rps_peer;
1432   char *file_name;
1433   char *file_name_dh;
1434   unsigned int i;
1435   struct PendingReply *pending_rep = (struct PendingReply *) cls;
1436
1437   rps_peer = pending_rep->rps_peer;
1438   file_name = "/tmp/rps/received_ids";
1439   file_name_dh = "/tmp/rps/diehard_input";
1440   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1441               "[%s] got %" PRIu64 " peers:\n",
1442               GNUNET_i2s (rps_peer->peer_id),
1443               n);
1444   for (i = 0; i < n; i++)
1445   {
1446     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1447                 "%u: %s\n",
1448                 i,
1449                 GNUNET_i2s (&recv_peers[i]));
1450     tofile (file_name,
1451              "%s\n",
1452              GNUNET_i2s_full (&recv_peers[i]));
1453     rcv_rps_peer = GNUNET_CONTAINER_multipeermap_get (peer_map, &recv_peers[i]);
1454     GNUNET_assert (NULL != rcv_rps_peer);
1455     tofile (file_name_dh,
1456              "%" PRIu32 "\n",
1457              (uint32_t) rcv_rps_peer->index);
1458   }
1459   default_reply_handle (cls, n, recv_peers);
1460 }
1461
1462
1463 static void
1464 profiler_cb (struct RPSPeer *rps_peer)
1465 {
1466   if (GNUNET_YES == in_shutdown)
1467   {
1468     return;
1469   }
1470
1471   /* Start churn */
1472   if (HAVE_CHURN == cur_test_run.have_churn && NULL == churn_task)
1473   {
1474     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1475                 "Starting churn task\n");
1476     churn_task = GNUNET_SCHEDULER_add_delayed (
1477           GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
1478           churn,
1479           NULL);
1480   } else {
1481     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1482                 "Not starting churn task\n");
1483   }
1484
1485   /* Only request peer ids at one peer.
1486    * (It's the before-last because last one is target of the focussed attack.)
1487    */
1488   if (eval_peer == rps_peer)
1489     schedule_missing_requests (rps_peer);
1490 }
1491
1492 /**
1493  * Function called from #profiler_eval with a filename.
1494  *
1495  * @param cls closure
1496  * @param filename complete filename (absolute path)
1497  * @return #GNUNET_OK to continue to iterate,
1498  *  #GNUNET_NO to stop iteration with no error,
1499  *  #GNUNET_SYSERR to abort iteration with error!
1500  */
1501 int
1502 file_name_cb (void *cls, const char *filename)
1503 {
1504   if (NULL != strstr (filename, "sampler_el"))
1505   {
1506     struct RPS_SamplerElement *s_elem;
1507     struct GNUNET_CRYPTO_AuthKey auth_key;
1508     const char *key_char;
1509     uint32_t i;
1510
1511     key_char = filename + 20; /* Length of "/tmp/rps/sampler_el-" */
1512     tofile (filename, "--------------------------\n");
1513
1514     auth_key = string_to_auth_key (key_char);
1515     s_elem = RPS_sampler_elem_create ();
1516     RPS_sampler_elem_set (s_elem, auth_key);
1517
1518     for (i = 0; i < num_peers; i++)
1519     {
1520       RPS_sampler_elem_next (s_elem, &rps_peer_ids[i]);
1521     }
1522     RPS_sampler_elem_destroy (s_elem);
1523   }
1524   return GNUNET_OK;
1525 }
1526
1527 /**
1528  * This is run after the test finished.
1529  *
1530  * Compute all perfect samples.
1531  */
1532 int
1533 profiler_eval (void)
1534 {
1535   /* Compute perfect sample for each sampler element */
1536   if (-1 == GNUNET_DISK_directory_scan ("/tmp/rps/", file_name_cb, NULL))
1537   {
1538     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Scan of directory failed\n");
1539   }
1540
1541   return evaluate ();
1542 }
1543
1544
1545 /***********************************************************************
1546  * /Definition of tests
1547 ***********************************************************************/
1548
1549
1550 /**
1551  * Actual "main" function for the testcase.
1552  *
1553  * @param cls closure
1554  * @param h the run handle
1555  * @param n_peers number of peers in 'peers'
1556  * @param peers handle to peers run in the testbed
1557  * @param links_succeeded the number of overlay link connection attempts that
1558  *          succeeded
1559  * @param links_failed the number of overlay link connection attempts that
1560  *          failed
1561  */
1562 static void
1563 run (void *cls,
1564      struct GNUNET_TESTBED_RunHandle *h,
1565      unsigned int n_peers,
1566      struct GNUNET_TESTBED_Peer **peers,
1567      unsigned int links_succeeded,
1568      unsigned int links_failed)
1569 {
1570   unsigned int i;
1571   struct OpListEntry *entry;
1572   uint32_t num_mal_peers;
1573
1574   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "RUN was called\n");
1575
1576   /* Check whether we timed out */
1577   if (n_peers != num_peers ||
1578       NULL == peers ||
1579       0 == links_succeeded)
1580   {
1581     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Going down due to args (eg. timeout)\n");
1582     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\tn_peers: %u\n", n_peers);
1583     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\tnum_peers: %" PRIu32 "\n", num_peers);
1584     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\tpeers: %p\n", peers);
1585     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\tlinks_succeeded: %u\n", links_succeeded);
1586     GNUNET_SCHEDULER_shutdown ();
1587     return;
1588   }
1589
1590
1591   /* Initialize peers */
1592   testbed_peers = peers;
1593   num_peers_online = 0;
1594   for (i = 0; i < num_peers; i++)
1595   {
1596     entry = make_oplist_entry ();
1597     entry->index = i;
1598     rps_peers[i].index = i;
1599     if (NULL != cur_test_run.init_peer)
1600       cur_test_run.init_peer (&rps_peers[i]);
1601     entry->op = GNUNET_TESTBED_peer_get_information (peers[i],
1602                                                      GNUNET_TESTBED_PIT_IDENTITY,
1603                                                      &info_cb,
1604                                                      entry);
1605   }
1606
1607   /* Bring peers up */
1608   num_mal_peers = round (portion * num_peers);
1609   GNUNET_assert (num_peers == n_peers);
1610   for (i = 0; i < n_peers; i++)
1611   {
1612     rps_peers[i].index = i;
1613     if ( (rps_peers[i].num_recv_ids < rps_peers[i].num_ids_to_request) ||
1614          (i < num_mal_peers) )
1615     {
1616       rps_peers[i].op =
1617         GNUNET_TESTBED_service_connect (&rps_peers[i],
1618                                         peers[i],
1619                                         "rps",
1620                                         &rps_connect_complete_cb,
1621                                         &rps_peers[i],
1622                                         &rps_connect_adapter,
1623                                         &rps_disconnect_adapter,
1624                                         &rps_peers[i]);
1625     }
1626   }
1627
1628   if (NULL != churn_task)
1629     GNUNET_SCHEDULER_cancel (churn_task);
1630   shutdown_task = GNUNET_SCHEDULER_add_delayed (timeout, &shutdown_op, NULL);
1631 }
1632
1633
1634 /**
1635  * Entry point for the testcase, sets up the testbed.
1636  *
1637  * @param argc unused
1638  * @param argv unused
1639  * @return 0 on success
1640  */
1641 int
1642 main (int argc, char *argv[])
1643 {
1644   int ret_value;
1645
1646   num_peers = 5;
1647   cur_test_run.name = "test-rps-default";
1648   cur_test_run.init_peer = default_init_peer;
1649   cur_test_run.pre_test = NULL;
1650   cur_test_run.reply_handle = default_reply_handle;
1651   cur_test_run.eval_cb = default_eval_cb;
1652   cur_test_run.have_churn = HAVE_CHURN;
1653   churn_task = NULL;
1654   timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30);
1655
1656   if (strstr (argv[0], "malicious") != NULL)
1657   {
1658     cur_test_run.pre_test = mal_pre;
1659     cur_test_run.main_test = mal_cb;
1660     cur_test_run.init_peer = mal_init_peer;
1661
1662     if (strstr (argv[0], "_1") != NULL)
1663     {
1664       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 1\n");
1665       cur_test_run.name = "test-rps-malicious_1";
1666       mal_type = 1;
1667     }
1668     else if (strstr (argv[0], "_2") != NULL)
1669     {
1670       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 2\n");
1671       cur_test_run.name = "test-rps-malicious_2";
1672       mal_type = 2;
1673     }
1674     else if (strstr (argv[0], "_3") != NULL)
1675     {
1676       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 3\n");
1677       cur_test_run.name = "test-rps-malicious_3";
1678       mal_type = 3;
1679     }
1680   }
1681
1682   else if (strstr (argv[0], "_single_req") != NULL)
1683   {
1684     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test single request\n");
1685     cur_test_run.name = "test-rps-single-req";
1686     cur_test_run.main_test = single_req_cb;
1687     cur_test_run.have_churn = HAVE_NO_CHURN;
1688   }
1689
1690   else if (strstr (argv[0], "_delayed_reqs") != NULL)
1691   {
1692     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test delayed requests\n");
1693     cur_test_run.name = "test-rps-delayed-reqs";
1694     cur_test_run.main_test = delay_req_cb;
1695     cur_test_run.have_churn = HAVE_NO_CHURN;
1696   }
1697
1698   else if (strstr (argv[0], "_seed_big") != NULL)
1699   {
1700     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding (num_peers > GNUNET_MAX_MESSAGE_SIZE)\n");
1701     num_peers = 1;
1702     cur_test_run.name = "test-rps-seed-big";
1703     cur_test_run.main_test = seed_big_cb;
1704     cur_test_run.eval_cb = no_eval;
1705     cur_test_run.have_churn = HAVE_NO_CHURN;
1706     timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10);
1707   }
1708
1709   else if (strstr (argv[0], "_single_peer_seed") != NULL)
1710   {
1711     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding and requesting on a single peer\n");
1712     cur_test_run.name = "test-rps-single-peer-seed";
1713     cur_test_run.main_test = single_peer_seed_cb;
1714     cur_test_run.have_churn = HAVE_NO_CHURN;
1715   }
1716
1717   else if (strstr (argv[0], "_seed_request") != NULL)
1718   {
1719     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding and requesting on multiple peers\n");
1720     cur_test_run.name = "test-rps-seed-request";
1721     cur_test_run.main_test = seed_req_cb;
1722     cur_test_run.have_churn = HAVE_NO_CHURN;
1723   }
1724
1725   else if (strstr (argv[0], "_seed") != NULL)
1726   {
1727     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding\n");
1728     cur_test_run.name = "test-rps-seed";
1729     cur_test_run.main_test = seed_cb;
1730     cur_test_run.eval_cb = no_eval;
1731     cur_test_run.have_churn = HAVE_NO_CHURN;
1732   }
1733
1734   else if (strstr (argv[0], "_req_cancel") != NULL)
1735   {
1736     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test cancelling a request\n");
1737     cur_test_run.name = "test-rps-req-cancel";
1738     num_peers = 1;
1739     cur_test_run.main_test = req_cancel_cb;
1740     cur_test_run.eval_cb = no_eval;
1741     cur_test_run.have_churn = HAVE_NO_CHURN;
1742     timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10);
1743   }
1744
1745   else if (strstr (argv[0], "_churn") != NULL)
1746   {
1747     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test churn\n");
1748     cur_test_run.name = "test-rps-churn";
1749     num_peers = 5;
1750     cur_test_run.init_peer = default_init_peer;
1751     cur_test_run.main_test = churn_test_cb;
1752     cur_test_run.reply_handle = default_reply_handle;
1753     cur_test_run.eval_cb = default_eval_cb;
1754     cur_test_run.have_churn = HAVE_CHURN;
1755     cur_test_run.have_quick_quit = HAVE_NO_QUICK_QUIT;
1756     timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10);
1757   }
1758
1759   else if (strstr (argv[0], "profiler") != NULL)
1760   {
1761     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "This is the profiler\n");
1762     cur_test_run.name = "test-rps-profiler";
1763     num_peers = 10;
1764     mal_type = 3;
1765     cur_test_run.init_peer = profiler_init_peer;
1766     cur_test_run.pre_test = mal_pre;
1767     cur_test_run.main_test = profiler_cb;
1768     cur_test_run.reply_handle = profiler_reply_handle;
1769     cur_test_run.eval_cb = profiler_eval;
1770     cur_test_run.request_interval = 2;
1771     cur_test_run.num_requests = 5;
1772     cur_test_run.have_churn = HAVE_CHURN;
1773     cur_test_run.have_quick_quit = HAVE_NO_QUICK_QUIT;
1774     timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300);
1775
1776     /* 'Clean' directory */
1777     (void) GNUNET_DISK_directory_remove ("/tmp/rps/");
1778     GNUNET_DISK_directory_create ("/tmp/rps/");
1779   }
1780
1781   rps_peers = GNUNET_new_array (num_peers, struct RPSPeer);
1782   peer_map = GNUNET_CONTAINER_multipeermap_create (num_peers, GNUNET_NO);
1783   rps_peer_ids = GNUNET_new_array (num_peers, struct GNUNET_PeerIdentity);
1784   if ( (2 == mal_type) ||
1785        (3 == mal_type))
1786     target_peer = &rps_peer_ids[num_peers - 2];
1787   if (profiler_eval == cur_test_run.eval_cb)
1788     eval_peer = &rps_peers[num_peers - 1];    /* FIXME: eval_peer could be a
1789                                                  malicious peer if not careful
1790                                                  with the malicious portion */
1791
1792   ok = 1;
1793   ret_value = GNUNET_TESTBED_test_run (cur_test_run.name,
1794                                        "test_rps.conf",
1795                                        num_peers,
1796                                        0, NULL, NULL,
1797                                        &run, NULL);
1798   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1799               "_test_run returned.\n");
1800   if (GNUNET_OK != ret_value)
1801   {
1802     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1803                 "Test did not run successfully!\n");
1804   }
1805
1806   ret_value = cur_test_run.eval_cb();
1807   GNUNET_free (rps_peers);
1808   GNUNET_free (rps_peer_ids);
1809   GNUNET_CONTAINER_multipeermap_destroy (peer_map);
1810   return ret_value;
1811 }
1812
1813 /* end of test_rps.c */