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