a430f4a83cd045dce35a8ad33766beee12c01ff1
[oweals/gnunet.git] / src / rps / test_rps.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2012 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20 /**
21  * @file rps/test_rps_multipeer.c
22  * @brief Testcase for the random peer sampling service.  Starts
23  *        a peergroup with a given number of peers, then waits to
24  *        receive size pushes/pulls from each peer.  Expects to wait
25  *        for one message from each peer.
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_testbed_service.h"
30
31 #include "gnunet_rps_service.h"
32 #include "rps-test_util.h"
33 #include "gnunet-service-rps_sampler_elem.h"
34
35 #include <inttypes.h>
36
37
38 /**
39  * How many peers do we start?
40  */
41 uint32_t num_peers;
42
43 /**
44  * How long do we run the test?
45  */
46 //#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
47 static struct GNUNET_TIME_Relative timeout;
48
49
50 /**
51  * Portion of malicious peers
52  */
53 static double portion = .1;
54
55 /**
56  * Type of malicious peer to test
57  */
58 static unsigned int mal_type = 0;
59
60 /**
61  * Handles to all of the running peers
62  */
63 static struct GNUNET_TESTBED_Peer **testbed_peers;
64
65
66 /**
67  * Operation map entry
68  */
69 struct OpListEntry
70 {
71   /**
72    * DLL next ptr
73    */
74   struct OpListEntry *next;
75
76   /**
77    * DLL prev ptr
78    */
79   struct OpListEntry *prev;
80
81   /**
82    * The testbed operation
83    */
84   struct GNUNET_TESTBED_Operation *op;
85
86   /**
87    * Depending on whether we start or stop NSE service at the peer set this to 1
88    * or -1
89    */
90   int delta;
91
92   /**
93    * Index of the regarding peer
94    */
95   unsigned int index;
96 };
97
98 /**
99  * OpList DLL head
100  */
101 static struct OpListEntry *oplist_head;
102
103 /**
104  * OpList DLL tail
105  */
106 static struct OpListEntry *oplist_tail;
107
108
109 /**
110  * Information we track for each peer.
111  */
112 struct RPSPeer
113 {
114   /**
115    * Index of the peer.
116    */
117   unsigned int index;
118
119   /**
120    * Handle for RPS connect operation.
121    */
122   struct GNUNET_TESTBED_Operation *op;
123
124   /**
125    * Handle to RPS service.
126    */
127   struct GNUNET_RPS_Handle *rps_handle;
128
129   /**
130    * ID of the peer.
131    */
132   struct GNUNET_PeerIdentity *peer_id;
133
134   /**
135    * A request handle to check for an request
136    */
137   //struct GNUNET_RPS_Request_Handle *req_handle;
138
139   /**
140    * Peer on- or offline?
141    */
142   int online;
143
144   /**
145    * Received PeerIDs
146    */
147   struct GNUNET_PeerIdentity *rec_ids;
148
149   /**
150    * Number of received PeerIDs
151    */
152   unsigned int num_rec_ids;
153 };
154
155
156 /**
157  * Information for all the peers.
158  */
159 static struct RPSPeer *rps_peers;
160
161 /**
162  * Peermap to get the index of a given peer ID quick.
163  */
164 static struct GNUNET_CONTAINER_MultiPeerMap *peer_map;
165
166 /**
167  * IDs of the peers.
168  */
169 static struct GNUNET_PeerIdentity *rps_peer_ids;
170
171 /**
172  * Number of online peers.
173  */
174 static unsigned int num_peers_online;
175
176 /**
177  * Return value from 'main'.
178  */
179 static int ok;
180
181
182 /**
183  * Identifier for the churn task that runs periodically
184  */
185 static struct GNUNET_SCHEDULER_Task *churn_task;
186
187
188 /**
189  * Called directly after connecting to the service
190  */
191 typedef void (*PreTest) (void *cls, struct GNUNET_RPS_Handle *h);
192
193 /**
194  * Called from within #rps_connect_complete_cb ()
195  * Executes functions to test the api/service
196  */
197 typedef void (*MainTest) (struct RPSPeer *rps_peer);
198
199 /**
200  * Callback called once the requested random peers are available
201  */
202 typedef void (*ReplyHandle) (void *cls,
203                              uint64_t n,
204                              const struct GNUNET_PeerIdentity *recv_peers);
205
206 /**
207  * Called directly before disconnecting from the service
208  */
209 typedef void (*PostTest) (void *cls, struct GNUNET_RPS_Handle *h);
210
211 /**
212  * Function called after disconnect to evaluate test success
213  */
214 typedef int (*EvaluationCallback) (void);
215
216
217 /**
218  * Structure to define a single test
219  */
220 struct SingleTestRun
221 {
222   /**
223    * Name of the test
224    */
225   char *name;
226
227   /**
228    * Called directly after connecting to the service
229    */
230   PreTest pre_test;
231
232   /**
233    * Function to execute the functions to be tested
234    */
235   MainTest main_test;
236
237   /**
238    * Callback called once the requested peers are available
239    */
240   ReplyHandle reply_handle;
241
242   /**
243    * Called directly before disconnecting from the service
244    */
245   PostTest post_test;
246
247   /**
248    * Function to evaluate the test results
249    */
250   EvaluationCallback eval_cb;
251
252   /**
253    * Request interval
254    */
255   uint32_t request_interval;
256
257   /**
258    * Number of Requests to make.
259    */
260   uint32_t num_requests;
261 } cur_test_run;
262
263
264 /**
265  * Append arguments to file
266  */
267 static void
268 tofile_ (const char *file_name, char *line)
269 {
270   struct GNUNET_DISK_FileHandle *f;
271   /* char output_buffer[512]; */
272   size_t size;
273   /* int size; */
274   size_t size2;
275
276   if (NULL == (f = GNUNET_DISK_file_open (file_name,
277                                           GNUNET_DISK_OPEN_APPEND |
278                                           GNUNET_DISK_OPEN_WRITE |
279                                           GNUNET_DISK_OPEN_CREATE,
280                                           GNUNET_DISK_PERM_USER_READ |
281                                           GNUNET_DISK_PERM_USER_WRITE |
282                                           GNUNET_DISK_PERM_GROUP_READ |
283                                           GNUNET_DISK_PERM_OTHER_READ)))
284   {
285     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
286                 "Not able to open file %s\n",
287                 file_name);
288     return;
289   }
290   /* size = GNUNET_snprintf (output_buffer,
291                           sizeof (output_buffer),
292                           "%llu %s\n",
293                           GNUNET_TIME_absolute_get ().abs_value_us,
294                           line);
295   if (0 > size)
296   {
297     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
298                 "Failed to write string to buffer (size: %i)\n",
299                 size);
300     return;
301   } */
302
303   size = strlen (line) * sizeof (char);
304
305   size2 = GNUNET_DISK_file_write (f, line, size);
306   if (size != size2)
307   {
308     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
309                 "Unable to write to file! (Size: %u, size2: %u)\n",
310                 size,
311                 size2);
312     return;
313   }
314
315   if (GNUNET_YES != GNUNET_DISK_file_close (f))
316     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
317                 "Unable to close file\n");
318 }
319
320 /**
321  * This function is used to facilitate writing important information to disk
322  */
323 #define tofile(file_name, ...) do {\
324   char tmp_buf[512];\
325     int size;\
326     size = GNUNET_snprintf(tmp_buf,sizeof(tmp_buf),__VA_ARGS__);\
327     if (0 > size)\
328       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,\
329                      "Failed to create tmp_buf\n");\
330     else\
331       tofile_(file_name,tmp_buf);\
332   } while (0);
333
334
335 /**
336  * Write the ids and their according index in the given array to a file 
337  * Unused
338  */
339 /* static void
340 ids_to_file (char *file_name,
341              struct GNUNET_PeerIdentity *peer_ids,
342              unsigned int num_peer_ids)
343 {
344   unsigned int i;
345
346   for (i=0 ; i < num_peer_ids ; i++)
347   {
348     to_file (file_name,
349              "%u\t%s",
350              i,
351              GNUNET_i2s_full (&peer_ids[i]));
352   }
353 } */
354
355 /**
356  * Test the success of a single test
357  */
358 static int
359 evaluate (struct RPSPeer *loc_rps_peers,
360           unsigned int num_loc_rps_peers,
361           unsigned int expected_recv)
362 {
363   unsigned int i;
364   int tmp_ok;
365
366   tmp_ok = (1 == loc_rps_peers[0].num_rec_ids);
367
368   for (i = 0 ; i < num_loc_rps_peers ; i++)
369   {
370     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
371                 "%u. peer [%s] received %u of %u expected peer_ids: %i\n",
372                 i,
373                 GNUNET_i2s (loc_rps_peers[i].peer_id),
374                 loc_rps_peers[i].num_rec_ids,
375                 expected_recv,
376                 (1 == loc_rps_peers[i].num_rec_ids));
377     tmp_ok &= (1 == loc_rps_peers[i].num_rec_ids);
378   }
379   return tmp_ok? 0 : 1;
380 }
381
382
383 /**
384  * Creates an oplist entry and adds it to the oplist DLL
385  */
386 static struct OpListEntry *
387 make_oplist_entry ()
388 {
389   struct OpListEntry *entry;
390
391   entry = GNUNET_new (struct OpListEntry);
392   GNUNET_CONTAINER_DLL_insert_tail (oplist_head, oplist_tail, entry);
393   return entry;
394 }
395
396
397 /**
398  * Callback to be called when RPS service is started or stopped at peers
399  *
400  * @param cls NULL
401  * @param op the operation handle
402  * @param emsg NULL on success; otherwise an error description
403  */
404 static void
405 churn_cb (void *cls,
406           struct GNUNET_TESTBED_Operation *op,
407           const char *emsg)
408 {
409   // FIXME
410   struct OpListEntry *entry = cls;
411
412   GNUNET_TESTBED_operation_done (entry->op);
413   if (NULL != emsg)
414   {
415     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start/stop RPS at a peer\n");
416     GNUNET_SCHEDULER_shutdown ();
417     return;
418   }
419   GNUNET_assert (0 != entry->delta);
420
421   num_peers_online += entry->delta;
422
423   if (0 > entry->delta)
424   { /* Peer hopefully just went offline */
425     if (GNUNET_YES != rps_peers[entry->index].online)
426     {
427       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
428                   "peer %s was expected to go offline but is still marked as online\n",
429                   GNUNET_i2s (rps_peers[entry->index].peer_id));
430       GNUNET_break (0);
431     }
432     else
433     {
434       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
435                   "peer %s probably went offline as expected\n",
436                   GNUNET_i2s (rps_peers[entry->index].peer_id));
437     }
438     rps_peers[entry->index].online = GNUNET_NO;
439   }
440
441   else if (0 < entry->delta)
442   { /* Peer hopefully just went online */
443     if (GNUNET_NO != rps_peers[entry->index].online)
444     {
445       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
446                   "peer %s was expected to go online but is still marked as offline\n",
447                   GNUNET_i2s (rps_peers[entry->index].peer_id));
448       GNUNET_break (0);
449     }
450     else
451     {
452       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
453                   "peer %s probably went online as expected\n",
454                   GNUNET_i2s (rps_peers[entry->index].peer_id));
455       if (NULL != cur_test_run.pre_test)
456       {
457         cur_test_run.pre_test (&rps_peers[entry->index],
458             rps_peers[entry->index].rps_handle);
459       }
460     }
461     rps_peers[entry->index].online = GNUNET_YES;
462   }
463
464   GNUNET_CONTAINER_DLL_remove (oplist_head, oplist_tail, entry);
465   GNUNET_free (entry);
466   //if (num_peers_in_round[current_round] == peers_running)
467   //  run_round ();
468 }
469
470
471 /**
472  * Task run on timeout to shut everything down.
473  */
474 static void
475 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
476 {
477   unsigned int i;
478
479   if (NULL != churn_task)
480     GNUNET_SCHEDULER_cancel (churn_task);
481
482   for (i = 0 ; i < num_peers ; i++)
483     GNUNET_TESTBED_operation_done (rps_peers[i].op);
484   GNUNET_SCHEDULER_shutdown ();
485 }
486
487
488 /**
489  * Seed peers.
490  */
491   void
492 seed_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
493 {
494   unsigned int amount;
495   struct RPSPeer *peer = (struct RPSPeer *) cls;
496   unsigned int i;
497
498   // TODO if malicious don't seed mal peers
499   amount = round (.5 * num_peers);
500
501   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Seeding peers:\n");
502   for (i = 0 ; i < amount ; i++)
503     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Seeding %u. peer: %s\n",
504                 i,
505                 GNUNET_i2s (&rps_peer_ids[i]));
506
507   GNUNET_RPS_seed_ids (peer->rps_handle, amount, rps_peer_ids);
508 }
509
510
511 /**
512  * Get the id of peer i.
513  */
514   void
515 info_cb (void *cb_cls,
516          struct GNUNET_TESTBED_Operation *op,
517          const struct GNUNET_TESTBED_PeerInformation *pinfo,
518          const char *emsg)
519 {
520   struct OpListEntry *entry = (struct OpListEntry *) cb_cls;
521
522   if (NULL == pinfo || NULL != emsg)
523   {
524     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Got Error: %s\n", emsg);
525     return;
526   }
527
528   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
529               "Peer %u is %s\n",
530               entry->index,
531               GNUNET_i2s (pinfo->result.id));
532
533   rps_peer_ids[entry->index] = *(pinfo->result.id);
534   rps_peers[entry->index].peer_id = &rps_peer_ids[entry->index];
535   rps_peers[entry->index].rec_ids = NULL;
536   rps_peers[entry->index].num_rec_ids = 0;
537
538   GNUNET_CONTAINER_multipeermap_put (peer_map,
539       &rps_peer_ids[entry->index],
540       &rps_peers[entry->index],
541       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
542
543   tofile ("/tmp/rps/peer_ids",
544            "%u\t%s\n",
545            entry->index,
546            GNUNET_i2s_full (&rps_peer_ids[entry->index]));
547
548   GNUNET_TESTBED_operation_done (entry->op);
549
550   GNUNET_CONTAINER_DLL_remove (oplist_head, oplist_tail, entry);
551   GNUNET_free (entry);
552 }
553
554
555 /**
556  * Callback to be called when RPS service connect operation is completed
557  *
558  * @param cls the callback closure from functions generating an operation
559  * @param op the operation that has been finished
560  * @param ca_result the RPS service handle returned from rps_connect_adapter
561  * @param emsg error message in case the operation has failed; will be NULL if
562  *          operation has executed successfully.
563  */
564 static void
565 rps_connect_complete_cb (void *cls,
566                          struct GNUNET_TESTBED_Operation *op,
567                          void *ca_result,
568                          const char *emsg)
569 {
570   struct RPSPeer *rps_peer = cls;
571   struct GNUNET_RPS_Handle *rps = ca_result;
572
573   rps_peer->rps_handle = rps;
574   rps_peer->online = GNUNET_YES;
575   num_peers_online++;
576
577   GNUNET_assert (op == rps_peer->op);
578   if (NULL != emsg)
579   {
580     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
581                 "Failed to connect to RPS service: %s\n",
582                 emsg);
583     ok = 1;
584     GNUNET_SCHEDULER_shutdown ();
585     return;
586   }
587
588   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started client successfully\n");
589
590   cur_test_run.main_test (rps_peer);
591 }
592
593
594 /**
595  * Adapter function called to establish a connection to
596  * the RPS service.
597  *
598  * @param cls closure
599  * @param cfg configuration of the peer to connect to; will be available until
600  *          GNUNET_TESTBED_operation_done() is called on the operation returned
601  *          from GNUNET_TESTBED_service_connect()
602  * @return service handle to return in 'op_result', NULL on error
603  */
604 static void *
605 rps_connect_adapter (void *cls,
606                                  const struct GNUNET_CONFIGURATION_Handle *cfg)
607 {
608   struct GNUNET_RPS_Handle *h;
609
610   h = GNUNET_RPS_connect (cfg);
611
612   if (NULL != cur_test_run.pre_test)
613     cur_test_run.pre_test (cls, h);
614
615   return h;
616 }
617
618
619 /**
620  * Adapter function called to destroy connection to
621  * RPS service.
622  *
623  * @param cls closure
624  * @param op_result service handle returned from the connect adapter
625  */
626 static void
627 rps_disconnect_adapter (void *cls,
628                                           void *op_result)
629 {
630   struct GNUNET_RPS_Handle *h = op_result;
631   GNUNET_RPS_disconnect (h);
632 }
633
634
635 /***********************************************************************
636  * Definition of tests
637 ***********************************************************************/
638
639 // TODO check whether tests can be stopped earlier
640 static int
641 default_eval_cb (void)
642 {
643   return evaluate (rps_peers, num_peers, 1);
644 }
645
646 static int
647 no_eval (void)
648 {
649   return 1;
650 }
651
652 /**
653  * Callback to call on receipt of a reply
654  *
655  * @param cls closure
656  * @param n number of peers
657  * @param recv_peers the received peers
658  */
659 static void
660 default_reply_handle (void *cls,
661                       uint64_t n,
662                       const struct GNUNET_PeerIdentity *recv_peers)
663 {
664   struct RPSPeer *rps_peer = (struct RPSPeer *) cls;
665   unsigned int i;
666
667   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
668               "[%s] got %" PRIu64 " peers:\n",
669               GNUNET_i2s (rps_peer->peer_id),
670               n);
671   
672   for (i = 0 ; i < n ; i++)
673   {
674     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
675                 "%u: %s\n",
676                 i,
677                 GNUNET_i2s (&recv_peers[i]));
678
679     GNUNET_array_append (rps_peer->rec_ids, rps_peer->num_rec_ids, recv_peers[i]);
680   }
681 }
682
683 /**
684  * Request random peers.
685  */
686 static void
687 request_peers (void *cls,
688                const struct GNUNET_SCHEDULER_TaskContext *tc)
689 {
690   struct RPSPeer *rps_peer = (struct RPSPeer *) cls;
691
692   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
693               "Requesting one peer\n");
694
695   GNUNET_free (GNUNET_RPS_request_peers (rps_peer->rps_handle,
696                                          1,
697                                          cur_test_run.reply_handle,
698                                          rps_peer));
699   //rps_peer->req_handle = GNUNET_RPS_request_peers (rps_peer->rps_handle, 1, handle_reply, rps_peer);
700 }
701
702
703 /***********************************
704  * MALICIOUS
705 ***********************************/
706 static void
707 mal_pre (void *cls, struct GNUNET_RPS_Handle *h)
708 {
709   #ifdef ENABLE_MALICIOUS
710   uint32_t num_mal_peers;
711   struct RPSPeer *rps_peer = (struct RPSPeer *) cls;
712
713   GNUNET_assert (1 >= portion
714                  && 0 <  portion);
715   num_mal_peers = round (portion * num_peers);
716
717   if (rps_peer->index < num_mal_peers)
718   {
719     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
720                 "%u. peer [%s] of %" PRIu32 " malicious peers turning malicious\n",
721                 rps_peer->index,
722                 GNUNET_i2s (rps_peer->peer_id),
723                 num_mal_peers);
724
725     GNUNET_RPS_act_malicious (h, mal_type, num_mal_peers, rps_peer_ids);
726   }
727   #endif /* ENABLE_MALICIOUS */
728 }
729
730 static void
731 mal_cb (struct RPSPeer *rps_peer)
732 {
733   uint32_t num_mal_peers;
734
735   #ifdef ENABLE_MALICIOUS
736   GNUNET_assert (1 >= portion
737                  && 0 <  portion);
738   num_mal_peers = round (portion * num_peers);
739
740   if (rps_peer->index >= num_mal_peers)
741   { /* It's useless to ask a malicious peer about a random sample -
742        it's not sampling */
743     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
744                                   seed_peers, rps_peer);
745     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
746                                   request_peers, rps_peer);
747   }
748   #endif /* ENABLE_MALICIOUS */
749 }
750
751 static int
752 mal_eval (void)
753 {
754   unsigned int num_mal_peers;
755
756   num_mal_peers = round (num_peers * portion);
757   return evaluate (&rps_peers[num_mal_peers],
758                    num_peers - (num_mal_peers),
759                    1);
760 }
761
762
763 /***********************************
764  * SINGLE_REQUEST
765 ***********************************/
766 static void
767 single_req_cb (struct RPSPeer *rps_peer)
768 {
769   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
770                                 request_peers, rps_peer);
771 }
772
773 /***********************************
774  * DELAYED_REQUESTS
775 ***********************************/
776 static void
777 delay_req_cb (struct RPSPeer *rps_peer)
778 {
779   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
780                                 request_peers, rps_peer);
781   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
782                                 request_peers, rps_peer);
783 }
784
785 /***********************************
786  * SEED
787 ***********************************/
788 static void
789 seed_cb (struct RPSPeer *rps_peer)
790 {
791   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
792                                 seed_peers, rps_peer);
793 }
794
795 /***********************************
796  * SEED_BIG
797 ***********************************/
798 static void
799 seed_big_cb (struct RPSPeer *rps_peer)
800 {
801   // TODO test seeding > GNUNET_SERVER_MAX_MESSAGE_SIZE peers
802 }
803
804 /***********************************
805  * SINGLE_PEER_SEED
806 ***********************************/
807 static void
808 single_peer_seed_cb (struct RPSPeer *rps_peer)
809 {
810   // TODO
811 }
812
813 /***********************************
814  * SEED_REQUEST
815 ***********************************/
816 static void
817 seed_req_cb (struct RPSPeer *rps_peer)
818 {
819   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
820                                 seed_peers, rps_peer);
821   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15),
822                                 request_peers, rps_peer);
823 }
824
825 //TODO start big mal
826
827 /***********************************
828  * REQUEST_CANCEL
829 ***********************************/
830 static void
831 req_cancel_cb (struct RPSPeer *rps_peer)
832 {
833   // TODO
834 }
835
836 /***********************************
837  * PROFILER
838 ***********************************/
839 static void
840 churn (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
841 {
842   struct OpListEntry *entry;
843   unsigned int i;
844   unsigned int j;
845   double portion_online;
846   unsigned int *permut;
847   double prob_go_offline;
848   double portion_go_online;
849   double portion_go_offline;
850   uint32_t prob;
851
852   /* Compute the probability for an online peer to go offline
853    * this round */
854   portion_online = num_peers_online * 1.0 / num_peers;
855   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
856               "Portion online: %f\n",
857               portion_online);
858   portion_go_online = ((1 - portion_online) * .5 * .66);
859   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
860               "Portion that should go online: %f\n",
861               portion_go_online);
862   portion_go_offline = (portion_online + portion_go_online) - .75;
863   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
864               "Portion that probably goes offline: %f\n",
865               portion_go_offline);
866   prob_go_offline = portion_go_offline / (portion_online * .5);
867   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
868               "Probability of a selected online peer to go offline: %f\n",
869               prob_go_offline);
870
871   permut = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
872                                          (unsigned int) num_peers);
873
874   /* Go over 50% randomly chosen peers */
875   for (i = 0 ; i < .5 * num_peers ; i++)
876   {
877     j = permut[i];
878
879     /* If online, shut down with certain probability */
880     if (GNUNET_YES == rps_peers[j].online)
881     {
882       prob = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
883                                        UINT32_MAX);
884       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
885                   "%u. selected peer (%u: %s) is online.\n",
886                   i,
887                   j,
888                   GNUNET_i2s (rps_peers[j].peer_id));
889       if (prob < prob_go_offline * UINT32_MAX)
890       {
891         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
892                     "%s goes offline\n",
893                     GNUNET_i2s (rps_peers[j].peer_id));
894
895         entry = make_oplist_entry ();
896         entry->delta = -1;
897         entry->index = j;
898         entry->op = GNUNET_TESTBED_peer_manage_service (NULL,
899                                                         testbed_peers[j],
900                                                         "rps",
901                                                         &churn_cb,
902                                                         entry,
903                                                         0);
904       }
905    }
906
907    /* If offline, restart with certain probability */
908    else if (GNUNET_NO == rps_peers[j].online)
909    {
910      prob = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
911                                       UINT32_MAX);
912      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
913                  "%u. selected peer (%u: %s) is offline.\n",
914                  i,
915                  j,
916                  GNUNET_i2s (rps_peers[j].peer_id));
917      if (prob < .66 * UINT32_MAX)
918      {
919        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
920                    "%s goes online\n",
921                    GNUNET_i2s (rps_peers[j].peer_id));
922
923        entry = make_oplist_entry ();
924        entry->delta = 1;
925        entry->index = j;
926        entry->op = GNUNET_TESTBED_peer_manage_service (NULL,
927                                                        testbed_peers[j],
928                                                        "rps",
929                                                        &churn_cb,
930                                                        entry,
931                                                        1);
932      }
933    }
934   }
935
936   GNUNET_free (permut);
937
938   churn_task = GNUNET_SCHEDULER_add_delayed (
939         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
940         churn,
941         NULL);
942 }
943
944
945 static void
946 profiler_pre (void *cls, struct GNUNET_RPS_Handle *h)
947 {
948   //churn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
949   //                                                                          10),
950   //                                           churn, NULL);
951   mal_pre (cls, h);
952
953   /* if (NULL == churn_task)
954   {
955     churn_task = GNUNET_SCHEDULER_add_delayed (
956           GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
957           churn,
958           NULL);
959   } */
960 }
961
962
963 /**
964  * Callback to call on receipt of a reply
965  *
966  * @param cls closure
967  * @param n number of peers
968  * @param recv_peers the received peers
969  */
970 static void
971 profiler_reply_handle (void *cls,
972                       uint64_t n,
973                       const struct GNUNET_PeerIdentity *recv_peers)
974 {
975   struct RPSPeer *rps_peer = (struct RPSPeer *) cls;
976   struct RPSPeer *rcv_rps_peer;
977   char *file_name;
978   char *file_name_dh;
979   unsigned int i;
980
981   file_name = "/tmp/rps/received_ids";
982   file_name_dh = "/tmp/rps/diehard_input";
983
984   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
985               "[%s] got %" PRIu64 " peers:\n",
986               GNUNET_i2s (rps_peer->peer_id),
987               n);
988   
989   for (i = 0 ; i < n ; i++)
990   {
991     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
992                 "%u: %s\n",
993                 i,
994                 GNUNET_i2s (&recv_peers[i]));
995
996     /* GNUNET_array_append (rps_peer->rec_ids, rps_peer->num_rec_ids, recv_peers[i]); */
997     tofile (file_name,
998              "%s\n",
999              GNUNET_i2s_full (&recv_peers[i]));
1000
1001     rcv_rps_peer = GNUNET_CONTAINER_multipeermap_get (peer_map, &recv_peers[i]);
1002
1003     tofile (file_name_dh,
1004              "%" PRIu32 "\n",
1005              (uint32_t) rcv_rps_peer->index);
1006   }
1007 }
1008
1009
1010 static void
1011 profiler_cb (struct RPSPeer *rps_peer)
1012 {
1013   uint32_t i;
1014
1015   /* Churn only at peers that do not request peers for evaluation */
1016   if (NULL == churn_task &&
1017       rps_peer->index != num_peers - 2)
1018   {
1019     churn_task = GNUNET_SCHEDULER_add_delayed (
1020           GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
1021           churn,
1022           NULL);
1023   }
1024
1025   /* Only request peer ids at one peer.
1026    * (It's the before-last because last one is target of the focussed attack.)
1027    */
1028   if (rps_peer->index == num_peers - 2)
1029   {
1030     for (i = 0 ; i < cur_test_run.num_requests ; i++)
1031     {
1032       GNUNET_SCHEDULER_add_delayed (
1033           GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
1034                                          cur_test_run.request_interval * i),
1035           request_peers,
1036           rps_peer);
1037     }
1038   }
1039 }
1040
1041 /**
1042  * Function called from #profiler_eval with a filename.
1043  *
1044  * @param cls closure
1045  * @param filename complete filename (absolute path)
1046  * @return #GNUNET_OK to continue to iterate,
1047  *  #GNUNET_NO to stop iteration with no error,
1048  *  #GNUNET_SYSERR to abort iteration with error!
1049  */
1050 int
1051 file_name_cb (void *cls, const char *filename)
1052 {
1053   if (NULL != strstr (filename, "sampler_el"))
1054   {
1055     struct RPS_SamplerElement *s_elem;
1056     struct GNUNET_CRYPTO_AuthKey auth_key;
1057     const char *key_char;
1058     uint32_t i;
1059
1060     key_char = filename + 20; /* Length of "/tmp/rps/sampler_el-" */
1061     tofile (filename, "--------------------------\n");
1062
1063     auth_key = string_to_auth_key (key_char);
1064     s_elem = RPS_sampler_elem_create ();
1065     RPS_sampler_elem_set (s_elem, auth_key);
1066
1067     for (i = 0; i < num_peers; i++)
1068     {
1069       RPS_sampler_elem_next (s_elem, &rps_peer_ids[i]);
1070     }
1071   }
1072   return GNUNET_OK;
1073 }
1074
1075 /**
1076  * This is run after the test finished.
1077  *
1078  * Compute all perfect samples.
1079  */
1080 int
1081 profiler_eval (void)
1082 {
1083   /* Compute perfect sample for each sampler element */
1084   if (-1 == GNUNET_DISK_directory_scan ("/tmp/rps/", file_name_cb, NULL))
1085   {
1086     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Scan of directory failed\n");
1087   }
1088
1089   return 0;
1090 }
1091
1092
1093 /***********************************************************************
1094  * /Definition of tests
1095 ***********************************************************************/
1096
1097
1098 /**
1099  * Actual "main" function for the testcase.
1100  *
1101  * @param cls closure
1102  * @param h the run handle
1103  * @param n_peers number of peers in 'peers'
1104  * @param peers handle to peers run in the testbed
1105  * @param links_succeeded the number of overlay link connection attempts that
1106  *          succeeded
1107  * @param links_failed the number of overlay link connection attempts that
1108  *          failed
1109  */
1110 static void
1111 run (void *cls,
1112      struct GNUNET_TESTBED_RunHandle *h,
1113      unsigned int n_peers,
1114      struct GNUNET_TESTBED_Peer **peers,
1115      unsigned int links_succeeded,
1116      unsigned int links_failed)
1117 {
1118   unsigned int i;
1119   struct OpListEntry *entry;
1120
1121   testbed_peers = peers;
1122   num_peers_online = 0;
1123
1124   for (i = 0 ; i < num_peers ; i++)
1125   {
1126     entry = make_oplist_entry ();
1127     entry->index = i;
1128     entry->op = GNUNET_TESTBED_peer_get_information (peers[i],
1129                                                      GNUNET_TESTBED_PIT_IDENTITY,
1130                                                      &info_cb,
1131                                                      entry);
1132   }
1133
1134
1135   // This seems not to work
1136   //if (NULL != strstr (cur_test_run.name, "profiler"))
1137   //{
1138   //  churn_task = GNUNET_SCHEDULER_add_delayed (
1139   //      GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
1140   //      churn,
1141   //      NULL);
1142   //}
1143
1144   GNUNET_assert (num_peers == n_peers);
1145   for (i = 0 ; i < n_peers ; i++)
1146   {
1147     rps_peers[i].index = i;
1148     rps_peers[i].op =
1149       GNUNET_TESTBED_service_connect (&rps_peers[i],
1150                                                                           peers[i],
1151                                                                           "rps",
1152                                                                           &rps_connect_complete_cb,
1153                                                                           &rps_peers[i],
1154                                                                           &rps_connect_adapter,
1155                                                                           &rps_disconnect_adapter,
1156                                                                           &rps_peers[i]);
1157   }
1158
1159   if (NULL != churn_task)
1160     GNUNET_SCHEDULER_cancel (churn_task);
1161
1162   GNUNET_SCHEDULER_add_delayed (timeout, &shutdown_task, NULL);
1163 }
1164
1165
1166 /**
1167  * Entry point for the testcase, sets up the testbed.
1168  *
1169  * @param argc unused
1170  * @param argv unused
1171  * @return 0 on success
1172  */
1173 int
1174 main (int argc, char *argv[])
1175 {
1176   int ret_value;
1177
1178   cur_test_run.name = "test-rps-default";
1179   cur_test_run.pre_test = NULL;
1180   cur_test_run.reply_handle = default_reply_handle;
1181   cur_test_run.eval_cb = default_eval_cb;
1182   churn_task = NULL;
1183
1184   num_peers = 5;
1185   timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30);
1186
1187   if (strstr (argv[0], "malicious") != NULL)
1188   {
1189     cur_test_run.pre_test = mal_pre;
1190     cur_test_run.main_test = mal_cb;
1191     cur_test_run.eval_cb = mal_eval;
1192
1193     if (strstr (argv[0], "_1") != NULL)
1194     {
1195       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 1\n");
1196       cur_test_run.name = "test-rps-malicious_1";
1197       mal_type = 1;
1198     }
1199     else if (strstr (argv[0], "_2") != NULL)
1200     {
1201       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 2\n");
1202       cur_test_run.name = "test-rps-malicious_2";
1203       mal_type = 2;
1204     }
1205     else if (strstr (argv[0], "_3") != NULL)
1206     {
1207       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 3\n");
1208       cur_test_run.name = "test-rps-malicious_3";
1209       mal_type = 3;
1210     }
1211   }
1212
1213   else if (strstr (argv[0], "_single_req") != NULL)
1214   {
1215     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test single request\n");
1216     cur_test_run.name = "test-rps-single-req";
1217     cur_test_run.main_test = single_req_cb;
1218   }
1219
1220   else if (strstr (argv[0], "_delayed_reqs") != NULL)
1221   {
1222     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test delayed requests\n");
1223     cur_test_run.name = "test-rps-delayed-reqs";
1224     cur_test_run.main_test = delay_req_cb;
1225   }
1226
1227   else if (strstr (argv[0], "_seed_big") != NULL)
1228   {
1229     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding (num_peers > GNUNET_SERVER_MAX_MESSAGE_SIZE)\n");
1230     cur_test_run.name = "test-rps-seed-big";
1231     cur_test_run.main_test = seed_big_cb;
1232   }
1233
1234   else if (strstr (argv[0], "_single_peer_seed") != NULL)
1235   {
1236     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding and requesting on a single peer\n");
1237     cur_test_run.name = "test-rps-single-peer-seed";
1238     cur_test_run.main_test = single_peer_seed_cb;
1239   }
1240
1241   else if (strstr (argv[0], "_seed_request") != NULL)
1242   {
1243     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding and requesting on multiple peers\n");
1244     cur_test_run.name = "test-rps-seed-request";
1245     cur_test_run.main_test = seed_req_cb;
1246   }
1247
1248   else if (strstr (argv[0], "_seed") != NULL)
1249   {
1250     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding\n");
1251     cur_test_run.name = "test-rps-seed";
1252     cur_test_run.main_test = seed_cb;
1253     cur_test_run.eval_cb = no_eval;
1254   }
1255
1256   else if (strstr (argv[0], "_req_cancel") != NULL)
1257   {
1258     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test cancelling a request\n");
1259     cur_test_run.name = "test-rps-req-cancel";
1260     cur_test_run.main_test = req_cancel_cb;
1261   }
1262
1263   else if (strstr (argv[0], "profiler") != NULL)
1264   {
1265     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "This is the profiler\n");
1266     cur_test_run.name = "test-rps-profiler";
1267     mal_type = 3;
1268     cur_test_run.pre_test = profiler_pre;
1269     cur_test_run.main_test = profiler_cb;
1270     cur_test_run.reply_handle = profiler_reply_handle;
1271     cur_test_run.eval_cb = profiler_eval;
1272     cur_test_run.request_interval = 2;
1273     cur_test_run.num_requests = 50;
1274
1275     num_peers = 50;
1276
1277     (void) GNUNET_DISK_directory_remove ("/tmp/rps/");
1278     GNUNET_DISK_directory_create ("/tmp/rps/");
1279     timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 90);
1280   }
1281
1282   rps_peers = GNUNET_new_array (num_peers, struct RPSPeer);
1283   rps_peer_ids = GNUNET_new_array (num_peers, struct GNUNET_PeerIdentity);
1284   peer_map = GNUNET_CONTAINER_multipeermap_create (num_peers, GNUNET_NO);
1285
1286   ok = 1;
1287   (void) GNUNET_TESTBED_test_run (cur_test_run.name,
1288                                   "test_rps.conf",
1289                                   num_peers,
1290                                   0, NULL, NULL,
1291                                   &run, NULL);
1292
1293   ret_value = cur_test_run.eval_cb();
1294
1295   GNUNET_free (rps_peers );
1296   GNUNET_free (rps_peer_ids);
1297   GNUNET_CONTAINER_multipeermap_destroy (peer_map);
1298
1299   return ret_value;
1300 }
1301
1302 /* end of test_rps_multipeer.c */