2 This file is part of GNUnet.
3 Copyright (C) 2009, 2012 Christian Grothoff (and other contributing authors)
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.
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.
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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
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.
28 #include "gnunet_util_lib.h"
29 #include "gnunet_testbed_service.h"
30 #include "gnunet_rps_service.h"
36 * How many peers do we start?
41 * How long do we run the test?
43 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
47 * Portion of malicious peers
49 static double portion = .1;
52 * Type of malicious peer to test
54 static unsigned int mal_type = 0;
57 * Handles to all of the running peers
59 static struct GNUNET_TESTBED_Peer **testbed_peers;
70 struct OpListEntry *next;
75 struct OpListEntry *prev;
78 * The testbed operation
80 struct GNUNET_TESTBED_Operation *op;
83 * Depending on whether we start or stop NSE service at the peer set this to 1
89 * Index of the regarding peer
97 static struct OpListEntry *oplist_head;
102 static struct OpListEntry *oplist_tail;
106 * Information we track for each peer.
116 * Handle for RPS connect operation.
118 struct GNUNET_TESTBED_Operation *op;
121 * Handle to RPS service.
123 struct GNUNET_RPS_Handle *rps_handle;
128 struct GNUNET_PeerIdentity *peer_id;
131 * A request handle to check for an request
133 //struct GNUNET_RPS_Request_Handle *req_handle;
136 * Peer on- or offline?
143 struct GNUNET_PeerIdentity *rec_ids;
146 * Number of received PeerIDs
148 unsigned int num_rec_ids;
153 * Information for all the peers.
155 static struct RPSPeer rps_peers[NUM_PEERS];
160 static struct GNUNET_PeerIdentity rps_peer_ids[NUM_PEERS];
163 * Number of online peers.
165 static unsigned int num_peers_online;
168 * Return value from 'main'.
174 * Identifier for the churn task that runs periodically
176 static struct GNUNET_SCHEDULER_Task *churn_task;
180 * Called directly after connecting to the service
182 typedef void (*PreTest) (void *cls, struct GNUNET_RPS_Handle *h);
185 * Called from within #rps_connect_complete_cb ()
186 * Executes functions to test the api/service
188 typedef void (*MainTest) (struct RPSPeer *rps_peer);
191 * Called directly before disconnecting from the service
193 typedef void (*PostTest) (void *cls, struct GNUNET_RPS_Handle *h);
196 * Function called after disconnect to evaluate test success
198 typedef int (*EvaluationCallback) (void);
202 * Structure to define a single test
207 * Called directly after connecting to the service
212 * Function to execute the functions to be tested
217 * Called directly before disconnecting from the service
222 * Function to evaluate the test results
224 EvaluationCallback eval_cb;
229 * Test the success of a single test
232 evaluate (struct RPSPeer *loc_rps_peers,
233 unsigned int num_loc_rps_peers,
234 unsigned int expected_recv)
239 tmp_ok = (1 == loc_rps_peers[0].num_rec_ids);
241 for (i = 0 ; i < num_loc_rps_peers ; i++)
243 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
244 "%u. peer [%s] received %u of %u expected peer_ids: %i\n",
246 GNUNET_i2s (loc_rps_peers[i].peer_id),
247 loc_rps_peers[i].num_rec_ids,
249 (1 == loc_rps_peers[i].num_rec_ids));
250 tmp_ok &= (1 == loc_rps_peers[i].num_rec_ids);
252 return tmp_ok? 0 : 1;
257 * Creates an oplist entry and adds it to the oplist DLL
259 static struct OpListEntry *
262 struct OpListEntry *entry;
264 entry = GNUNET_new (struct OpListEntry);
265 GNUNET_CONTAINER_DLL_insert_tail (oplist_head, oplist_tail, entry);
271 * Callback to be called when NSE service is started or stopped at peers
274 * @param op the operation handle
275 * @param emsg NULL on success; otherwise an error description
279 struct GNUNET_TESTBED_Operation *op,
282 struct OpListEntry *entry = cls;
284 GNUNET_TESTBED_operation_done (entry->op);
287 //LOG (GNUNET_ERROR_TYPE_ERROR, "Failed to start/stop NSE at a peer\n");
288 GNUNET_SCHEDULER_shutdown ();
291 GNUNET_assert (0 != entry->delta);
293 num_peers_online += entry->delta;
295 if (0 < entry->delta)
296 { /* Peer hopefully just went online */
297 GNUNET_break (GNUNET_NO == rps_peers[entry->index].online);
298 rps_peers[entry->index].online = GNUNET_YES;
300 else if (0 > entry->delta)
301 { /* Peer hopefully just went offline */
302 GNUNET_break (GNUNET_YES == rps_peers[entry->index].online);
303 rps_peers[entry->index].online = GNUNET_NO;
306 GNUNET_CONTAINER_DLL_remove (oplist_head, oplist_tail, entry);
308 //if (num_peers_in_round[current_round] == peers_running)
314 * Task run on timeout to shut everything down.
317 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
321 if (NULL != churn_task)
322 GNUNET_SCHEDULER_cancel (churn_task);
324 for (i = 0 ; i < num_peers ; i++)
325 GNUNET_TESTBED_operation_done (rps_peers[i].op);
326 GNUNET_SCHEDULER_shutdown ();
331 * Callback to call on receipt of a reply
334 * @param n number of peers
335 * @param recv_peers the received peers
338 handle_reply (void *cls, uint64_t n, const struct GNUNET_PeerIdentity *recv_peers)
340 struct RPSPeer *rps_peer = (struct RPSPeer *) cls;
343 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
344 "[%s] got %" PRIu64 " peers:\n",
345 GNUNET_i2s (rps_peer->peer_id),
348 for (i = 0 ; i < n ; i++)
350 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
353 GNUNET_i2s (&recv_peers[i]));
355 GNUNET_array_append (rps_peer->rec_ids, rps_peer->num_rec_ids, recv_peers[i]);
361 * Request random peers.
364 request_peers (void *cls,
365 const struct GNUNET_SCHEDULER_TaskContext *tc)
367 struct RPSPeer *rps_peer = (struct RPSPeer *) cls;
369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
370 "Requesting one peer\n");
372 (void) GNUNET_RPS_request_peers (rps_peer->rps_handle, 1, handle_reply, rps_peer);
373 //rps_peer->req_handle = GNUNET_RPS_request_peers (rps_peer->rps_handle, 1, handle_reply, rps_peer);
381 seed_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
384 struct RPSPeer *peer = (struct RPSPeer *) cls;
387 // TODO if malicious don't seed mal peers
388 amount = round (.5 * NUM_PEERS);
390 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Seeding peers:\n");
391 for (i = 0 ; i < amount ; i++)
392 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Seeding %u. peer: %s\n",
394 GNUNET_i2s (&rps_peer_ids[i]));
396 GNUNET_RPS_seed_ids (peer->rps_handle, amount, rps_peer_ids);
401 * Get the id of peer i.
404 info_cb (void *cb_cls,
405 struct GNUNET_TESTBED_Operation *op,
406 const struct GNUNET_TESTBED_PeerInformation *pinfo,
409 unsigned int i = *((unsigned int *) cb_cls);
411 if (NULL == pinfo || NULL != emsg)
413 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Got Error: %s\n", emsg);
417 GNUNET_free (cb_cls);
419 rps_peer_ids[i] = *(pinfo->result.id);
420 rps_peers[i].peer_id = &rps_peer_ids[i];
421 rps_peers[i].rec_ids = NULL;
422 rps_peers[i].num_rec_ids = 0;
428 * Callback to be called when RPS service connect operation is completed
430 * @param cls the callback closure from functions generating an operation
431 * @param op the operation that has been finished
432 * @param ca_result the RPS service handle returned from rps_connect_adapter
433 * @param emsg error message in case the operation has failed; will be NULL if
434 * operation has executed successfully.
437 rps_connect_complete_cb (void *cls,
438 struct GNUNET_TESTBED_Operation *op,
442 struct RPSPeer *rps_peer = cls;
443 struct GNUNET_RPS_Handle *rps = ca_result;
445 rps_peer->rps_handle = rps;
446 rps_peer->online = GNUNET_YES;
449 GNUNET_assert (op == rps_peer->op);
452 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
453 "Failed to connect to RPS service: %s\n",
456 GNUNET_SCHEDULER_shutdown ();
460 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started client successfully\n");
462 cur_test_run.main_test (rps_peer);
467 * Adapter function called to establish a connection to
471 * @param cfg configuration of the peer to connect to; will be available until
472 * GNUNET_TESTBED_operation_done() is called on the operation returned
473 * from GNUNET_TESTBED_service_connect()
474 * @return service handle to return in 'op_result', NULL on error
477 rps_connect_adapter (void *cls,
478 const struct GNUNET_CONFIGURATION_Handle *cfg)
480 struct GNUNET_RPS_Handle *h;
482 h = GNUNET_RPS_connect (cfg);
484 if (NULL != cur_test_run.pre_test)
485 cur_test_run.pre_test (cls, h);
492 * Adapter function called to destroy connection to
496 * @param op_result service handle returned from the connect adapter
499 rps_disconnect_adapter (void *cls,
502 struct GNUNET_RPS_Handle *h = op_result;
503 GNUNET_RPS_disconnect (h);
507 /***********************************************************************
508 * Definition of tests
509 ***********************************************************************/
512 default_eval_cb (void)
514 return evaluate (rps_peers, NUM_PEERS, 1);
516 /***********************************
518 ***********************************/
520 mal_pre (void *cls, struct GNUNET_RPS_Handle *h)
522 #ifdef ENABLE_MALICIOUS
523 uint32_t num_mal_peers;
524 struct RPSPeer *rps_peer = (struct RPSPeer *) cls;
526 GNUNET_assert (1 >= portion
528 num_mal_peers = round (portion * NUM_PEERS);
530 if (rps_peer->index < num_mal_peers)
532 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
533 "%u. peer [%s] of %" PRIu32 " malicious peers turning malicious\n",
535 GNUNET_i2s (rps_peer->peer_id),
538 GNUNET_RPS_act_malicious (h, mal_type, num_mal_peers, rps_peer_ids);
540 #endif /* ENABLE_MALICIOUS */
544 mal_cb (struct RPSPeer *rps_peer)
546 uint32_t num_mal_peers;
548 #ifdef ENABLE_MALICIOUS
549 GNUNET_assert (1 >= portion
551 num_mal_peers = round (portion * NUM_PEERS);
553 if (rps_peer->index >= num_mal_peers)
554 { /* It's useless to ask a malicious peer about a random sample -
556 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
557 seed_peers, rps_peer);
558 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
559 request_peers, rps_peer);
561 #endif /* ENABLE_MALICIOUS */
567 unsigned int num_mal_peers;
569 num_mal_peers = round (NUM_PEERS * portion);
570 return evaluate (&rps_peers[num_mal_peers],
571 NUM_PEERS - (num_mal_peers),
576 /***********************************
578 ***********************************/
580 single_req_cb (struct RPSPeer *rps_peer)
582 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
583 request_peers, rps_peer);
586 /***********************************
588 ***********************************/
590 delay_req_cb (struct RPSPeer *rps_peer)
592 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
593 request_peers, rps_peer);
594 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
595 request_peers, rps_peer);
598 /***********************************
600 ***********************************/
602 seed_cb (struct RPSPeer *rps_peer)
604 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
605 seed_peers, rps_peer);
614 /***********************************
616 ***********************************/
618 seed_big_cb (struct RPSPeer *rps_peer)
620 // TODO test seeding > GNUNET_SERVER_MAX_MESSAGE_SIZE peers
623 /***********************************
625 ***********************************/
627 single_peer_seed_cb (struct RPSPeer *rps_peer)
632 /***********************************
634 ***********************************/
636 seed_req_cb (struct RPSPeer *rps_peer)
638 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
639 seed_peers, rps_peer);
640 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15),
641 request_peers, rps_peer);
646 /***********************************
648 ***********************************/
650 req_cancel_cb (struct RPSPeer *rps_peer)
655 /***********************************
657 ***********************************/
659 churn (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
661 struct OpListEntry *entry;
664 double portion_online;
665 unsigned int *permut;
666 double prob_go_offline;
667 double portion_go_online;
668 double portion_go_offline;
671 portion_online = num_peers_online / NUM_PEERS;
672 portion_go_online = ((1 - portion_online) * .5 * .66);
673 portion_go_offline = (portion_online + portion_go_online) - .75;
674 prob_go_offline = portion_go_offline / (portion_online * .5);
676 permut = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
677 (unsigned int) NUM_PEERS);
679 for (i = 0 ; i < .5 * NUM_PEERS ; i++)
683 if (GNUNET_YES == rps_peers[j].online)
685 prob = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
687 if (prob < prob_go_offline * UINT32_MAX)
689 entry = make_oplist_entry ();
692 entry->op = GNUNET_TESTBED_peer_manage_service (NULL,
701 else if (GNUNET_NO == rps_peers[j].online)
703 prob = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
705 if (prob < .66 * UINT32_MAX)
707 entry = make_oplist_entry ();
710 entry->op = GNUNET_TESTBED_peer_manage_service (NULL,
720 churn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
726 profiler_pre (void *cls, struct GNUNET_RPS_Handle *h)
728 churn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
735 profiler_cb (struct RPSPeer *rps_peer)
737 // We're not requesting peers
742 /***********************************************************************
743 * /Definition of tests
744 ***********************************************************************/
748 * Actual "main" function for the testcase.
751 * @param h the run handle
752 * @param num_peers number of peers in 'peers'
753 * @param peers handle to peers run in the testbed
754 * @param links_succeeded the number of overlay link connection attempts that
756 * @param links_failed the number of overlay link connection attempts that
761 struct GNUNET_TESTBED_RunHandle *h,
762 unsigned int num_peers,
763 struct GNUNET_TESTBED_Peer **peers,
764 unsigned int links_succeeded,
765 unsigned int links_failed)
770 testbed_peers = peers;
771 num_peers_online = 0;
773 for (i = 0 ; i < NUM_PEERS ; i++)
775 tmp_i = GNUNET_new (unsigned int);
778 (void) GNUNET_TESTBED_peer_get_information (peers[i],
779 GNUNET_TESTBED_PIT_IDENTITY,
784 GNUNET_assert (NUM_PEERS == num_peers);
785 for (i = 0 ; i < num_peers ; i++)
787 rps_peers[i].index = i;
789 GNUNET_TESTBED_service_connect (&rps_peers[i],
792 &rps_connect_complete_cb,
794 &rps_connect_adapter,
795 &rps_disconnect_adapter,
798 GNUNET_SCHEDULER_add_delayed (TIMEOUT, &shutdown_task, NULL);
803 * Entry point for the testcase, sets up the testbed.
807 * @return 0 on success
810 main (int argc, char *argv[])
812 cur_test_run.pre_test = NULL;
813 cur_test_run.eval_cb = default_eval_cb;
816 if (strstr (argv[0], "malicious") != NULL)
818 cur_test_run.pre_test = mal_pre;
819 cur_test_run.main_test = mal_cb;
820 cur_test_run.eval_cb = mal_eval;
822 if (strstr (argv[0], "_1") != NULL)
824 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 1\n");
827 else if (strstr (argv[0], "_2") != NULL)
829 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 2\n");
832 else if (strstr (argv[0], "_3") != NULL)
834 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 3\n");
839 else if (strstr (argv[0], "_single_req") != NULL)
841 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test single request\n");
842 cur_test_run.main_test = single_req_cb;
844 else if (strstr (argv[0], "_delayed_reqs") != NULL)
846 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test delayed requests\n");
847 cur_test_run.main_test = delay_req_cb;
849 else if (strstr (argv[0], "_seed_big") != NULL)
851 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding (num_peers > GNUNET_SERVER_MAX_MESSAGE_SIZE)\n");
852 cur_test_run.main_test = seed_big_cb;
854 else if (strstr (argv[0], "_single_peer_seed") != NULL)
856 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding and requesting on a single peer\n");
857 cur_test_run.main_test = single_peer_seed_cb;
859 else if (strstr (argv[0], "_seed_request") != NULL)
861 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding and requesting on multiple peers\n");
862 cur_test_run.main_test = seed_req_cb;
864 else if (strstr (argv[0], "_seed") != NULL)
866 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding\n");
867 cur_test_run.main_test = seed_cb;
868 cur_test_run.eval_cb = seed_eval;
870 else if (strstr (argv[0], "_req_cancel") != NULL)
872 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test cancelling a request\n");
873 cur_test_run.main_test = req_cancel_cb;
875 else if (strstr (argv[0], "profiler") != NULL)
877 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "This is the profiler\n");
879 cur_test_run.pre_test = profiler_pre;
880 cur_test_run.main_test = profiler_cb;
881 churn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
887 (void) GNUNET_TESTBED_test_run ("test-rps-multipeer",
893 if (NULL != churn_task)
894 GNUNET_SCHEDULER_cancel (churn_task);
896 return cur_test_run.eval_cb();
899 /* end of test_rps_multipeer.c */