tighten formatting rules
[oweals/gnunet.git] / src / rps / gnunet-rps-profiler.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 it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
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 "rps_test_lib.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_testbed_service.h"
31
32 #include "gnunet_rps_service.h"
33 #include "rps-test_util.h"
34 #include "gnunet-service-rps_sampler_elem.h"
35
36 #include <inttypes.h>
37
38
39 #define BIT(n) (1 << (n))
40
41 /**
42  * How many peers do we start?
43  */
44 static uint32_t num_peers;
45
46 /**
47  * @brief numer of bits required to represent the largest peer id
48  */
49 static unsigned bits_needed;
50
51 /**
52  * How long do we run the test?
53  */
54 static struct GNUNET_TIME_Relative duration;
55
56 /**
57  * When do we do a hard shutdown?
58  */
59 static struct GNUNET_TIME_Relative timeout;
60
61
62 /**
63  * Portion of malicious peers
64  */
65 static double portion = .1;
66
67 /**
68  * Type of malicious peer to test
69  */
70 static unsigned int mal_type = 0;
71
72 /**
73  * Handles to all of the running peers
74  */
75 static struct GNUNET_TESTBED_Peer **testbed_peers;
76
77 enum STAT_TYPE
78 {
79   STAT_TYPE_ROUNDS,                   /*   0 */
80   STAT_TYPE_BLOCKS,                   /*   1 */
81   STAT_TYPE_BLOCKS_MANY_PUSH,         /*   2 */
82   STAT_TYPE_BLOCKS_NO_PUSH,           /*   3 */
83   STAT_TYPE_BLOCKS_NO_PULL,           /*   4 */
84   STAT_TYPE_BLOCKS_MANY_PUSH_NO_PULL, /*   5 */
85   STAT_TYPE_BLOCKS_NO_PUSH_NO_PULL,   /*   6 */
86   STAT_TYPE_ISSUED_PUSH_SEND,         /*   7 */
87   STAT_TYPE_ISSUED_PUSH_SEND_MH,      /*   8 */
88   STAT_TYPE_ISSUED_PULL_REQ,          /*   9 */
89   STAT_TYPE_ISSUED_PULL_REQ_MH,       /*  10 */
90   STAT_TYPE_ISSUED_PULL_REP,          /*  11 */
91   STAT_TYPE_SENT_PUSH_SEND,           /*  12 */
92   STAT_TYPE_SENT_PULL_REQ,            /*  13 */
93   STAT_TYPE_SENT_PULL_REQ_MH,         /*  14 */
94   STAT_TYPE_SENT_PULL_REP,            /*  15 */
95   STAT_TYPE_RECV_PUSH_SEND,           /*  16 */
96   STAT_TYPE_RECV_PUSH_SEND_MH,        /*  17 */
97   STAT_TYPE_RECV_PULL_REQ,            /*  18 */
98   STAT_TYPE_RECV_PULL_REQ_MH,         /*  19 */
99   STAT_TYPE_RECV_PULL_REP,            /*  20 */
100   STAT_TYPE_RECV_PULL_REP_MH,         /*  21 */
101   STAT_TYPE_VIEW_SIZE,                /*  22 */
102   STAT_TYPE_KNOWN_PEERS,              /*  23 */
103   STAT_TYPE_VALID_PEERS,              /*  24 */
104   STAT_TYPE_LEARND_PEERS,             /*  25 */
105   STAT_TYPE_PENDING_ONLINE_CHECKS,    /*  26 */
106   STAT_TYPE_UNREQUESTED_PULL_REPLIES, /*  27 */
107   STAT_TYPE_PEERS_IN_PUSH_MAP,        /*  28 */
108   STAT_TYPE_PEERS_IN_PULL_MAP,        /*  29 */
109   STAT_TYPE_PEERS_IN_VIEW,            /*  30 */
110   STAT_TYPE_VIEW_SIZE_AIM,            /*  31 */
111   STAT_TYPE_MAX,                      /*  32 */
112 };
113
114 static char*stat_type_strings[] = {
115   "# rounds",
116   "# rounds blocked",
117   "# rounds blocked - too many pushes",
118   "# rounds blocked - no pushes",
119   "# rounds blocked - no pull replies",
120   "# rounds blocked - too many pushes, no pull replies",
121   "# rounds blocked - no pushes, no pull replies",
122   "# push send issued",
123   "# push send issued (multi-hop peer)",
124   "# pull request send issued",
125   "# pull request send issued (multi-hop peer)",
126   "# pull reply send issued",
127   "# pushes sent",
128   "# pull requests sent",
129   "# pull requests sent (multi-hop peer)",
130   "# pull replys sent",
131   "# push message received",
132   "# push message received (multi-hop peer)",
133   "# pull request message received",
134   "# pull request message received (multi-hop peer)",
135   "# pull reply messages received",
136   "# pull reply messages received (multi-hop peer)",
137   "view size",
138   "# known peers",
139   "# valid peers",
140   "# learnd peers",
141   "# pending online checks",
142   "# unrequested pull replies",
143   "# peers in push map at end of round",
144   "# peers in pull map at end of round",
145   "# peers in view at end of round",
146   "view size aim",
147 };
148
149 struct STATcls
150 {
151   struct RPSPeer *rps_peer;
152   enum STAT_TYPE stat_type;
153 };
154
155
156 /**
157  * @brief Converts string representation to the corresponding #STAT_TYPE enum.
158  *
159  * @param stat_str string representation of statistics specifier
160  *
161  * @return corresponding enum
162  */
163 enum STAT_TYPE
164 stat_str_2_type (const char *stat_str)
165 {
166   if (0 == strncmp (stat_type_strings[STAT_TYPE_BLOCKS_NO_PULL],
167                     stat_str,
168                     strlen (stat_type_strings[STAT_TYPE_BLOCKS_NO_PULL])))
169   {
170     return STAT_TYPE_BLOCKS_NO_PULL;
171   }
172   else if (0 == strncmp (stat_type_strings[STAT_TYPE_BLOCKS_MANY_PUSH_NO_PULL],
173                          stat_str,
174                          strlen (
175                            stat_type_strings[STAT_TYPE_BLOCKS_MANY_PUSH_NO_PULL])))
176   {
177     return STAT_TYPE_BLOCKS_MANY_PUSH_NO_PULL;
178   }
179   else if (0 == strncmp (stat_type_strings[STAT_TYPE_BLOCKS_MANY_PUSH],
180                          stat_str,
181                          strlen (
182                            stat_type_strings[STAT_TYPE_BLOCKS_MANY_PUSH])))
183   {
184     return STAT_TYPE_BLOCKS_MANY_PUSH;
185   }
186   else if (0 == strncmp (stat_type_strings[STAT_TYPE_BLOCKS_NO_PUSH_NO_PULL],
187                          stat_str,
188                          strlen (
189                            stat_type_strings[STAT_TYPE_BLOCKS_NO_PUSH_NO_PULL])))
190   {
191     return STAT_TYPE_BLOCKS_NO_PUSH_NO_PULL;
192   }
193   else if (0 == strncmp (stat_type_strings[STAT_TYPE_BLOCKS_NO_PUSH],
194                          stat_str,
195                          strlen (stat_type_strings[STAT_TYPE_BLOCKS_NO_PUSH])))
196   {
197     return STAT_TYPE_BLOCKS_NO_PUSH;
198   }
199   else if (0 == strncmp (stat_type_strings[STAT_TYPE_BLOCKS],
200                          stat_str,
201                          strlen (stat_type_strings[STAT_TYPE_BLOCKS])))
202   {
203     return STAT_TYPE_BLOCKS;
204   }
205   else if (0 == strncmp (stat_type_strings[STAT_TYPE_ROUNDS],
206                          stat_str,
207                          strlen (stat_type_strings[STAT_TYPE_ROUNDS])))
208   {
209     return STAT_TYPE_ROUNDS;
210   }
211   else if (0 == strncmp (stat_type_strings[STAT_TYPE_ISSUED_PUSH_SEND],
212                          stat_str,
213                          strlen (
214                            stat_type_strings[STAT_TYPE_ISSUED_PUSH_SEND])))
215   {
216     return STAT_TYPE_ISSUED_PUSH_SEND;
217   }
218   else if (0 == strncmp (stat_type_strings[STAT_TYPE_ISSUED_PUSH_SEND_MH],
219                          stat_str,
220                          strlen (
221                            stat_type_strings[STAT_TYPE_ISSUED_PUSH_SEND_MH])))
222   {
223     return STAT_TYPE_ISSUED_PUSH_SEND_MH;
224   }
225   else if (0 == strncmp (stat_type_strings[STAT_TYPE_ISSUED_PULL_REQ],
226                          stat_str,
227                          strlen (stat_type_strings[STAT_TYPE_ISSUED_PULL_REQ])))
228   {
229     return STAT_TYPE_ISSUED_PULL_REQ;
230   }
231   else if (0 == strncmp (stat_type_strings[STAT_TYPE_ISSUED_PULL_REQ_MH],
232                          stat_str,
233                          strlen (
234                            stat_type_strings[STAT_TYPE_ISSUED_PULL_REQ_MH])))
235   {
236     return STAT_TYPE_ISSUED_PULL_REQ_MH;
237   }
238   else if (0 == strncmp (stat_type_strings[STAT_TYPE_ISSUED_PULL_REP],
239                          stat_str,
240                          strlen (stat_type_strings[STAT_TYPE_ISSUED_PULL_REP])))
241   {
242     return STAT_TYPE_ISSUED_PULL_REP;
243   }
244   else if (0 == strncmp (stat_type_strings[STAT_TYPE_SENT_PUSH_SEND],
245                          stat_str,
246                          strlen (stat_type_strings[STAT_TYPE_SENT_PUSH_SEND])))
247   {
248     return STAT_TYPE_SENT_PUSH_SEND;
249   }
250   else if (0 == strncmp (stat_type_strings[STAT_TYPE_SENT_PULL_REQ],
251                          stat_str,
252                          strlen (stat_type_strings[STAT_TYPE_SENT_PULL_REQ])))
253   {
254     return STAT_TYPE_SENT_PULL_REQ;
255   }
256   else if (0 == strncmp (stat_type_strings[STAT_TYPE_SENT_PULL_REQ_MH],
257                          stat_str,
258                          strlen (
259                            stat_type_strings[STAT_TYPE_SENT_PULL_REQ_MH])))
260   {
261     return STAT_TYPE_SENT_PULL_REQ_MH;
262   }
263   else if (0 == strncmp (stat_type_strings[STAT_TYPE_SENT_PULL_REP],
264                          stat_str,
265                          strlen (stat_type_strings[STAT_TYPE_SENT_PULL_REP])))
266   {
267     return STAT_TYPE_SENT_PULL_REP;
268   }
269   else if (0 == strncmp (stat_type_strings[STAT_TYPE_RECV_PUSH_SEND],
270                          stat_str,
271                          strlen (stat_type_strings[STAT_TYPE_RECV_PUSH_SEND])))
272   {
273     return STAT_TYPE_RECV_PUSH_SEND;
274   }
275   else if (0 == strncmp (stat_type_strings[STAT_TYPE_RECV_PUSH_SEND_MH],
276                          stat_str,
277                          strlen (
278                            stat_type_strings[STAT_TYPE_RECV_PUSH_SEND_MH])))
279   {
280     return STAT_TYPE_RECV_PUSH_SEND_MH;
281   }
282   else if (0 == strncmp (stat_type_strings[STAT_TYPE_RECV_PULL_REQ],
283                          stat_str,
284                          strlen (stat_type_strings[STAT_TYPE_RECV_PULL_REQ])))
285   {
286     return STAT_TYPE_RECV_PULL_REQ;
287   }
288   else if (0 == strncmp (stat_type_strings[STAT_TYPE_RECV_PULL_REQ_MH],
289                          stat_str,
290                          strlen (
291                            stat_type_strings[STAT_TYPE_RECV_PULL_REQ_MH])))
292   {
293     return STAT_TYPE_RECV_PULL_REQ_MH;
294   }
295   else if (0 == strncmp (stat_type_strings[STAT_TYPE_RECV_PULL_REP],
296                          stat_str,
297                          strlen (stat_type_strings[STAT_TYPE_RECV_PULL_REP])))
298   {
299     return STAT_TYPE_RECV_PULL_REP;
300   }
301   else if (0 == strncmp (stat_type_strings[STAT_TYPE_RECV_PULL_REP_MH],
302                          stat_str,
303                          strlen (
304                            stat_type_strings[STAT_TYPE_RECV_PULL_REP_MH])))
305   {
306     return STAT_TYPE_RECV_PULL_REP_MH;
307   }
308   else if (0 == strncmp (stat_type_strings[STAT_TYPE_VIEW_SIZE],
309                          stat_str,
310                          strlen (stat_type_strings[STAT_TYPE_VIEW_SIZE])))
311   {
312     return STAT_TYPE_VIEW_SIZE;
313   }
314   else if (0 == strncmp (stat_type_strings[STAT_TYPE_KNOWN_PEERS],
315                          stat_str,
316                          strlen (stat_type_strings[STAT_TYPE_KNOWN_PEERS])))
317   {
318     return STAT_TYPE_KNOWN_PEERS;
319   }
320   else if (0 == strncmp (stat_type_strings[STAT_TYPE_VALID_PEERS],
321                          stat_str,
322                          strlen (stat_type_strings[STAT_TYPE_VALID_PEERS])))
323   {
324     return STAT_TYPE_VALID_PEERS;
325   }
326   else if (0 == strncmp (stat_type_strings[STAT_TYPE_LEARND_PEERS],
327                          stat_str,
328                          strlen (stat_type_strings[STAT_TYPE_LEARND_PEERS])))
329   {
330     return STAT_TYPE_LEARND_PEERS;
331   }
332   else if (0 == strncmp (stat_type_strings[STAT_TYPE_PENDING_ONLINE_CHECKS],
333                          stat_str,
334                          strlen (
335                            stat_type_strings[STAT_TYPE_PENDING_ONLINE_CHECKS])))
336   {
337     return STAT_TYPE_PENDING_ONLINE_CHECKS;
338   }
339   else if (0 == strncmp (stat_type_strings[STAT_TYPE_UNREQUESTED_PULL_REPLIES],
340                          stat_str,
341                          strlen (
342                            stat_type_strings[STAT_TYPE_UNREQUESTED_PULL_REPLIES])))
343   {
344     return STAT_TYPE_UNREQUESTED_PULL_REPLIES;
345   }
346   else if (0 == strncmp (stat_type_strings[STAT_TYPE_PEERS_IN_PUSH_MAP],
347                          stat_str,
348                          strlen (
349                            stat_type_strings[STAT_TYPE_PEERS_IN_PUSH_MAP])))
350   {
351     return STAT_TYPE_PEERS_IN_PUSH_MAP;
352   }
353   else if (0 == strncmp (stat_type_strings[STAT_TYPE_PEERS_IN_PULL_MAP],
354                          stat_str,
355                          strlen (
356                            stat_type_strings[STAT_TYPE_PEERS_IN_PULL_MAP])))
357   {
358     return STAT_TYPE_PEERS_IN_PULL_MAP;
359   }
360   else if (0 == strncmp (stat_type_strings[STAT_TYPE_PEERS_IN_VIEW],
361                          stat_str,
362                          strlen (stat_type_strings[STAT_TYPE_PEERS_IN_VIEW])))
363   {
364     return STAT_TYPE_PEERS_IN_VIEW;
365   }
366   else if (0 == strncmp (stat_type_strings[STAT_TYPE_VIEW_SIZE_AIM],
367                          stat_str,
368                          strlen (stat_type_strings[STAT_TYPE_VIEW_SIZE_AIM])))
369   {
370     return STAT_TYPE_VIEW_SIZE_AIM;
371   }
372   return STAT_TYPE_MAX;
373 }
374
375
376 /**
377  * @brief Indicates whether peer should go off- or online
378  */
379 enum PEER_ONLINE_DELTA
380 {
381   /**
382    * @brief Indicates peer going online
383    */
384   PEER_GO_ONLINE = 1,
385   /**
386    * @brief Indicates peer going offline
387    */
388   PEER_GO_OFFLINE = -1,
389 };
390
391 /**
392  * Operation map entry
393  */
394 struct OpListEntry
395 {
396   /**
397    * DLL next ptr
398    */
399   struct OpListEntry *next;
400
401   /**
402    * DLL prev ptr
403    */
404   struct OpListEntry *prev;
405
406   /**
407    * The testbed operation
408    */
409   struct GNUNET_TESTBED_Operation *op;
410
411   /**
412    * Depending on whether we start or stop RPS service at the peer, set this to
413    * #PEER_GO_ONLINE (1) or #PEER_GO_OFFLINE (-1)
414    */
415   enum PEER_ONLINE_DELTA delta;
416
417   /**
418    * Index of the regarding peer
419    */
420   unsigned int index;
421 };
422
423 /**
424  * OpList DLL head
425  */
426 static struct OpListEntry *oplist_head;
427
428 /**
429  * OpList DLL tail
430  */
431 static struct OpListEntry *oplist_tail;
432
433
434 /**
435  * A pending reply: A request was sent and the reply is pending.
436  */
437 struct PendingReply
438 {
439   /**
440    * DLL next,prev ptr
441    */
442   struct PendingReply *next;
443   struct PendingReply *prev;
444
445   /**
446    * Handle to the request we are waiting for
447    */
448   struct GNUNET_RPS_Request_Handle_Single_Info *req_handle;
449
450   /**
451    * The peer that requested
452    */
453   struct RPSPeer *rps_peer;
454 };
455
456
457 /**
458  * A pending request: A request was not made yet but is scheduled for later.
459  */
460 struct PendingRequest
461 {
462   /**
463    * DLL next,prev ptr
464    */
465   struct PendingRequest *next;
466   struct PendingRequest *prev;
467
468   /**
469    * Handle to the request we are waiting for
470    */
471   struct GNUNET_SCHEDULER_Task *request_task;
472
473   /**
474    * The peer that requested
475    */
476   struct RPSPeer *rps_peer;
477 };
478
479
480 /**
481  * Information we track for each peer.
482  */
483 struct RPSPeer
484 {
485   /**
486    * Index of the peer.
487    */
488   unsigned int index;
489
490   /**
491    * Handle for RPS connect operation.
492    */
493   struct GNUNET_TESTBED_Operation *op;
494
495   /**
496    * Handle to RPS service.
497    */
498   struct GNUNET_RPS_Handle *rps_handle;
499
500   /**
501    * ID of the peer.
502    */
503   struct GNUNET_PeerIdentity *peer_id;
504
505   /**
506    * A request handle to check for an request
507    */
508   // struct GNUNET_RPS_Request_Handle *req_handle;
509
510   /**
511    * Peer on- or offline?
512    */
513   int online;
514
515   /**
516    * Number of Peer IDs to request during the whole test
517    */
518   unsigned int num_ids_to_request;
519
520   /**
521    * Pending requests DLL
522    */
523   struct PendingRequest *pending_req_head;
524   struct PendingRequest *pending_req_tail;
525
526   /**
527    * Number of pending requests
528    */
529   unsigned int num_pending_reqs;
530
531   /**
532    * Pending replies DLL
533    */
534   struct PendingReply *pending_rep_head;
535   struct PendingReply *pending_rep_tail;
536
537   /**
538    * Number of pending replies
539    */
540   unsigned int num_pending_reps;
541
542   /**
543    * Number of received PeerIDs
544    */
545   unsigned int num_recv_ids;
546
547   /**
548    * Pending operation on that peer
549    */
550   const struct OpListEntry *entry_op_manage;
551
552   /**
553    * Testbed operation to connect to statistics service
554    */
555   struct GNUNET_TESTBED_Operation *stat_op;
556
557   /**
558    * Handle to the statistics service
559    */
560   struct GNUNET_STATISTICS_Handle *stats_h;
561
562   /**
563    * @brief flags to indicate which statistics values have been already
564    * collected from the statistics service.
565    * Used to check whether we are able to shutdown.
566    */
567   uint32_t stat_collected_flags;
568
569   /**
570    * @brief File name of the file the stats are finally written to
571    */
572   const char *file_name_stats;
573
574   /**
575    * @brief File name of the file the stats are finally written to
576    */
577   const char *file_name_probs;
578
579   /**
580    * @brief File name of the file the stats are finally written to
581    */
582   const char *file_name_probs_hist;
583
584   /**
585    * @brief The current view
586    */
587   struct GNUNET_PeerIdentity *cur_view;
588
589   /**
590    * @brief Number of peers in the #cur_view.
591    */
592   uint32_t cur_view_count;
593
594   /**
595    * @brief Number of occurrences in other peer's view
596    */
597   uint32_t count_in_views;
598
599   /**
600    * @brief statistics values
601    */
602   uint64_t stats[STAT_TYPE_MAX];
603   /**
604    * @brief Handle for the statistics get request
605    */
606   struct GNUNET_STATISTICS_GetHandle *h_stat_get[STAT_TYPE_MAX];
607
608   /**
609    * @brief Keep the probabilities in cache for computing the probabilities
610    * with respect to history.
611    */
612   double *eval_probs_cache;
613 };
614
615 /**
616  * Information for all the peers.
617  */
618 static struct RPSPeer *rps_peers;
619
620 /**
621  * Peermap to get the index of a given peer ID quick.
622  */
623 static struct GNUNET_CONTAINER_MultiPeerMap *peer_map;
624
625 /**
626  * IDs of the peers.
627  */
628 static struct GNUNET_PeerIdentity *rps_peer_ids;
629
630 /**
631  * ID of the targeted peer.
632  */
633 static struct GNUNET_PeerIdentity *target_peer;
634
635 /**
636  * Number of online peers.
637  */
638 static unsigned int num_peers_online;
639
640 /**
641  * @brief The added sizes of the peer's views
642  */
643 static unsigned int view_sizes;
644
645 /**
646  * Return value from 'main'.
647  */
648 static int ok;
649
650 /**
651  * Identifier for the task that runs after the test to collect results
652  */
653 static struct GNUNET_SCHEDULER_Task *post_test_task;
654
655 /**
656  * Identifier for the shutdown task
657  */
658 static struct GNUNET_SCHEDULER_Task *shutdown_task;
659
660
661 /**
662  * Identifier for the churn task that runs periodically
663  */
664 static struct GNUNET_SCHEDULER_Task *churn_task;
665
666 /**
667  * Called to initialise the given RPSPeer
668  */
669 typedef void (*InitPeer) (struct RPSPeer *rps_peer);
670
671 /**
672  * @brief Called directly after connecting to the service
673  *
674  * @param rps_peer Specific peer the function is called on
675  * @param h the handle to the rps service
676  */
677 typedef void (*PreTest) (struct RPSPeer *rps_peer, struct GNUNET_RPS_Handle *h);
678
679 /**
680  * @brief Executes functions to test the api/service for a given peer
681  *
682  * Called from within #rps_connect_complete_cb ()
683  * Implemented by #churn_test_cb, #profiler_cb, #mal_cb, #single_req_cb,
684  * #delay_req_cb, #seed_big_cb, #single_peer_seed_cb, #seed_cb, #req_cancel_cb
685  *
686  * @param rps_peer the peer the task runs on
687  */
688 typedef void (*MainTest) (struct RPSPeer *rps_peer);
689
690 /**
691  * Callback called once the requested random peers are available
692  */
693 typedef void (*ReplyHandle) (void *cls,
694                              uint64_t n,
695                              const struct GNUNET_PeerIdentity *recv_peers);
696
697 /**
698  * Called directly before disconnecting from the service
699  */
700 typedef void (*PostTest) (struct RPSPeer *peer);
701
702 /**
703  * Function called after disconnect to evaluate test success
704  */
705 typedef int (*EvaluationCallback) (void);
706
707 /**
708  * @brief Do we have Churn?
709  */
710 enum OPTION_CHURN
711 {
712   /**
713    * @brief If we have churn this is set
714    */
715   HAVE_CHURN,
716   /**
717    * @brief If we have no churn this is set
718    */
719   HAVE_NO_CHURN,
720 };
721
722 /**
723  * @brief Is it ok to quit the test before the timeout?
724  */
725 enum OPTION_QUICK_QUIT
726 {
727   /**
728    * @brief It is ok for the test to quit before the timeout triggers
729    */
730   HAVE_QUICK_QUIT,
731
732   /**
733    * @brief It is NOT ok for the test to quit before the timeout triggers
734    */
735   HAVE_NO_QUICK_QUIT,
736 };
737
738 /**
739  * @brief Do we collect statistics at the end?
740  */
741 enum OPTION_COLLECT_STATISTICS
742 {
743   /**
744    * @brief We collect statistics at the end
745    */
746   COLLECT_STATISTICS,
747
748   /**
749    * @brief We do not collect statistics at the end
750    */
751   NO_COLLECT_STATISTICS,
752 };
753
754 /**
755  * @brief Do we collect views during run?
756  */
757 enum OPTION_COLLECT_VIEW
758 {
759   /**
760    * @brief We collect view during run
761    */
762   COLLECT_VIEW,
763
764   /**
765    * @brief We do not collect the view during run
766    */
767   NO_COLLECT_VIEW,
768 };
769
770 /**
771  * Structure to define a single test
772  */
773 struct SingleTestRun
774 {
775   /**
776    * Name of the test
777    */
778   char *name;
779
780   /**
781    * Called with a single peer in order to initialise that peer
782    */
783   InitPeer init_peer;
784
785   /**
786    * Called directly after connecting to the service
787    */
788   PreTest pre_test;
789
790   /**
791    * Main function for each peer
792    */
793   MainTest main_test;
794
795   /**
796    * Callback called once the requested peers are available
797    */
798   ReplyHandle reply_handle;
799
800   /**
801    * Called directly before disconnecting from the service
802    */
803   PostTest post_test;
804
805   /**
806    * Function to evaluate the test results
807    */
808   EvaluationCallback eval_cb;
809
810   /**
811    * Request interval
812    */
813   uint32_t request_interval;
814
815   /**
816    * Number of Requests to make.
817    */
818   uint32_t num_requests;
819
820   /**
821    * Run with (-out) churn
822    */
823   enum OPTION_CHURN have_churn;
824
825   /**
826    * Quit test before timeout?
827    */
828   enum OPTION_QUICK_QUIT have_quick_quit;
829
830   /**
831    * Collect statistics at the end?
832    */
833   enum OPTION_COLLECT_STATISTICS have_collect_statistics;
834
835   /**
836    * Collect view during run?
837    */
838   enum OPTION_COLLECT_VIEW have_collect_view;
839
840   /**
841    * @brief Mark which values from the statistics service to collect at the end
842    * of the run
843    */
844   uint32_t stat_collect_flags;
845 } cur_test_run;
846
847 /**
848  * Did we finish the test?
849  */
850 static int post_test;
851
852 /**
853  * Are we shutting down?
854  */
855 static int in_shutdown;
856
857 /**
858  * Append arguments to file
859  */
860 static void
861 tofile_ (const char *file_name, const char *line)
862 {
863   struct GNUNET_DISK_FileHandle *f;
864   /* char output_buffer[512]; */
865   size_t size;
866   /* int size; */
867   size_t size2;
868
869   if (NULL == (f = GNUNET_DISK_file_open (file_name,
870                                           GNUNET_DISK_OPEN_APPEND
871                                           | GNUNET_DISK_OPEN_WRITE
872                                           | GNUNET_DISK_OPEN_CREATE,
873                                           GNUNET_DISK_PERM_USER_READ
874                                           | GNUNET_DISK_PERM_USER_WRITE
875                                           | GNUNET_DISK_PERM_GROUP_READ
876                                           | GNUNET_DISK_PERM_OTHER_READ)))
877   {
878     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
879                 "Not able to open file %s\n",
880                 file_name);
881     return;
882   }
883   /* size = GNUNET_snprintf (output_buffer,
884                           sizeof (output_buffer),
885                           "%llu %s\n",
886                           GNUNET_TIME_absolute_get ().abs_value_us,
887                           line);
888      if (0 > size)
889      {
890      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
891                 "Failed to write string to buffer (size: %i)\n",
892                 size);
893      return;
894      } */size = strlen (line) * sizeof(char);
895
896   size2 = GNUNET_DISK_file_write (f, line, size);
897   if (size != size2)
898   {
899     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
900                 "Unable to write to file! (Size: %lu, size2: %lu)\n",
901                 size,
902                 size2);
903     if (GNUNET_YES != GNUNET_DISK_file_close (f))
904     {
905       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
906                   "Unable to close file\n");
907     }
908     return;
909   }
910
911   if (GNUNET_YES != GNUNET_DISK_file_close (f))
912   {
913     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
914                 "Unable to close file\n");
915   }
916 }
917
918
919 /**
920  * This function is used to facilitate writing important information to disk
921  */
922 #define tofile(file_name, ...) do { \
923     char tmp_buf[512]; \
924     int size; \
925     size = GNUNET_snprintf (tmp_buf, sizeof(tmp_buf), __VA_ARGS__); \
926     if (0 > size) \
927       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \
928                   "Failed to create tmp_buf\n"); \
929     else \
930       tofile_ (file_name, tmp_buf); \
931 } while (0);
932
933
934 /**
935  * Write the ids and their according index in the given array to a file
936  * Unused
937  */
938 /* static void
939    ids_to_file (char *file_name,
940              struct GNUNET_PeerIdentity *peer_ids,
941              unsigned int num_peer_ids)
942    {
943    unsigned int i;
944
945    for (i=0 ; i < num_peer_ids ; i++)
946    {
947     to_file (file_name,
948              "%u\t%s",
949              i,
950              GNUNET_i2s_full (&peer_ids[i]));
951    }
952    } */
953
954 /**
955  * Test the success of a single test
956  */
957 static int
958 evaluate (void)
959 {
960   unsigned int i;
961   int tmp_ok;
962
963   tmp_ok = 1;
964
965   for (i = 0; i < num_peers; i++)
966   {
967     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
968                 "%u. peer [%s] received %u of %u expected peer_ids: %i\n",
969                 i,
970                 GNUNET_i2s (rps_peers[i].peer_id),
971                 rps_peers[i].num_recv_ids,
972                 rps_peers[i].num_ids_to_request,
973                 (rps_peers[i].num_ids_to_request == rps_peers[i].num_recv_ids));
974     tmp_ok &= (rps_peers[i].num_ids_to_request == rps_peers[i].num_recv_ids);
975   }
976   return tmp_ok ? 0 : 1;
977 }
978
979
980 /**
981  * Creates an oplist entry and adds it to the oplist DLL
982  */
983 static struct OpListEntry *
984 make_oplist_entry ()
985 {
986   struct OpListEntry *entry;
987
988   entry = GNUNET_new (struct OpListEntry);
989   GNUNET_CONTAINER_DLL_insert_tail (oplist_head, oplist_tail, entry);
990   return entry;
991 }
992
993
994 /**
995  * @brief Checks if given peer already received its statistics value from the
996  * statistics service.
997  *
998  * @param rps_peer the peer to check for
999  *
1000  * @return #GNUNET_YES if so
1001  *         #GNUNET_NO otherwise
1002  */
1003 static int
1004 check_statistics_collect_completed_single_peer (
1005   const struct RPSPeer *rps_peer)
1006 {
1007   if (cur_test_run.stat_collect_flags !=
1008       (cur_test_run.stat_collect_flags
1009        & rps_peer->stat_collected_flags))
1010   {
1011     return GNUNET_NO;
1012   }
1013   return GNUNET_YES;
1014 }
1015
1016
1017 /**
1018  * @brief Checks if all peers already received their statistics value from the
1019  * statistics service.
1020  *
1021  * @return #GNUNET_YES if so
1022  *         #GNUNET_NO otherwise
1023  */
1024 static int
1025 check_statistics_collect_completed ()
1026 {
1027   uint32_t i;
1028
1029   for (i = 0; i < num_peers; i++)
1030   {
1031     if (GNUNET_NO == check_statistics_collect_completed_single_peer (
1032           &rps_peers[i]))
1033     {
1034       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1035                   "At least Peer %" PRIu32
1036                   " did not yet receive all statistics values\n",
1037                   i);
1038       return GNUNET_NO;
1039     }
1040   }
1041   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1042               "All peers received their statistics values\n");
1043   return GNUNET_YES;
1044 }
1045
1046
1047 static void
1048 rps_disconnect_adapter (void *cls,
1049                         void *op_result);
1050
1051 static void
1052 cancel_pending_req (struct PendingRequest *pending_req)
1053 {
1054   struct RPSPeer *rps_peer;
1055
1056   rps_peer = pending_req->rps_peer;
1057   GNUNET_CONTAINER_DLL_remove (rps_peer->pending_req_head,
1058                                rps_peer->pending_req_tail,
1059                                pending_req);
1060   rps_peer->num_pending_reqs--;
1061   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1062               "Cancelling pending rps get request\n");
1063   GNUNET_SCHEDULER_cancel (pending_req->request_task);
1064   GNUNET_free (pending_req);
1065 }
1066
1067
1068 static void
1069 cancel_request (struct PendingReply *pending_rep)
1070 {
1071   struct RPSPeer *rps_peer;
1072
1073   rps_peer = pending_rep->rps_peer;
1074   GNUNET_CONTAINER_DLL_remove (rps_peer->pending_rep_head,
1075                                rps_peer->pending_rep_tail,
1076                                pending_rep);
1077   rps_peer->num_pending_reps--;
1078   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1079               "Cancelling rps get reply\n");
1080   GNUNET_assert (NULL != pending_rep->req_handle);
1081   GNUNET_RPS_request_single_info_cancel (pending_rep->req_handle);
1082   pending_rep->req_handle = NULL;
1083   GNUNET_free (pending_rep);
1084   pending_rep = NULL;
1085 }
1086
1087
1088 void
1089 clean_peer (unsigned peer_index)
1090 {
1091   struct PendingRequest *pending_req;
1092
1093   while (NULL != (pending_req = rps_peers[peer_index].pending_req_head))
1094   {
1095     cancel_pending_req (pending_req);
1096   }
1097   pending_req = rps_peers[peer_index].pending_req_head;
1098   rps_disconnect_adapter (&rps_peers[peer_index],
1099                           &rps_peers[peer_index].rps_handle);
1100   for (unsigned stat_type = STAT_TYPE_ROUNDS;
1101        stat_type < STAT_TYPE_MAX;
1102        stat_type++)
1103   {
1104     if (NULL != rps_peers[peer_index].h_stat_get[stat_type])
1105     {
1106       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1107                   "(%u) did not yet receive stat value for `%s'\n",
1108                   rps_peers[peer_index].index,
1109                   stat_type_strings[stat_type]);
1110       GNUNET_STATISTICS_get_cancel (
1111         rps_peers[peer_index].h_stat_get[stat_type]);
1112     }
1113   }
1114   if (NULL != rps_peers[peer_index].op)
1115   {
1116     GNUNET_TESTBED_operation_done (rps_peers[peer_index].op);
1117     rps_peers[peer_index].op = NULL;
1118   }
1119 }
1120
1121
1122 /**
1123  * Task run on timeout to shut everything down.
1124  */
1125 static void
1126 shutdown_op (void *cls)
1127 {
1128   unsigned int i;
1129   struct OpListEntry *entry;
1130
1131   (void) cls;
1132
1133   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1134               "Shutdown task scheduled, going down.\n");
1135   in_shutdown = GNUNET_YES;
1136
1137   if (NULL != shutdown_task)
1138   {
1139     GNUNET_SCHEDULER_cancel (shutdown_task);
1140     shutdown_task = NULL;
1141   }
1142   if (NULL != post_test_task)
1143   {
1144     GNUNET_SCHEDULER_cancel (post_test_task);
1145     post_test_task = NULL;
1146   }
1147   if (NULL != churn_task)
1148   {
1149     GNUNET_SCHEDULER_cancel (churn_task);
1150     churn_task = NULL;
1151   }
1152   entry = oplist_head;
1153   while (NULL != (entry = oplist_head))
1154   {
1155     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1156                 "Operation still pending on shutdown (%u)\n",
1157                 entry->index);
1158     GNUNET_TESTBED_operation_done (entry->op);
1159     GNUNET_CONTAINER_DLL_remove (oplist_head, oplist_tail, entry);
1160     GNUNET_free (entry);
1161   }
1162   for (i = 0; i < num_peers; i++)
1163   {
1164     clean_peer (i);
1165   }
1166   close_all_files ();
1167 }
1168
1169
1170 static void
1171 trigger_shutdown (void *cls)
1172 {
1173   (void) cls;
1174
1175   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1176               "Shutdown was triggerd by timeout, going down.\n");
1177   shutdown_task = NULL;
1178   GNUNET_SCHEDULER_shutdown ();
1179 }
1180
1181
1182 /**
1183  * Task run after #duration to collect statistics and potentially shut down.
1184  */
1185 static void
1186 post_test_op (void *cls)
1187 {
1188   unsigned int i;
1189
1190   (void) cls;
1191
1192   post_test_task = NULL;
1193   post_test = GNUNET_YES;
1194   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1195               "Executing post test op.\n");
1196   if (NULL != churn_task)
1197   {
1198     GNUNET_SCHEDULER_cancel (churn_task);
1199     churn_task = NULL;
1200   }
1201   for (i = 0; i < num_peers; i++)
1202   {
1203     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1204                 "Executing post test op. (peer %" PRIu32 ")\n",
1205                 rps_peers[i].index);
1206     if (NULL != rps_peers[i].op)
1207     {
1208       GNUNET_TESTBED_operation_done (rps_peers[i].op);
1209       rps_peers[i].op = NULL;
1210       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1211                   "Cancelled testbed operation\n");
1212     }
1213     if (NULL != cur_test_run.post_test)
1214     {
1215       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing post_test for peer %u\n",
1216                   i);
1217       cur_test_run.post_test (&rps_peers[i]);
1218     }
1219   }
1220   /* If we do not collect statistics, shut down directly */
1221   if ((NO_COLLECT_STATISTICS == cur_test_run.have_collect_statistics) ||
1222       (GNUNET_YES == check_statistics_collect_completed ()) )
1223   {
1224     GNUNET_SCHEDULER_cancel (shutdown_task);
1225     shutdown_task = NULL;
1226     GNUNET_SCHEDULER_shutdown ();
1227   }
1228 }
1229
1230
1231 /**
1232  * Seed peers.
1233  */
1234 static void
1235 seed_peers (void *cls)
1236 {
1237   struct RPSPeer *peer = cls;
1238   unsigned int amount;
1239   unsigned int i;
1240
1241   // TODO if malicious don't seed mal peers
1242   amount = round (.5 * num_peers);
1243
1244   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Seeding peers:\n");
1245   for (i = 0; i < amount; i++)
1246     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Seeding %u. peer: %s\n",
1247                 i,
1248                 GNUNET_i2s (&rps_peer_ids[i]));
1249
1250   GNUNET_RPS_seed_ids (peer->rps_handle, amount, rps_peer_ids);
1251 }
1252
1253
1254 /**
1255  * Get the id of peer i.
1256  */
1257 void
1258 info_cb (void *cb_cls,
1259          struct GNUNET_TESTBED_Operation *op,
1260          const struct GNUNET_TESTBED_PeerInformation *pinfo,
1261          const char *emsg)
1262 {
1263   struct OpListEntry *entry = (struct OpListEntry *) cb_cls;
1264
1265   (void) op;
1266
1267   if ((GNUNET_YES == in_shutdown) || (GNUNET_YES == post_test))
1268   {
1269     return;
1270   }
1271
1272   if ((NULL == pinfo) || (NULL != emsg))
1273   {
1274     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Got Error: %s\n", emsg);
1275     GNUNET_TESTBED_operation_done (entry->op);
1276     return;
1277   }
1278
1279   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1280               "Peer %u is %s\n",
1281               entry->index,
1282               GNUNET_i2s (pinfo->result.id));
1283
1284   rps_peer_ids[entry->index] = *(pinfo->result.id);
1285   rps_peers[entry->index].peer_id = &rps_peer_ids[entry->index];
1286
1287   GNUNET_assert (GNUNET_OK ==
1288                  GNUNET_CONTAINER_multipeermap_put (peer_map,
1289                                                     &rps_peer_ids[entry->index],
1290                                                     &rps_peers[entry->index],
1291                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1292   tofile ("/tmp/rps/peer_ids",
1293           "%u\t%s\n",
1294           entry->index,
1295           GNUNET_i2s_full (&rps_peer_ids[entry->index]));
1296
1297   GNUNET_CONTAINER_DLL_remove (oplist_head, oplist_tail, entry);
1298   GNUNET_TESTBED_operation_done (entry->op);
1299   GNUNET_free (entry);
1300 }
1301
1302
1303 /**
1304  * Callback to be called when RPS service connect operation is completed
1305  *
1306  * @param cls the callback closure from functions generating an operation
1307  * @param op the operation that has been finished
1308  * @param ca_result the RPS service handle returned from rps_connect_adapter
1309  * @param emsg error message in case the operation has failed; will be NULL if
1310  *          operation has executed successfully.
1311  */
1312 static void
1313 rps_connect_complete_cb (void *cls,
1314                          struct GNUNET_TESTBED_Operation *op,
1315                          void *ca_result,
1316                          const char *emsg)
1317 {
1318   struct RPSPeer *rps_peer = cls;
1319   struct GNUNET_RPS_Handle *rps = ca_result;
1320
1321   if ((GNUNET_YES == in_shutdown) || (GNUNET_YES == post_test))
1322   {
1323     return;
1324   }
1325
1326   rps_peer->rps_handle = rps;
1327   rps_peer->online = GNUNET_YES;
1328   num_peers_online++;
1329
1330   GNUNET_assert (op == rps_peer->op);
1331   if (NULL != emsg)
1332   {
1333     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1334                 "Failed to connect to RPS service: %s\n",
1335                 emsg);
1336     ok = 1;
1337     GNUNET_SCHEDULER_shutdown ();
1338     return;
1339   }
1340
1341   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1342               "Started client successfully (%u)\n",
1343               rps_peer->index);
1344
1345   cur_test_run.main_test (rps_peer);
1346 }
1347
1348
1349 /**
1350  * Adapter function called to establish a connection to
1351  * the RPS service.
1352  *
1353  * @param cls closure
1354  * @param cfg configuration of the peer to connect to; will be available until
1355  *          GNUNET_TESTBED_operation_done() is called on the operation returned
1356  *          from GNUNET_TESTBED_service_connect()
1357  * @return service handle to return in 'op_result', NULL on error
1358  */
1359 static void *
1360 rps_connect_adapter (void *cls,
1361                      const struct GNUNET_CONFIGURATION_Handle *cfg)
1362 {
1363   struct GNUNET_RPS_Handle *h;
1364
1365   h = GNUNET_RPS_connect (cfg);
1366
1367   if (NULL != cur_test_run.pre_test)
1368     cur_test_run.pre_test (cls, h);
1369
1370   return h;
1371 }
1372
1373
1374 /**
1375  * Called to open a connection to the peer's statistics
1376  *
1377  * @param cls peer context
1378  * @param cfg configuration of the peer to connect to; will be available until
1379  *          GNUNET_TESTBED_operation_done() is called on the operation returned
1380  *          from GNUNET_TESTBED_service_connect()
1381  * @return service handle to return in 'op_result', NULL on error
1382  */
1383 static void *
1384 stat_connect_adapter (void *cls,
1385                       const struct GNUNET_CONFIGURATION_Handle *cfg)
1386 {
1387   struct RPSPeer *peer = cls;
1388
1389   peer->stats_h = GNUNET_STATISTICS_create ("rps-profiler", cfg);
1390   return peer->stats_h;
1391 }
1392
1393
1394 /**
1395  * Called to disconnect from peer's statistics service
1396  *
1397  * @param cls peer context
1398  * @param op_result service handle returned from the connect adapter
1399  */
1400 static void
1401 stat_disconnect_adapter (void *cls, void *op_result)
1402 {
1403   struct RPSPeer *peer = cls;
1404
1405   // GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch_cancel
1406   //              (peer->stats_h, "core", "# peers connected",
1407   //               stat_iterator, peer));
1408   // GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch_cancel
1409   //              (peer->stats_h, "nse", "# peers connected",
1410   //               stat_iterator, peer));
1411   GNUNET_STATISTICS_destroy (op_result, GNUNET_NO);
1412   peer->stats_h = NULL;
1413 }
1414
1415
1416 /**
1417  * Called after successfully opening a connection to a peer's statistics
1418  * service; we register statistics monitoring for CORE and NSE here.
1419  *
1420  * @param cls the callback closure from functions generating an operation
1421  * @param op the operation that has been finished
1422  * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter()
1423  * @param emsg error message in case the operation has failed; will be NULL if
1424  *          operation has executed successfully.
1425  */
1426 static void
1427 stat_complete_cb (void *cls,
1428                   struct GNUNET_TESTBED_Operation *op,
1429                   void *ca_result,
1430                   const char *emsg)
1431 {
1432   // struct GNUNET_STATISTICS_Handle *sh = ca_result;
1433   // struct RPSPeer *peer = (struct RPSPeer *) cls;
1434   (void) cls;
1435   (void) op;
1436   (void) ca_result;
1437
1438   if (NULL != emsg)
1439   {
1440     GNUNET_break (0);
1441     return;
1442   }
1443   // GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch
1444   //              (sh, "core", "# peers connected",
1445   //               stat_iterator, peer));
1446   // GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch
1447   //              (sh, "nse", "# peers connected",
1448   //               stat_iterator, peer));
1449 }
1450
1451
1452 /**
1453  * Adapter function called to destroy connection to
1454  * RPS service.
1455  *
1456  * @param cls closure
1457  * @param op_result service handle returned from the connect adapter
1458  */
1459 static void
1460 rps_disconnect_adapter (void *cls,
1461                         void *op_result)
1462 {
1463   struct RPSPeer *peer = cls;
1464   struct GNUNET_RPS_Handle *h = op_result;
1465   struct PendingReply *pending_rep;
1466
1467   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1468               "disconnect_adapter (%u)\n",
1469               peer->index);
1470   GNUNET_assert (NULL != peer);
1471   if (NULL != peer->rps_handle)
1472   {
1473     while (NULL != (pending_rep = peer->pending_rep_head))
1474     {
1475       cancel_request (pending_rep);
1476     }
1477     GNUNET_assert (h == peer->rps_handle);
1478     if (NULL != h)
1479     {
1480       GNUNET_RPS_disconnect (h);
1481       h = NULL;
1482     }
1483     peer->rps_handle = NULL;
1484   }
1485 }
1486
1487
1488 /***********************************************************************
1489 * Definition of tests
1490 ***********************************************************************/
1491
1492 /**
1493  * Callback to call on receipt of a reply
1494  *
1495  * @param cls closure
1496  * @param n number of peers
1497  * @param recv_peers the received peers
1498  */
1499 static void
1500 default_reply_handle (void *cls,
1501                       uint64_t n,
1502                       const struct GNUNET_PeerIdentity *recv_peers)
1503 {
1504   struct RPSPeer *rps_peer;
1505   struct PendingReply *pending_rep = (struct PendingReply *) cls;
1506   unsigned int i;
1507
1508   rps_peer = pending_rep->rps_peer;
1509   GNUNET_CONTAINER_DLL_remove (rps_peer->pending_rep_head,
1510                                rps_peer->pending_rep_tail,
1511                                pending_rep);
1512   rps_peer->num_pending_reps--;
1513   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1514               "[%s] got %" PRIu64 " peers:\n",
1515               GNUNET_i2s (rps_peer->peer_id),
1516               n);
1517
1518   for (i = 0; i < n; i++)
1519   {
1520     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1521                 "%u: %s\n",
1522                 i,
1523                 GNUNET_i2s (&recv_peers[i]));
1524
1525     rps_peer->num_recv_ids++;
1526   }
1527
1528   if (GNUNET_YES != post_test)
1529     return;
1530   if (HAVE_QUICK_QUIT != cur_test_run.have_quick_quit)
1531     return;
1532   if (0 == evaluate ())
1533   {
1534     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1535                 "Test succeeded before end of duration\n");
1536     if (NULL != post_test_task)
1537       GNUNET_SCHEDULER_cancel (post_test_task);
1538     post_test_task = GNUNET_SCHEDULER_add_now (&post_test_op, NULL);
1539     GNUNET_assert (NULL != post_test_task);
1540   }
1541 }
1542
1543
1544 static void
1545 profiler_reply_handle_info (void *cls,
1546                             const struct GNUNET_PeerIdentity *recv_peer,
1547                             double probability,
1548                             uint32_t num_observed);
1549
1550 /**
1551  * Request random peers.
1552  */
1553 static void
1554 request_peers (void *cls)
1555 {
1556   struct PendingRequest *pending_req = cls;
1557   struct RPSPeer *rps_peer;
1558   struct PendingReply *pending_rep;
1559
1560   rps_peer = pending_req->rps_peer;
1561   GNUNET_assert (1 <= rps_peer->num_pending_reqs);
1562   GNUNET_CONTAINER_DLL_remove (rps_peer->pending_req_head,
1563                                rps_peer->pending_req_tail,
1564                                pending_req);
1565   rps_peer->num_pending_reqs--;
1566   if ((GNUNET_YES == in_shutdown) || (GNUNET_YES == post_test))
1567     return;
1568   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1569               "Requesting one peer\n");
1570   pending_rep = GNUNET_new (struct PendingReply);
1571   pending_rep->rps_peer = rps_peer;
1572   // pending_rep->req_handle = GNUNET_RPS_request_peers (rps_peer->rps_handle,
1573   //    1,
1574   //    cur_test_run.reply_handle,
1575   //    pending_rep);
1576   pending_rep->req_handle = GNUNET_RPS_request_peer_info (rps_peer->rps_handle,
1577                                                           profiler_reply_handle_info,
1578                                                           pending_rep);
1579   GNUNET_CONTAINER_DLL_insert_tail (rps_peer->pending_rep_head,
1580                                     rps_peer->pending_rep_tail,
1581                                     pending_rep);
1582   rps_peer->num_pending_reps++;
1583 }
1584
1585
1586 /**
1587  * Schedule requests for peer @a rps_peer that have neither been scheduled, nor
1588  * issued, nor replied
1589  */
1590 void
1591 schedule_missing_requests (struct RPSPeer *rps_peer)
1592 {
1593   unsigned int i;
1594   struct PendingRequest *pending_req;
1595
1596   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1597               "Scheduling %u - %u missing requests\n",
1598               rps_peer->num_ids_to_request,
1599               rps_peer->num_pending_reqs + rps_peer->num_pending_reps);
1600   GNUNET_assert (rps_peer->num_pending_reqs + rps_peer->num_pending_reps <=
1601                  rps_peer->num_ids_to_request);
1602   for (i = rps_peer->num_pending_reqs + rps_peer->num_pending_reps;
1603        i < rps_peer->num_ids_to_request; i++)
1604   {
1605     pending_req = GNUNET_new (struct PendingRequest);
1606     pending_req->rps_peer = rps_peer;
1607     pending_req->request_task = GNUNET_SCHEDULER_add_delayed (
1608       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
1609                                      cur_test_run.request_interval * i),
1610       request_peers,
1611       pending_req);
1612     GNUNET_CONTAINER_DLL_insert_tail (rps_peer->pending_req_head,
1613                                       rps_peer->pending_req_tail,
1614                                       pending_req);
1615     rps_peer->num_pending_reqs++;
1616   }
1617 }
1618
1619
1620 void
1621 cancel_pending_req_rep (struct RPSPeer *rps_peer)
1622 {
1623   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1624               "Cancelling all (pending) requests.\n");
1625   while (NULL != rps_peer->pending_req_head)
1626     cancel_pending_req (rps_peer->pending_req_head);
1627   GNUNET_assert (0 == rps_peer->num_pending_reqs);
1628   while (NULL != rps_peer->pending_rep_head)
1629     cancel_request (rps_peer->pending_rep_head);
1630   GNUNET_assert (0 == rps_peer->num_pending_reps);
1631 }
1632
1633
1634 /***********************************
1635 * MALICIOUS
1636 ***********************************/
1637
1638 /**
1639  * Initialise only non-mal RPSPeers
1640  */
1641 static void
1642 mal_init_peer (struct RPSPeer *rps_peer)
1643 {
1644   if (rps_peer->index >= round (portion * num_peers))
1645     rps_peer->num_ids_to_request = 1;
1646 }
1647
1648
1649 /**
1650  * @brief Set peers to (non-)malicious before execution
1651  *
1652  * Of signature #PreTest
1653  *
1654  * @param rps_peer the peer to set (non-) malicious
1655  * @param h the handle to the service
1656  */
1657 static void
1658 mal_pre (struct RPSPeer *rps_peer, struct GNUNET_RPS_Handle *h)
1659 {
1660   #if ENABLE_MALICIOUS
1661   uint32_t num_mal_peers;
1662
1663   GNUNET_assert ((1 >= portion) &&
1664                  (0 < portion));
1665   num_mal_peers = round (portion * num_peers);
1666
1667   if (rps_peer->index < num_mal_peers)
1668   {
1669     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1670                 "%u. peer [%s] of %" PRIu32
1671                 " malicious peers turning malicious\n",
1672                 rps_peer->index,
1673                 GNUNET_i2s (rps_peer->peer_id),
1674                 num_mal_peers);
1675
1676     GNUNET_RPS_act_malicious (h, mal_type, num_mal_peers,
1677                               rps_peer_ids, target_peer);
1678   }
1679   #endif /* ENABLE_MALICIOUS */
1680 }
1681
1682
1683 static void
1684 mal_cb (struct RPSPeer *rps_peer)
1685 {
1686   uint32_t num_mal_peers;
1687
1688   if ((GNUNET_YES == in_shutdown) || (GNUNET_YES == post_test))
1689   {
1690     return;
1691   }
1692
1693   #if ENABLE_MALICIOUS
1694   GNUNET_assert ((1 >= portion) &&
1695                  (0 < portion));
1696   num_mal_peers = round (portion * num_peers);
1697
1698   if (rps_peer->index >= num_mal_peers)
1699   {   /* It's useless to ask a malicious peer about a random sample -
1700          it's not sampling */
1701     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (
1702                                     GNUNET_TIME_UNIT_SECONDS, 2),
1703                                   seed_peers, rps_peer);
1704     schedule_missing_requests (rps_peer);
1705   }
1706   #endif /* ENABLE_MALICIOUS */
1707 }
1708
1709
1710 /***********************************
1711 * CHURN
1712 ***********************************/
1713
1714 static void
1715 churn (void *cls);
1716
1717 /**
1718  * @brief Starts churn
1719  *
1720  * Has signature of #MainTest
1721  *
1722  * This is not implemented too nicely as this is called for each peer, but we
1723  * only need to call it once. (Yes we check that we only schedule the task
1724  * once.)
1725  *
1726  * @param rps_peer The peer it's called for
1727  */
1728 static void
1729 churn_test_cb (struct RPSPeer *rps_peer)
1730 {
1731   if ((GNUNET_YES == in_shutdown) || (GNUNET_YES == post_test))
1732   {
1733     return;
1734   }
1735
1736   /* Start churn */
1737   if ((HAVE_CHURN == cur_test_run.have_churn) && (NULL == churn_task))
1738   {
1739     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1740                 "Starting churn task\n");
1741     churn_task = GNUNET_SCHEDULER_add_delayed (
1742       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
1743       churn,
1744       NULL);
1745   }
1746   else
1747   {
1748     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1749                 "Not starting churn task\n");
1750   }
1751
1752   schedule_missing_requests (rps_peer);
1753 }
1754
1755
1756 /***********************************
1757 * PROFILER
1758 ***********************************/
1759
1760 /**
1761  * Callback to be called when RPS service is started or stopped at peers
1762  *
1763  * @param cls NULL
1764  * @param op the operation handle
1765  * @param emsg NULL on success; otherwise an error description
1766  */
1767 static void
1768 churn_cb (void *cls,
1769           struct GNUNET_TESTBED_Operation *op,
1770           const char *emsg)
1771 {
1772   // FIXME
1773   struct OpListEntry *entry = cls;
1774
1775   (void) op;
1776
1777   if ((GNUNET_YES == in_shutdown) || (GNUNET_YES == post_test))
1778   {
1779     return;
1780   }
1781
1782   GNUNET_TESTBED_operation_done (entry->op);
1783   if (NULL != emsg)
1784   {
1785     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1786                 "Failed to start/stop RPS at a peer\n");
1787     GNUNET_SCHEDULER_shutdown ();
1788     return;
1789   }
1790   GNUNET_assert (0 != entry->delta);
1791
1792   num_peers_online += entry->delta;
1793
1794   if (PEER_GO_OFFLINE == entry->delta)
1795   {   /* Peer hopefully just went offline */
1796     if (GNUNET_YES != rps_peers[entry->index].online)
1797     {
1798       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1799                   "peer %s was expected to go offline but is still marked as online\n",
1800                   GNUNET_i2s (rps_peers[entry->index].peer_id));
1801       GNUNET_break (0);
1802     }
1803     else
1804     {
1805       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1806                   "peer %s probably went offline as expected\n",
1807                   GNUNET_i2s (rps_peers[entry->index].peer_id));
1808     }
1809     rps_peers[entry->index].online = GNUNET_NO;
1810   }
1811
1812   else if (PEER_GO_ONLINE < entry->delta)
1813   {   /* Peer hopefully just went online */
1814     if (GNUNET_NO != rps_peers[entry->index].online)
1815     {
1816       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1817                   "peer %s was expected to go online but is still marked as offline\n",
1818                   GNUNET_i2s (rps_peers[entry->index].peer_id));
1819       GNUNET_break (0);
1820     }
1821     else
1822     {
1823       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1824                   "peer %s probably went online as expected\n",
1825                   GNUNET_i2s (rps_peers[entry->index].peer_id));
1826       if (NULL != cur_test_run.pre_test)
1827       {
1828         cur_test_run.pre_test (&rps_peers[entry->index],
1829                                rps_peers[entry->index].rps_handle);
1830         schedule_missing_requests (&rps_peers[entry->index]);
1831       }
1832     }
1833     rps_peers[entry->index].online = GNUNET_YES;
1834   }
1835   else
1836   {
1837     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1838                 "Invalid value for delta: %i\n", entry->delta);
1839     GNUNET_break (0);
1840   }
1841
1842   GNUNET_CONTAINER_DLL_remove (oplist_head, oplist_tail, entry);
1843   rps_peers[entry->index].entry_op_manage = NULL;
1844   GNUNET_free (entry);
1845   // if (num_peers_in_round[current_round] == peers_running)
1846   //  run_round ();
1847 }
1848
1849
1850 /**
1851  * @brief Set the rps-service up or down for a specific peer
1852  *
1853  * @param i index of action
1854  * @param j index of peer
1855  * @param delta (#PEER_ONLINE_DELTA) down (-1) or up (1)
1856  * @param prob_go_on_off the probability of the action
1857  */
1858 static void
1859 manage_service_wrapper (unsigned int i, unsigned int j,
1860                         enum PEER_ONLINE_DELTA delta,
1861                         double prob_go_on_off)
1862 {
1863   struct OpListEntry *entry = NULL;
1864   uint32_t prob;
1865
1866   /* make sure that management operation is not already scheduled */
1867   if (NULL != rps_peers[j].entry_op_manage)
1868   {
1869     return;
1870   }
1871
1872   prob = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1873                                    UINT32_MAX);
1874   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1875               "%u. selected peer (%u: %s) is %s.\n",
1876               i,
1877               j,
1878               GNUNET_i2s (rps_peers[j].peer_id),
1879               (PEER_GO_ONLINE == delta) ? "online" : "offline");
1880   if (prob < prob_go_on_off * UINT32_MAX)
1881   {
1882     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1883                 "%s goes %s\n",
1884                 GNUNET_i2s (rps_peers[j].peer_id),
1885                 (PEER_GO_OFFLINE == delta) ? "offline" : "online");
1886
1887     if (PEER_GO_OFFLINE == delta)
1888       cancel_pending_req_rep (&rps_peers[j]);
1889     entry = make_oplist_entry ();
1890     entry->delta = delta;
1891     entry->index = j;
1892     entry->op = GNUNET_TESTBED_peer_manage_service (NULL,
1893                                                     testbed_peers[j],
1894                                                     "rps",
1895                                                     &churn_cb,
1896                                                     entry,
1897                                                     (PEER_GO_OFFLINE == delta) ?
1898                                                     0 : 1);
1899     rps_peers[j].entry_op_manage = entry;
1900   }
1901 }
1902
1903
1904 static void
1905 churn (void *cls)
1906 {
1907   unsigned int i;
1908   unsigned int j;
1909   double portion_online;
1910   unsigned int *permut;
1911   double prob_go_offline;
1912   double portion_go_online;
1913   double portion_go_offline;
1914
1915   (void) cls;
1916
1917   if ((GNUNET_YES == in_shutdown) || (GNUNET_YES == post_test))
1918   {
1919     return;
1920   }
1921   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1922               "Churn function executing\n");
1923
1924   churn_task = NULL; /* Should be invalid by now */
1925
1926   /* Compute the probability for an online peer to go offline
1927    * this round */
1928   portion_online = num_peers_online * 1.0 / num_peers;
1929   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1930               "Portion online: %f\n",
1931               portion_online);
1932   portion_go_online = ((1 - portion_online) * .5 * .66);
1933   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1934               "Portion that should go online: %f\n",
1935               portion_go_online);
1936   portion_go_offline = (portion_online + portion_go_online) - .75;
1937   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1938               "Portion that probably goes offline: %f\n",
1939               portion_go_offline);
1940   prob_go_offline = portion_go_offline / (portion_online * .5);
1941   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1942               "Probability of a selected online peer to go offline: %f\n",
1943               prob_go_offline);
1944
1945   permut = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
1946                                          (unsigned int) num_peers);
1947
1948   /* Go over 50% randomly chosen peers */
1949   for (i = 0; i < .5 * num_peers; i++)
1950   {
1951     j = permut[i];
1952
1953     /* If online, shut down with certain probability */
1954     if (GNUNET_YES == rps_peers[j].online)
1955     {
1956       manage_service_wrapper (i, j, -1, prob_go_offline);
1957     }
1958
1959     /* If offline, restart with certain probability */
1960     else if (GNUNET_NO == rps_peers[j].online)
1961     {
1962       manage_service_wrapper (i, j, 1, 0.66);
1963     }
1964   }
1965
1966   GNUNET_free (permut);
1967
1968   churn_task = GNUNET_SCHEDULER_add_delayed (
1969     GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
1970     churn,
1971     NULL);
1972 }
1973
1974
1975 /**
1976  * Initialise given RPSPeer
1977  */
1978 static void
1979 profiler_init_peer (struct RPSPeer *rps_peer)
1980 {
1981   rps_peer->num_ids_to_request = cur_test_run.num_requests;
1982   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "peer shall request %i peers\n",
1983               rps_peer->num_ids_to_request);
1984 }
1985
1986
1987 /**
1988  * Callback to call on receipt of a reply
1989  *
1990  * @param cls closure
1991  * @param n number of peers
1992  * @param recv_peers the received peers
1993  */
1994 static void
1995 profiler_reply_handle (void *cls,
1996                        uint64_t n,
1997                        const struct GNUNET_PeerIdentity *recv_peers)
1998 {
1999   struct RPSPeer *rps_peer;
2000   struct RPSPeer *rcv_rps_peer;
2001   char file_name_buf[128];
2002   char file_name_dh_buf[128];
2003   char file_name_dhr_buf[128];
2004   char file_name_dhru_buf[128];
2005   char *file_name = file_name_buf;
2006   char *file_name_dh = file_name_dh_buf;
2007   char *file_name_dhr = file_name_dhr_buf;
2008   char *file_name_dhru = file_name_dhru_buf;
2009   unsigned int i;
2010   struct PendingReply *pending_rep = (struct PendingReply *) cls;
2011
2012   pending_rep->req_handle = NULL;
2013   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "profiler_reply_handle()\n");
2014   rps_peer = pending_rep->rps_peer;
2015   (void) GNUNET_asprintf (&file_name,
2016                           "/tmp/rps/received_ids-%u",
2017                           rps_peer->index);
2018
2019   (void) GNUNET_asprintf (&file_name_dh,
2020                           "/tmp/rps/diehard_input-%u",
2021                           rps_peer->index);
2022   (void) GNUNET_asprintf (&file_name_dhr,
2023                           "/tmp/rps/diehard_input_raw-%u",
2024                           rps_peer->index);
2025   (void) GNUNET_asprintf (&file_name_dhru,
2026                           "/tmp/rps/diehard_input_raw_aligned-%u",
2027                           rps_peer->index);
2028   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2029               "[%s] got %" PRIu64 " peers:\n",
2030               GNUNET_i2s (rps_peer->peer_id),
2031               n);
2032   for (i = 0; i < n; i++)
2033   {
2034     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2035                 "%u: %s\n",
2036                 i,
2037                 GNUNET_i2s (&recv_peers[i]));
2038     tofile (file_name,
2039             "%s\n",
2040             GNUNET_i2s_full (&recv_peers[i]));
2041     rcv_rps_peer = GNUNET_CONTAINER_multipeermap_get (peer_map, &recv_peers[i]);
2042     GNUNET_assert (NULL != rcv_rps_peer);
2043     tofile (file_name_dh,
2044             "%" PRIu32 "\n",
2045             (uint32_t) rcv_rps_peer->index);
2046 #ifdef TO_FILE
2047     to_file_raw (file_name_dhr,
2048                  (char *) &rcv_rps_peer->index,
2049                  sizeof(uint32_t));
2050     to_file_raw_unaligned (file_name_dhru,
2051                            (char *) &rcv_rps_peer->index,
2052                            sizeof(uint32_t),
2053                            bits_needed);
2054 #endif /* TO_FILE */
2055   }
2056   default_reply_handle (cls, n, recv_peers);
2057 }
2058
2059
2060 /**
2061  * Callback to call on receipt of a reply
2062  *
2063  * @param cls closure
2064  * @param n number of peers
2065  * @param recv_peers the received peers
2066  */
2067 static void
2068 profiler_reply_handle_info (void *cls,
2069                             const struct GNUNET_PeerIdentity *recv_peer,
2070                             double probability,
2071                             uint32_t num_observed)
2072 {
2073   struct RPSPeer *rps_peer;
2074   struct RPSPeer *rcv_rps_peer;
2075   char file_name_buf[128];
2076   char file_name_dh_buf[128];
2077   char file_name_dhr_buf[128];
2078   char file_name_dhru_buf[128];
2079   char *file_name = file_name_buf;
2080   char *file_name_dh = file_name_dh_buf;
2081   char *file_name_dhr = file_name_dhr_buf;
2082   char *file_name_dhru = file_name_dhru_buf;
2083   unsigned int i;
2084   struct PendingReply *pending_rep = (struct PendingReply *) cls;
2085
2086   pending_rep->req_handle = NULL;
2087   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "profiler_reply_handle()\n");
2088   rps_peer = pending_rep->rps_peer;
2089   (void) GNUNET_asprintf (&file_name,
2090                           "/tmp/rps/received_ids-%u",
2091                           rps_peer->index);
2092
2093   (void) GNUNET_asprintf (&file_name_dh,
2094                           "/tmp/rps/diehard_input-%u",
2095                           rps_peer->index);
2096   (void) GNUNET_asprintf (&file_name_dhr,
2097                           "/tmp/rps/diehard_input_raw-%u",
2098                           rps_peer->index);
2099   (void) GNUNET_asprintf (&file_name_dhru,
2100                           "/tmp/rps/diehard_input_raw_aligned-%u",
2101                           rps_peer->index);
2102   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2103               "[%s] got peer with info:\n",
2104               GNUNET_i2s (rps_peer->peer_id));
2105   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2106               "  %s\n",
2107               GNUNET_i2s (recv_peer));
2108   tofile (file_name,
2109           "%s %d %" PRIu32 " \n",
2110           GNUNET_i2s_full (recv_peer),
2111           probability,
2112           num_observed);
2113   rcv_rps_peer = GNUNET_CONTAINER_multipeermap_get (peer_map, recv_peer);
2114   GNUNET_assert (NULL != rcv_rps_peer);
2115   tofile (file_name_dh,
2116           "%" PRIu32 "\n",
2117           (uint32_t) rcv_rps_peer->index);
2118 #ifdef TO_FILE
2119   to_file_raw (file_name_dhr,
2120                (char *) &rcv_rps_peer->index,
2121                sizeof(uint32_t));
2122   to_file_raw_unaligned (file_name_dhru,
2123                          (char *) &rcv_rps_peer->index,
2124                          sizeof(uint32_t),
2125                          bits_needed);
2126 #endif /* TO_FILE */
2127   default_reply_handle (cls, 1, recv_peer);
2128 }
2129
2130
2131 static void
2132 profiler_cb (struct RPSPeer *rps_peer)
2133 {
2134   if ((GNUNET_YES == in_shutdown) || (GNUNET_YES == post_test))
2135   {
2136     return;
2137   }
2138
2139   /* Start churn */
2140   if ((HAVE_CHURN == cur_test_run.have_churn) && (NULL == churn_task))
2141   {
2142     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2143                 "Starting churn task\n");
2144     churn_task = GNUNET_SCHEDULER_add_delayed (
2145       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
2146       churn,
2147       NULL);
2148   }
2149   else
2150   {
2151     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2152                 "Not starting churn task\n");
2153   }
2154
2155   /* Only request peer ids at one peer.
2156    * (It's the before-last because last one is target of the focussed attack.)
2157    */
2158   if (0 < rps_peer->num_ids_to_request)
2159     schedule_missing_requests (rps_peer);
2160 }
2161
2162
2163 /**
2164  * Function called from #profiler_eval with a filename.
2165  *
2166  * @param cls closure
2167  * @param filename complete filename (absolute path)
2168  * @return #GNUNET_OK to continue to iterate,
2169  *  #GNUNET_NO to stop iteration with no error,
2170  *  #GNUNET_SYSERR to abort iteration with error!
2171  */
2172 static int
2173 file_name_cb (void *cls, const char *filename)
2174 {
2175   if (NULL != strstr (filename, "sampler_el"))
2176   {
2177     struct RPS_SamplerElement *s_elem;
2178     struct GNUNET_CRYPTO_AuthKey auth_key;
2179     const char *key_char;
2180     uint32_t i;
2181     (void) cls;
2182
2183     key_char = filename + 20;   /* Length of "/tmp/rps/sampler_el-" */
2184     tofile (filename, "--------------------------\n");
2185
2186     auth_key = string_to_auth_key (key_char);
2187     s_elem = RPS_sampler_elem_create ();
2188     RPS_sampler_elem_set (s_elem, auth_key);
2189
2190     for (i = 0; i < num_peers; i++)
2191     {
2192       RPS_sampler_elem_next (s_elem, &rps_peer_ids[i]);
2193     }
2194     RPS_sampler_elem_destroy (s_elem);
2195   }
2196   return GNUNET_OK;
2197 }
2198
2199
2200 /**
2201  * This is run after the test finished.
2202  *
2203  * Compute all perfect samples.
2204  */
2205 static int
2206 profiler_eval (void)
2207 {
2208 #ifdef TO_FILE
2209   /* Compute perfect sample for each sampler element */
2210   if (-1 == GNUNET_DISK_directory_scan ("/tmp/rps/", file_name_cb, NULL))
2211   {
2212     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Scan of directory failed\n");
2213   }
2214 #endif /* TO_FILE */
2215
2216   return evaluate ();
2217 }
2218
2219
2220 /** @brief is b in view of a?
2221  *
2222  * @param a
2223  * @param b
2224  *
2225  * @return
2226  */
2227 static int
2228 is_in_view (uint32_t a, uint32_t b)
2229 {
2230   uint32_t i;
2231
2232   for (i = 0; i < rps_peers[a].cur_view_count; i++)
2233   {
2234     if (0 == memcmp (rps_peers[b].peer_id,
2235                      &rps_peers[a].cur_view[i],
2236                      sizeof(struct GNUNET_PeerIdentity)))
2237     {
2238       return GNUNET_YES;
2239     }
2240   }
2241   return GNUNET_NO;
2242 }
2243
2244
2245 static uint32_t
2246 get_idx_of_pid (const struct GNUNET_PeerIdentity *pid)
2247 {
2248   uint32_t i;
2249
2250   for (i = 0; i < num_peers; i++)
2251   {
2252     if (0 == memcmp (pid,
2253                      rps_peers[i].peer_id,
2254                      sizeof(struct GNUNET_PeerIdentity)))
2255     {
2256       return i;
2257     }
2258   }
2259   // return 0; /* Should not happen - make compiler happy */
2260   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2261               "No known _PeerIdentity %s!\n",
2262               GNUNET_i2s_full (pid));
2263   GNUNET_assert (0);
2264 }
2265
2266
2267 /**
2268  * @brief Counts number of peers in view of a that have b in their view
2269  *
2270  * @param a
2271  * @param uint32_tb
2272  *
2273  * @return
2274  */
2275 static uint32_t
2276 count_containing_views (uint32_t a, uint32_t b)
2277 {
2278   uint32_t i;
2279   uint32_t peer_idx;
2280   uint32_t count = 0;
2281
2282   for (i = 0; i < rps_peers[a].cur_view_count; i++)
2283   {
2284     peer_idx = get_idx_of_pid (&rps_peers[a].cur_view[i]);
2285     if (GNUNET_YES == is_in_view (peer_idx, b))
2286     {
2287       count++;
2288     }
2289   }
2290   return count;
2291 }
2292
2293
2294 /**
2295  * @brief Computes the probability for each other peer to be selected by the
2296  * sampling process based on the views of all peers
2297  *
2298  * @param peer_idx index of the peer that is about to sample
2299  */
2300 static void
2301 compute_probabilities (uint32_t peer_idx)
2302 {
2303   // double probs[num_peers] = { 0 };
2304   double probs[num_peers];
2305   double probs_hist[num_peers]; /* Probability respecting the history */
2306   size_t probs_as_str_size = (num_peers * 10 + 2) * sizeof(char);
2307   char *probs_as_str = GNUNET_malloc (probs_as_str_size);
2308   char *probs_as_str_cpy;
2309   uint32_t i;
2310   double prob_push;
2311   double prob_pull;
2312   uint32_t view_size;
2313   uint32_t cont_views;
2314   uint32_t number_of_being_in_pull_events;
2315   int tmp;
2316   double sum_non_zero_prob = 0;
2317   double sum_non_zero_prob_hist = 0;
2318
2319   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2320               "Computing probabilities for peer %" PRIu32 "\n", peer_idx);
2321   /* Firstly without knowledge of old views */
2322   for (i = 0; i < num_peers; i++)
2323   {
2324     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2325                 "\tfor peer %" PRIu32 ":\n", i);
2326     view_size = rps_peers[i].cur_view_count;
2327     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2328                 "\t\tview_size: %" PRIu32 "\n", view_size);
2329     /* For peer i the probability of being sampled is
2330      * evenly distributed among all possibly observed peers. */
2331     /* We could have observed a peer in three cases:
2332      *   1. peer sent a push
2333      *   2. peer was contained in a pull reply
2334      *   3. peer was in history (sampler) - ignored for now */
2335     /* 1. Probability of having received a push from peer i */
2336     if ((GNUNET_YES == is_in_view (i, peer_idx)) &&
2337         (1 <= (0.45 * view_size)))
2338     {
2339       if (0 == binom (view_size, 0.45 * view_size))
2340         prob_push = 0;
2341       else
2342       {
2343         prob_push = 1.0 * binom (0.45 * view_size, 1)
2344                     /
2345                     binom (view_size, 0.45 * view_size);
2346       }
2347       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2348                   "\t\t%" PRIu32 " is in %" PRIu32 "'s view, prob: %f\n",
2349                   peer_idx,
2350                   i,
2351                   prob_push);
2352       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2353                   "\t\tposs choices from view: %" PRIu32 ", containing i: %"
2354                   PRIu32 "\n",
2355                   binom (view_size, 0.45 * view_size),
2356                   binom (0.45 * view_size, 1));
2357     }
2358     else
2359     {
2360       prob_push = 0;
2361       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2362                   "\t\t%" PRIu32 " is not in %" PRIu32 "'s view, prob: 0\n",
2363                   peer_idx,
2364                   i);
2365     }
2366     /* 2. Probability of peer i being contained in pulls */
2367     view_size = rps_peers[peer_idx].cur_view_count;
2368     cont_views = count_containing_views (peer_idx, i);
2369     number_of_being_in_pull_events =
2370       (binom (view_size, 0.45 * view_size)
2371        - binom (view_size - cont_views, 0.45 * view_size));
2372     if (0 != number_of_being_in_pull_events)
2373     {
2374       prob_pull = number_of_being_in_pull_events
2375                   /
2376                   (1.0 * binom (view_size, 0.45 * view_size));
2377     }
2378     else
2379     {
2380       prob_pull = 0;
2381     }
2382     probs[i] = prob_push + prob_pull - (prob_push * prob_pull);
2383     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2384                 "\t\t%" PRIu32 " has %" PRIu32 " of %" PRIu32
2385                 " peers in its view who know %" PRIu32 " prob: %f\n",
2386                 peer_idx,
2387                 cont_views,
2388                 view_size,
2389                 i,
2390                 prob_pull);
2391     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2392                 "\t\tnumber of possible pull combinations: %" PRIu32 "\n",
2393                 binom (view_size, 0.45 * view_size));
2394     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2395                 "\t\tnumber of possible pull combinations without %" PRIu32
2396                 ": %" PRIu32 "\n",
2397                 i,
2398                 binom (view_size - cont_views, 0.45 * view_size));
2399     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2400                 "\t\tnumber of possible pull combinations with %" PRIu32
2401                 ": %" PRIu32 "\n",
2402                 i,
2403                 number_of_being_in_pull_events);
2404
2405     probs_hist[i] = 0.9 * rps_peers[peer_idx].eval_probs_cache[i] + probs[i];
2406     rps_peers[peer_idx].eval_probs_cache[i] = probs_hist[i];
2407
2408     sum_non_zero_prob += probs[i];
2409     sum_non_zero_prob_hist += probs_hist[i];
2410   }
2411   /* normalize */
2412   if (0 != sum_non_zero_prob)
2413   {
2414     for (i = 0; i < num_peers; i++)
2415     {
2416       probs[i] = probs[i] * (1.0 / sum_non_zero_prob);
2417     }
2418   }
2419   if (0 != sum_non_zero_prob_hist)
2420   {
2421     for (i = 0; i < num_peers; i++)
2422     {
2423       probs_hist[i] = probs_hist[i] * (1.0 / sum_non_zero_prob_hist);
2424     }
2425   }
2426
2427   /* str repr */
2428   for (i = 0; i < num_peers; i++)
2429   {
2430     probs_as_str_cpy = GNUNET_strndup (probs_as_str, probs_as_str_size);
2431     tmp = GNUNET_snprintf (probs_as_str,
2432                            probs_as_str_size,
2433                            "%s %7.6f", probs_as_str_cpy, probs[i]);
2434     GNUNET_free (probs_as_str_cpy);
2435     GNUNET_assert (0 <= tmp);
2436   }
2437
2438   to_file_w_len (rps_peers[peer_idx].file_name_probs,
2439                  probs_as_str_size,
2440                  probs_as_str);
2441
2442   probs_as_str[0] = '\0';
2443   for (i = 0; i < num_peers; i++)
2444   {
2445     probs_as_str_cpy = GNUNET_strndup (probs_as_str, probs_as_str_size);
2446     tmp = GNUNET_snprintf (probs_as_str,
2447                            probs_as_str_size,
2448                            "%s %7.6f", probs_as_str_cpy, probs_hist[i]);
2449     GNUNET_free (probs_as_str_cpy);
2450     GNUNET_assert (0 <= tmp);
2451   }
2452
2453   to_file_w_len (rps_peers[peer_idx].file_name_probs_hist,
2454                  probs_as_str_size,
2455                  probs_as_str);
2456   GNUNET_free (probs_as_str);
2457 }
2458
2459
2460 /**
2461  * @brief This counts the number of peers in which views a given peer occurs.
2462  *
2463  * It also stores this value in the rps peer.
2464  *
2465  * @param peer_idx the index of the peer to count the representation
2466  *
2467  * @return the number of occurrences
2468  */
2469 static uint32_t
2470 count_peer_in_views_2 (uint32_t peer_idx)
2471 {
2472   uint32_t i, j;
2473   uint32_t count = 0;
2474
2475   for (i = 0; i < num_peers; i++) /* Peer in which view is counted */
2476   {
2477     for (j = 0; j < rps_peers[i].cur_view_count; j++)   /* entry in view */
2478     {
2479       if (0 == memcmp (rps_peers[peer_idx].peer_id,
2480                        &rps_peers[i].cur_view[j],
2481                        sizeof(struct GNUNET_PeerIdentity)))
2482       {
2483         count++;
2484         break;
2485       }
2486     }
2487   }
2488   rps_peers[peer_idx].count_in_views = count;
2489   return count;
2490 }
2491
2492
2493 static uint32_t
2494 cumulated_view_sizes ()
2495 {
2496   uint32_t i;
2497
2498   view_sizes = 0;
2499   for (i = 0; i < num_peers; i++) /* Peer in which view is counted */
2500   {
2501     view_sizes += rps_peers[i].cur_view_count;
2502   }
2503   return view_sizes;
2504 }
2505
2506
2507 static void
2508 count_peer_in_views (uint32_t *count_peers)
2509 {
2510   uint32_t i, j;
2511
2512   for (i = 0; i < num_peers; i++) /* Peer in which view is counted */
2513   {
2514     for (j = 0; j < rps_peers[i].cur_view_count; j++)   /* entry in view */
2515     {
2516       if (0 == memcmp (rps_peers[i].peer_id,
2517                        &rps_peers[i].cur_view[j],
2518                        sizeof(struct GNUNET_PeerIdentity)))
2519       {
2520         count_peers[i]++;
2521       }
2522     }
2523   }
2524 }
2525
2526
2527 void
2528 compute_diversity ()
2529 {
2530   uint32_t i;
2531   /* ith entry represents the numer of occurrences in other peer's views */
2532   uint32_t *count_peers = GNUNET_new_array (num_peers, uint32_t);
2533   uint32_t views_total_size;
2534   double expected;
2535   /* deviation from expected number of peers */
2536   double *deviation = GNUNET_new_array (num_peers, double);
2537
2538   views_total_size = 0;
2539   expected = 0;
2540
2541   /* For each peer count its representation in other peer's views*/
2542   for (i = 0; i < num_peers; i++) /* Peer to count */
2543   {
2544     views_total_size += rps_peers[i].cur_view_count;
2545     count_peer_in_views (count_peers);
2546     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2547                 "Counted representation of %" PRIu32 "th peer [%s]: %" PRIu32
2548                 "\n",
2549                 i,
2550                 GNUNET_i2s (rps_peers[i].peer_id),
2551                 count_peers[i]);
2552   }
2553
2554   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2555               "size of all views combined: %" PRIu32 "\n",
2556               views_total_size);
2557   expected = ((double) 1 / num_peers) * views_total_size;
2558   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2559               "Expected number of occurrences of each peer in all views: %f\n",
2560               expected);
2561   for (i = 0; i < num_peers; i++) /* Peer to count */
2562   {
2563     deviation[i] = expected - count_peers[i];
2564     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2565                 "Deviation from expectation: %f\n", deviation[i]);
2566   }
2567   GNUNET_free (count_peers);
2568   GNUNET_free (deviation);
2569 }
2570
2571
2572 void
2573 print_view_sizes ()
2574 {
2575   uint32_t i;
2576
2577   for (i = 0; i < num_peers; i++) /* Peer to count */
2578   {
2579     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2580                 "View size of %" PRIu32 ". [%s] is %" PRIu32 "\n",
2581                 i,
2582                 GNUNET_i2s (rps_peers[i].peer_id),
2583                 rps_peers[i].cur_view_count);
2584   }
2585 }
2586
2587
2588 void
2589 all_views_updated_cb ()
2590 {
2591   compute_diversity ();
2592   print_view_sizes ();
2593 }
2594
2595
2596 void
2597 view_update_cb (void *cls,
2598                 uint64_t view_size,
2599                 const struct GNUNET_PeerIdentity *peers)
2600 {
2601   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2602               "View was updated (%" PRIu64 ")\n", view_size);
2603   struct RPSPeer *rps_peer = (struct RPSPeer *) cls;
2604   to_file ("/tmp/rps/view_sizes.txt",
2605            "%" PRIu64 " %" PRIu32 "",
2606            rps_peer->index,
2607            view_size);
2608   for (uint64_t i = 0; i < view_size; i++)
2609   {
2610     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2611                 "\t%s\n", GNUNET_i2s (&peers[i]));
2612   }
2613   GNUNET_array_grow (rps_peer->cur_view,
2614                      rps_peer->cur_view_count,
2615                      view_size);
2616   // *rps_peer->cur_view = *peers;
2617   GNUNET_memcpy (rps_peer->cur_view,
2618                  peers,
2619                  view_size * sizeof(struct GNUNET_PeerIdentity));
2620   to_file ("/tmp/rps/count_in_views.txt",
2621            "%" PRIu64 " %" PRIu32 "",
2622            rps_peer->index,
2623            count_peer_in_views_2 (rps_peer->index));
2624   cumulated_view_sizes ();
2625   if (0 != view_size)
2626   {
2627     to_file ("/tmp/rps/repr.txt",
2628              "%" PRIu64  /* index */
2629              " %" PRIu32  /* occurrence in views */
2630              " %" PRIu32  /* view sizes */
2631              " %f"  /* fraction of repr in views */
2632              " %f"  /* average view size */
2633              " %f"  /* prob of occurrence in view slot */
2634              " %f" "",  /* exp frac of repr in views */
2635              rps_peer->index,
2636              count_peer_in_views_2 (rps_peer->index),
2637              view_sizes,
2638              count_peer_in_views_2 (rps_peer->index) / (view_size * 1.0), /* fraction of representation in views */
2639              view_sizes / (view_size * 1.0),  /* average view size */
2640              1.0 / view_size,  /* prob of occurrence in view slot */
2641              (1.0 / view_size) * (view_sizes / view_size)  /* expected fraction of repr in views */
2642              );
2643   }
2644   compute_probabilities (rps_peer->index);
2645   all_views_updated_cb ();
2646 }
2647
2648
2649 static void
2650 pre_profiler (struct RPSPeer *rps_peer, struct GNUNET_RPS_Handle *h)
2651 {
2652   rps_peer->file_name_probs =
2653     store_prefix_file_name (rps_peer->index, "probs");
2654   rps_peer->file_name_probs_hist =
2655     store_prefix_file_name (rps_peer->index, "probs_hist");
2656   GNUNET_RPS_view_request (h, 0, view_update_cb, rps_peer);
2657 }
2658
2659
2660 void
2661 write_final_stats (void)
2662 {
2663   uint64_t sums[STAT_TYPE_MAX] = { 0 };
2664
2665   for (uint32_t i = 0; i < num_peers; i++)
2666   {
2667     to_file ("/tmp/rps/final_stats.csv",
2668              "%" PRIu32 ", "  /* index */
2669              "%s, %"  /* id */
2670              PRIu64 ", %"  /* rounds */
2671              PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %"
2672              PRIu64 ", %"                                                                   /* blocking */
2673              PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %"  /* issued */
2674              PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %"  /* sent */
2675              PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %"
2676              PRIu64 ", %"                                                                   /* recv */
2677              PRIu64 ", %"  /* view size */
2678              PRIu64 ", %"  /* known peers */
2679              PRIu64 ", %"  /* valid peers */
2680              PRIu64 ", %"  /* learned peers */
2681              PRIu64 ", %"  /* pending online checks */
2682              PRIu64 ", %"  /* unrequested pull replies */
2683              PRIu64 ", %"  /* peers in push map */
2684              PRIu64 ", %"  /* peers in pull map */
2685              PRIu64 ", %"  /* peers in view */
2686              PRIu64 "\n" /* view size aim */,
2687              i,
2688              GNUNET_i2s (rps_peers[i].peer_id),
2689              rps_peers[i].stats[STAT_TYPE_ROUNDS],
2690              rps_peers[i].stats[STAT_TYPE_BLOCKS],
2691              rps_peers[i].stats[STAT_TYPE_BLOCKS_MANY_PUSH],
2692              rps_peers[i].stats[STAT_TYPE_BLOCKS_NO_PUSH],
2693              rps_peers[i].stats[STAT_TYPE_BLOCKS_NO_PULL],
2694              rps_peers[i].stats[STAT_TYPE_BLOCKS_MANY_PUSH_NO_PULL],
2695              rps_peers[i].stats[STAT_TYPE_BLOCKS_NO_PUSH_NO_PULL],
2696              rps_peers[i].stats[STAT_TYPE_ISSUED_PUSH_SEND],
2697              rps_peers[i].stats[STAT_TYPE_ISSUED_PUSH_SEND_MH],
2698              rps_peers[i].stats[STAT_TYPE_ISSUED_PULL_REQ],
2699              rps_peers[i].stats[STAT_TYPE_ISSUED_PULL_REQ_MH],
2700              rps_peers[i].stats[STAT_TYPE_ISSUED_PULL_REP],
2701              rps_peers[i].stats[STAT_TYPE_SENT_PUSH_SEND],
2702              rps_peers[i].stats[STAT_TYPE_SENT_PULL_REQ],
2703              rps_peers[i].stats[STAT_TYPE_SENT_PULL_REQ_MH],
2704              rps_peers[i].stats[STAT_TYPE_SENT_PULL_REP],
2705              rps_peers[i].stats[STAT_TYPE_RECV_PUSH_SEND],
2706              rps_peers[i].stats[STAT_TYPE_RECV_PUSH_SEND_MH],
2707              rps_peers[i].stats[STAT_TYPE_RECV_PULL_REQ],
2708              rps_peers[i].stats[STAT_TYPE_RECV_PULL_REQ_MH],
2709              rps_peers[i].stats[STAT_TYPE_RECV_PULL_REP_MH],
2710              rps_peers[i].stats[STAT_TYPE_RECV_PULL_REP],
2711              rps_peers[i].stats[STAT_TYPE_VIEW_SIZE],
2712              rps_peers[i].stats[STAT_TYPE_KNOWN_PEERS],
2713              rps_peers[i].stats[STAT_TYPE_VALID_PEERS],
2714              rps_peers[i].stats[STAT_TYPE_LEARND_PEERS],
2715              rps_peers[i].stats[STAT_TYPE_PENDING_ONLINE_CHECKS],
2716              rps_peers[i].stats[STAT_TYPE_UNREQUESTED_PULL_REPLIES],
2717              rps_peers[i].stats[STAT_TYPE_PEERS_IN_PUSH_MAP],
2718              rps_peers[i].stats[STAT_TYPE_PEERS_IN_PULL_MAP],
2719              rps_peers[i].stats[STAT_TYPE_PEERS_IN_VIEW],
2720              rps_peers[i].stats[STAT_TYPE_VIEW_SIZE_AIM]);
2721     for (enum STAT_TYPE stat_type = STAT_TYPE_ROUNDS;
2722          stat_type < STAT_TYPE_MAX;
2723          stat_type++)
2724     {
2725       sums[stat_type] += rps_peers[i].stats[stat_type];
2726     }
2727   }
2728   to_file ("/tmp/rps/final_stats.dat",
2729            "SUM %"
2730            PRIu64 " %" /* rounds */
2731            PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64
2732            " %"                                                                    /* blocking */
2733            PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" /* issued */
2734            PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" /* sent */
2735            PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %"
2736            PRIu64 ", %"                                                                  /* recv */
2737            PRIu64 ", %" /* view size */
2738            PRIu64 ", %" /* known peers */
2739            PRIu64 ", %" /* valid peers */
2740            PRIu64 ", %" /* learned peers */
2741            PRIu64 ", %" /* pending online checks */
2742            PRIu64 ", %" /* unrequested pull replies */
2743            PRIu64 ", %" /* peers in push map */
2744            PRIu64 ", %" /* peers in pull map */
2745            PRIu64 ", %" /* peers in view */
2746            PRIu64 "\n" /* view size aim */,
2747            sums[STAT_TYPE_ROUNDS],
2748            sums[STAT_TYPE_BLOCKS],
2749            sums[STAT_TYPE_BLOCKS_MANY_PUSH],
2750            sums[STAT_TYPE_BLOCKS_NO_PUSH],
2751            sums[STAT_TYPE_BLOCKS_NO_PULL],
2752            sums[STAT_TYPE_BLOCKS_MANY_PUSH_NO_PULL],
2753            sums[STAT_TYPE_BLOCKS_NO_PUSH_NO_PULL],
2754            sums[STAT_TYPE_ISSUED_PUSH_SEND],
2755            sums[STAT_TYPE_ISSUED_PUSH_SEND_MH],
2756            sums[STAT_TYPE_ISSUED_PULL_REQ],
2757            sums[STAT_TYPE_ISSUED_PULL_REQ_MH],
2758            sums[STAT_TYPE_ISSUED_PULL_REP],
2759            sums[STAT_TYPE_SENT_PUSH_SEND],
2760            sums[STAT_TYPE_SENT_PULL_REQ],
2761            sums[STAT_TYPE_SENT_PULL_REQ_MH],
2762            sums[STAT_TYPE_SENT_PULL_REP],
2763            sums[STAT_TYPE_RECV_PUSH_SEND],
2764            sums[STAT_TYPE_RECV_PUSH_SEND_MH],
2765            sums[STAT_TYPE_RECV_PULL_REQ],
2766            sums[STAT_TYPE_RECV_PULL_REQ_MH],
2767            sums[STAT_TYPE_RECV_PULL_REP],
2768            sums[STAT_TYPE_RECV_PULL_REP_MH],
2769            sums[STAT_TYPE_VIEW_SIZE],
2770            sums[STAT_TYPE_KNOWN_PEERS],
2771            sums[STAT_TYPE_VALID_PEERS],
2772            sums[STAT_TYPE_LEARND_PEERS],
2773            sums[STAT_TYPE_PENDING_ONLINE_CHECKS],
2774            sums[STAT_TYPE_UNREQUESTED_PULL_REPLIES],
2775            sums[STAT_TYPE_PEERS_IN_PUSH_MAP],
2776            sums[STAT_TYPE_PEERS_IN_PULL_MAP],
2777            sums[STAT_TYPE_PEERS_IN_VIEW],
2778            sums[STAT_TYPE_VIEW_SIZE_AIM]);
2779 }
2780
2781
2782 /**
2783  * Continuation called by #GNUNET_STATISTICS_get() functions.
2784  *
2785  * Remembers that this specific statistics value was received for this peer.
2786  * Checks whether all peers received their statistics yet.
2787  * Issues the shutdown.
2788  *
2789  * @param cls closure
2790  * @param success #GNUNET_OK if statistics were
2791  *        successfully obtained, #GNUNET_SYSERR if not.
2792  */
2793 void
2794 post_test_shutdown_ready_cb (void *cls,
2795                              int success)
2796 {
2797   struct STATcls *stat_cls = (struct STATcls *) cls;
2798   struct RPSPeer *rps_peer = stat_cls->rps_peer;
2799
2800   rps_peer->h_stat_get[stat_cls->stat_type] = NULL;
2801   if (GNUNET_OK == success)
2802   {
2803     /* set flag that we we got the value */
2804     rps_peer->stat_collected_flags |= BIT (stat_cls->stat_type);
2805   }
2806   else
2807   {
2808     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2809                 "Peer %u did not receive statistics value\n",
2810                 rps_peer->index);
2811     GNUNET_free (stat_cls);
2812     GNUNET_break (0);
2813     return;
2814   }
2815
2816   if ((NULL != rps_peer->stat_op) &&
2817       (GNUNET_YES == check_statistics_collect_completed_single_peer (
2818          rps_peer)) )
2819   {
2820     GNUNET_TESTBED_operation_done (rps_peer->stat_op);
2821   }
2822
2823   write_final_stats ();
2824   if (GNUNET_YES == check_statistics_collect_completed ())
2825   {
2826     // write_final_stats ();
2827     GNUNET_free (stat_cls);
2828     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2829                 "Shutting down\n");
2830     GNUNET_SCHEDULER_shutdown ();
2831   }
2832   else
2833   {
2834     GNUNET_free (stat_cls);
2835   }
2836 }
2837
2838
2839 /**
2840  * Callback function to process statistic values.
2841  *
2842  * @param cls closure
2843  * @param subsystem name of subsystem that created the statistic
2844  * @param name the name of the datum
2845  * @param value the current value
2846  * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
2847  * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
2848  */
2849 int
2850 stat_iterator (void *cls,
2851                const char *subsystem,
2852                const char *name,
2853                uint64_t value,
2854                int is_persistent)
2855 {
2856   const struct STATcls *stat_cls = (const struct STATcls *) cls;
2857   struct RPSPeer *rps_peer = (struct RPSPeer *) stat_cls->rps_peer;
2858   enum STAT_TYPE stat_type;
2859
2860   (void) subsystem;
2861   (void) is_persistent;
2862
2863   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2864               "Got stat value: %s - %" PRIu64 " (%u)\n",
2865               name,
2866               value,
2867               rps_peer->index);
2868   to_file (rps_peer->file_name_stats,
2869            "%s: %" PRIu64 "\n",
2870            name,
2871            value);
2872   stat_type = stat_str_2_type (name);
2873   GNUNET_assert (STAT_TYPE_ROUNDS <= stat_type &&
2874                  STAT_TYPE_MAX > stat_type);
2875   rps_peer->stats[stat_type] = value;
2876   return GNUNET_OK;
2877 }
2878
2879
2880 void
2881 post_profiler (struct RPSPeer *rps_peer)
2882 {
2883   if (COLLECT_STATISTICS != cur_test_run.have_collect_statistics)
2884   {
2885     return;
2886   }
2887
2888   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2889               "Going to request statistic values with mask 0x%" PRIx32 "\n",
2890               cur_test_run.stat_collect_flags);
2891
2892   struct STATcls *stat_cls;
2893   uint32_t stat_type;
2894   for (stat_type = STAT_TYPE_ROUNDS;
2895        stat_type < STAT_TYPE_MAX;
2896        stat_type++)
2897   {
2898     if (BIT (stat_type) & cur_test_run.stat_collect_flags)
2899     {
2900       stat_cls = GNUNET_malloc (sizeof(struct STATcls));
2901       stat_cls->rps_peer = rps_peer;
2902       stat_cls->stat_type = stat_type;
2903       rps_peer->file_name_stats =
2904         store_prefix_file_name (rps_peer->peer_id, "stats");
2905       rps_peer->h_stat_get[stat_type] =
2906         GNUNET_STATISTICS_get (rps_peer->stats_h,
2907                                "rps",
2908                                stat_type_strings [stat_type],
2909                                post_test_shutdown_ready_cb,
2910                                stat_iterator,
2911                                (struct STATcls *) stat_cls);
2912       GNUNET_assert (NULL != rps_peer->h_stat_get);
2913       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2914                   "Requested statistics for %s (peer %" PRIu32 ")\n",
2915                   stat_type_strings [stat_type],
2916                   rps_peer->index);
2917     }
2918   }
2919   GNUNET_free (rps_peer->eval_probs_cache);
2920 }
2921
2922
2923 /***********************************************************************
2924 * /Definition of tests
2925 ***********************************************************************/
2926
2927
2928 /**
2929  * Actual "main" function for the testcase.
2930  *
2931  * @param cls closure
2932  * @param h the run handle
2933  * @param n_peers number of peers in 'peers'
2934  * @param peers handle to peers run in the testbed
2935  * @param links_succeeded the number of overlay link connection attempts that
2936  *          succeeded
2937  * @param links_failed the number of overlay link connection attempts that
2938  *          failed
2939  */
2940 static void
2941 test_run (void *cls,
2942           struct GNUNET_TESTBED_RunHandle *h,
2943           unsigned int n_peers,
2944           struct GNUNET_TESTBED_Peer **peers,
2945           unsigned int links_succeeded,
2946           unsigned int links_failed)
2947 {
2948   unsigned int i;
2949   struct OpListEntry *entry;
2950
2951   (void) cls;
2952   (void) h;
2953   (void) links_failed;
2954
2955   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "RUN was called\n");
2956
2957   /* Check whether we timed out */
2958   if ((n_peers != num_peers) ||
2959       (NULL == peers) ||
2960       (0 == links_succeeded) )
2961   {
2962     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2963                 "Going down due to args (eg. timeout)\n");
2964     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\tn_peers: %u\n", n_peers);
2965     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\tnum_peers: %" PRIu32 "\n",
2966                 num_peers);
2967     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\tpeers: %p\n", peers);
2968     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\tlinks_succeeded: %u\n",
2969                 links_succeeded);
2970     ok = 1;
2971     GNUNET_SCHEDULER_shutdown ();
2972     return;
2973   }
2974
2975
2976   /* Initialize peers */
2977   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "going to initialise peers\n");
2978   testbed_peers = peers;
2979   num_peers_online = 0;
2980   for (i = 0; i < num_peers; i++)
2981   {
2982     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "initialising %u\n", i);
2983     entry = make_oplist_entry ();
2984     entry->index = i;
2985     rps_peers[i].index = i;
2986     if (NULL != cur_test_run.init_peer)
2987       cur_test_run.init_peer (&rps_peers[i]);
2988     if (NO_COLLECT_VIEW == cur_test_run.have_collect_view)
2989     {
2990       rps_peers->cur_view_count = 0;
2991       rps_peers->cur_view = NULL;
2992     }
2993     entry->op = GNUNET_TESTBED_peer_get_information (peers[i],
2994                                                      GNUNET_TESTBED_PIT_IDENTITY,
2995                                                      &info_cb,
2996                                                      entry);
2997   }
2998
2999   /* Bring peers up */
3000   GNUNET_assert (num_peers == n_peers);
3001   for (i = 0; i < n_peers; i++)
3002   {
3003     rps_peers[i].index = i;
3004     rps_peers[i].op =
3005       GNUNET_TESTBED_service_connect (&rps_peers[i],
3006                                       peers[i],
3007                                       "rps",
3008                                       &rps_connect_complete_cb,
3009                                       &rps_peers[i],
3010                                       &rps_connect_adapter,
3011                                       &rps_disconnect_adapter,
3012                                       &rps_peers[i]);
3013     /* Connect all peers to statistics service */
3014     if (COLLECT_STATISTICS == cur_test_run.have_collect_statistics)
3015     {
3016       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3017                   "Connecting to statistics service\n");
3018       rps_peers[i].stat_op =
3019         GNUNET_TESTBED_service_connect (NULL,
3020                                         peers[i],
3021                                         "statistics",
3022                                         stat_complete_cb,
3023                                         &rps_peers[i],
3024                                         &stat_connect_adapter,
3025                                         &stat_disconnect_adapter,
3026                                         &rps_peers[i]);
3027     }
3028   }
3029
3030   if (NULL != churn_task)
3031     GNUNET_SCHEDULER_cancel (churn_task);
3032   post_test_task = GNUNET_SCHEDULER_add_delayed (duration, &post_test_op, NULL);
3033   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "timeout for shutdown is %lu\n",
3034               timeout.rel_value_us / 1000000);
3035   shutdown_task = GNUNET_SCHEDULER_add_delayed (timeout,
3036                                                 &trigger_shutdown,
3037                                                 NULL);
3038   GNUNET_SCHEDULER_add_shutdown (shutdown_op, NULL);
3039 }
3040
3041
3042 /**
3043  * Entry point for the testcase, sets up the testbed.
3044  *
3045  * @param argc unused
3046  * @param argv unused
3047  */
3048 static void
3049 run (void *cls,
3050      char *const *args,
3051      const char *cfgfile,
3052      const struct GNUNET_CONFIGURATION_Handle *cfg)
3053 {
3054   // int ret_value;
3055   (void) cls;
3056   (void) args;
3057   (void) cfgfile;
3058
3059   /* Defaults for tests */
3060   churn_task = NULL;
3061
3062   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "This is the profiler\n");
3063   cur_test_run.name = "test-rps-profiler";
3064   if (0 == num_peers)
3065     num_peers = 10;
3066   mal_type = 3;
3067   cur_test_run.init_peer = profiler_init_peer;
3068   // cur_test_run.pre_test = mal_pre;
3069   cur_test_run.pre_test = pre_profiler;
3070   cur_test_run.main_test = profiler_cb;
3071   cur_test_run.reply_handle = profiler_reply_handle;
3072   cur_test_run.eval_cb = profiler_eval;
3073   cur_test_run.post_test = post_profiler;
3074   cur_test_run.request_interval = 2;
3075   if (0 == cur_test_run.num_requests)
3076     cur_test_run.num_requests = 5;
3077   // cur_test_run.have_churn = HAVE_CHURN;
3078   cur_test_run.have_churn = HAVE_NO_CHURN;
3079   cur_test_run.have_quick_quit = HAVE_QUICK_QUIT;
3080   cur_test_run.have_collect_statistics = COLLECT_STATISTICS;
3081   cur_test_run.stat_collect_flags = BIT (STAT_TYPE_ROUNDS)
3082                                     | BIT (STAT_TYPE_BLOCKS)
3083                                     | BIT (STAT_TYPE_BLOCKS_MANY_PUSH)
3084                                     | BIT (STAT_TYPE_BLOCKS_NO_PUSH)
3085                                     | BIT (STAT_TYPE_BLOCKS_NO_PULL)
3086                                     | BIT (STAT_TYPE_BLOCKS_MANY_PUSH_NO_PULL)
3087                                     | BIT (STAT_TYPE_BLOCKS_NO_PUSH_NO_PULL)
3088                                     | BIT (STAT_TYPE_ISSUED_PUSH_SEND)
3089                                     | BIT (STAT_TYPE_ISSUED_PUSH_SEND_MH)
3090                                     | BIT (STAT_TYPE_ISSUED_PULL_REQ)
3091                                     | BIT (STAT_TYPE_ISSUED_PULL_REQ_MH)
3092                                     | BIT (STAT_TYPE_ISSUED_PULL_REP)
3093                                     | BIT (STAT_TYPE_SENT_PUSH_SEND)
3094                                     | BIT (STAT_TYPE_SENT_PULL_REQ)
3095                                     | BIT (STAT_TYPE_SENT_PULL_REQ_MH)
3096                                     | BIT (STAT_TYPE_SENT_PULL_REP)
3097                                     | BIT (STAT_TYPE_RECV_PUSH_SEND)
3098                                     | BIT (STAT_TYPE_RECV_PUSH_SEND_MH)
3099                                     | BIT (STAT_TYPE_RECV_PULL_REQ)
3100                                     | BIT (STAT_TYPE_RECV_PULL_REQ_MH)
3101                                     | BIT (STAT_TYPE_RECV_PULL_REP)
3102                                     | BIT (STAT_TYPE_RECV_PULL_REP_MH)
3103                                     | BIT (STAT_TYPE_VIEW_SIZE)
3104                                     | BIT (STAT_TYPE_KNOWN_PEERS)
3105                                     | BIT (STAT_TYPE_VALID_PEERS)
3106                                     | BIT (STAT_TYPE_LEARND_PEERS)
3107                                     | BIT (STAT_TYPE_PENDING_ONLINE_CHECKS)
3108                                     | BIT (STAT_TYPE_UNREQUESTED_PULL_REPLIES)
3109                                     | BIT (STAT_TYPE_PEERS_IN_PUSH_MAP)
3110                                     | BIT (STAT_TYPE_PEERS_IN_PULL_MAP)
3111                                     | BIT (STAT_TYPE_PEERS_IN_VIEW)
3112                                     | BIT (STAT_TYPE_VIEW_SIZE_AIM);
3113   cur_test_run.have_collect_view = COLLECT_VIEW;
3114
3115   /* 'Clean' directory */
3116   (void) GNUNET_DISK_directory_remove ("/tmp/rps/");
3117   GNUNET_DISK_directory_create ("/tmp/rps/");
3118   if (0 == duration.rel_value_us)
3119   {
3120     if (0 == timeout.rel_value_us)
3121     {
3122       duration = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 90);
3123       timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
3124                                                (90 * 1.2)
3125                                                + (0.01 * num_peers));
3126     }
3127     else
3128     {
3129       duration = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
3130                                                 (timeout.rel_value_us / 1000000)
3131                                                 * 0.75);
3132     }
3133   }
3134   else
3135   {
3136     if (0 == timeout.rel_value_us)
3137     {
3138       timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
3139                                                ((duration.rel_value_us
3140                                                  / 1000000)
3141                                                 * 1.2) + (0.01 * num_peers));
3142     }
3143   }
3144   GNUNET_assert (duration.rel_value_us < timeout.rel_value_us);
3145   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3146               "duration is %lus\n",
3147               duration.rel_value_us / 1000000);
3148   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3149               "timeout is %lus\n",
3150               timeout.rel_value_us / 1000000);
3151
3152   /* Compute number of bits for representing largest peer id */
3153   for (bits_needed = 1; (1 << bits_needed) < num_peers; bits_needed++)
3154     ;
3155   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3156               "Need %u bits to represent %" PRIu32 " peers\n",
3157               bits_needed,
3158               num_peers);
3159
3160   rps_peers = GNUNET_new_array (num_peers, struct RPSPeer);
3161   peer_map = GNUNET_CONTAINER_multipeermap_create (num_peers, GNUNET_NO);
3162   rps_peer_ids = GNUNET_new_array (num_peers, struct GNUNET_PeerIdentity);
3163   if ((2 == mal_type) ||
3164       (3 == mal_type))
3165     target_peer = &rps_peer_ids[num_peers - 2];
3166
3167   ok = 1;
3168   GNUNET_TESTBED_run (NULL,
3169                       cfg,
3170                       num_peers,
3171                       0, /* event mask */
3172                       NULL,
3173                       NULL,
3174                       &test_run,
3175                       NULL);
3176 }
3177
3178
3179 /**
3180  * Entry point for the testcase, sets up the testbed.
3181  *
3182  * @param argc unused
3183  * @param argv unused
3184  * @return 0 on success
3185  */
3186 int
3187 main (int argc, char *argv[])
3188 {
3189   int ret_value;
3190   struct GNUNET_GETOPT_CommandLineOption options[] = {
3191     GNUNET_GETOPT_option_uint ('n',
3192                                "num-peers",
3193                                "COUNT",
3194                                gettext_noop ("number of peers to start"),
3195                                &num_peers),
3196     GNUNET_GETOPT_option_relative_time ('d',
3197                                         "duration",
3198                                         "DURATION",
3199                                         gettext_noop (
3200                                           "duration of the profiling"),
3201                                         &duration),
3202     GNUNET_GETOPT_option_relative_time ('t',
3203                                         "timeout",
3204                                         "TIMEOUT",
3205                                         gettext_noop (
3206                                           "timeout for the profiling"),
3207                                         &timeout),
3208     GNUNET_GETOPT_option_uint ('r',
3209                                "num-requests",
3210                                "COUNT",
3211                                gettext_noop ("number of PeerIDs to request"),
3212                                &cur_test_run.num_requests),
3213     GNUNET_GETOPT_OPTION_END
3214   };
3215
3216   unsetenv ("XDG_DATA_HOME");
3217   unsetenv ("XDG_CONFIG_HOME");
3218   // if (GNUNET_OK !=
3219   //    GNUNET_STRINGS_get_utf8_args (argc, argv,
3220   //                                  &argc, &argv))
3221   //  return 2;
3222   ret_value = 0;
3223   if (GNUNET_OK !=
3224       GNUNET_PROGRAM_run (argc,
3225                           argv,
3226                           "gnunet-rps-profiler",
3227                           gettext_noop (
3228                             "Measure quality and performance of the RPS service."),
3229                           options,
3230                           &run,
3231                           NULL))
3232   {
3233     ret_value = 1;
3234   }
3235   if (0 != ret_value)
3236   {
3237     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3238                 "Test did not run successfully!\n");
3239   }
3240   else
3241   {
3242     ret_value = cur_test_run.eval_cb ();
3243     if (NO_COLLECT_VIEW == cur_test_run.have_collect_view)
3244     {
3245       GNUNET_array_grow (rps_peers->cur_view,
3246                          rps_peers->cur_view_count,
3247                          0);
3248     }
3249     GNUNET_free (rps_peers);
3250     GNUNET_free (rps_peer_ids);
3251     GNUNET_CONTAINER_multipeermap_destroy (peer_map);
3252   }
3253   return ret_value;
3254 }
3255
3256
3257 /* end of test_rps.c */