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