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)
44 static struct GNUNET_TIME_Relative timeout;
48 * Portion of malicious peers
50 static double portion = .1;
53 * Type of malicious peer to test
55 static unsigned int mal_type = 0;
58 * Handles to all of the running peers
60 static struct GNUNET_TESTBED_Peer **testbed_peers;
71 struct OpListEntry *next;
76 struct OpListEntry *prev;
79 * The testbed operation
81 struct GNUNET_TESTBED_Operation *op;
84 * Depending on whether we start or stop NSE service at the peer set this to 1
90 * Index of the regarding peer
98 static struct OpListEntry *oplist_head;
103 static struct OpListEntry *oplist_tail;
107 * Information we track for each peer.
117 * Handle for RPS connect operation.
119 struct GNUNET_TESTBED_Operation *op;
122 * Handle to RPS service.
124 struct GNUNET_RPS_Handle *rps_handle;
129 struct GNUNET_PeerIdentity *peer_id;
132 * A request handle to check for an request
134 //struct GNUNET_RPS_Request_Handle *req_handle;
137 * Peer on- or offline?
144 struct GNUNET_PeerIdentity *rec_ids;
147 * Number of received PeerIDs
149 unsigned int num_rec_ids;
154 * Information for all the peers.
156 static struct RPSPeer *rps_peers;
161 static struct GNUNET_PeerIdentity *rps_peer_ids;
164 * Number of online peers.
166 static unsigned int num_peers_online;
169 * Return value from 'main'.
175 * Identifier for the churn task that runs periodically
177 static struct GNUNET_SCHEDULER_Task *churn_task;
181 * Called directly after connecting to the service
183 typedef void (*PreTest) (void *cls, struct GNUNET_RPS_Handle *h);
186 * Called from within #rps_connect_complete_cb ()
187 * Executes functions to test the api/service
189 typedef void (*MainTest) (struct RPSPeer *rps_peer);
192 * Called directly before disconnecting from the service
194 typedef void (*PostTest) (void *cls, struct GNUNET_RPS_Handle *h);
197 * Function called after disconnect to evaluate test success
199 typedef int (*EvaluationCallback) (void);
203 * Structure to define a single test
213 * Called directly after connecting to the service
218 * Function to execute the functions to be tested
223 * Called directly before disconnecting from the service
228 * Function to evaluate the test results
230 EvaluationCallback eval_cb;
235 * Test the success of a single test
238 evaluate (struct RPSPeer *loc_rps_peers,
239 unsigned int num_loc_rps_peers,
240 unsigned int expected_recv)
245 tmp_ok = (1 == loc_rps_peers[0].num_rec_ids);
247 for (i = 0 ; i < num_loc_rps_peers ; i++)
249 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
250 "%u. peer [%s] received %u of %u expected peer_ids: %i\n",
252 GNUNET_i2s (loc_rps_peers[i].peer_id),
253 loc_rps_peers[i].num_rec_ids,
255 (1 == loc_rps_peers[i].num_rec_ids));
256 tmp_ok &= (1 == loc_rps_peers[i].num_rec_ids);
258 return tmp_ok? 0 : 1;
263 * Creates an oplist entry and adds it to the oplist DLL
265 static struct OpListEntry *
268 struct OpListEntry *entry;
270 entry = GNUNET_new (struct OpListEntry);
271 GNUNET_CONTAINER_DLL_insert_tail (oplist_head, oplist_tail, entry);
277 * Callback to be called when NSE service is started or stopped at peers
280 * @param op the operation handle
281 * @param emsg NULL on success; otherwise an error description
285 struct GNUNET_TESTBED_Operation *op,
289 struct OpListEntry *entry = cls;
291 GNUNET_TESTBED_operation_done (entry->op);
294 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start/stop RPS at a peer\n");
295 GNUNET_SCHEDULER_shutdown ();
298 GNUNET_assert (0 != entry->delta);
300 num_peers_online += entry->delta;
302 if (0 > entry->delta)
303 { /* Peer hopefully just went offline */
304 if (GNUNET_YES != rps_peers[entry->index].online)
306 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
307 "peer %s was expected to go offline but is still marked as online\n",
308 GNUNET_i2s (rps_peers[entry->index].peer_id));
313 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
314 "peer %s probably went offline as expected\n",
315 GNUNET_i2s (rps_peers[entry->index].peer_id));
317 rps_peers[entry->index].online = GNUNET_NO;
320 else if (0 < entry->delta)
321 { /* Peer hopefully just went online */
322 if (GNUNET_NO != rps_peers[entry->index].online)
324 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
325 "peer %s was expected to go online but is still marked as offline\n",
326 GNUNET_i2s (rps_peers[entry->index].peer_id));
331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
332 "peer %s probably went online as expected\n",
333 GNUNET_i2s (rps_peers[entry->index].peer_id));
335 rps_peers[entry->index].online = GNUNET_YES;
338 GNUNET_CONTAINER_DLL_remove (oplist_head, oplist_tail, entry);
340 //if (num_peers_in_round[current_round] == peers_running)
346 * Task run on timeout to shut everything down.
349 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
353 if (NULL != churn_task)
354 GNUNET_SCHEDULER_cancel (churn_task);
356 for (i = 0 ; i < num_peers ; i++)
357 GNUNET_TESTBED_operation_done (rps_peers[i].op);
358 GNUNET_SCHEDULER_shutdown ();
363 * Callback to call on receipt of a reply
366 * @param n number of peers
367 * @param recv_peers the received peers
370 handle_reply (void *cls, uint64_t n, const struct GNUNET_PeerIdentity *recv_peers)
372 struct RPSPeer *rps_peer = (struct RPSPeer *) cls;
375 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
376 "[%s] got %" PRIu64 " peers:\n",
377 GNUNET_i2s (rps_peer->peer_id),
380 for (i = 0 ; i < n ; i++)
382 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
385 GNUNET_i2s (&recv_peers[i]));
387 GNUNET_array_append (rps_peer->rec_ids, rps_peer->num_rec_ids, recv_peers[i]);
393 * Request random peers.
396 request_peers (void *cls,
397 const struct GNUNET_SCHEDULER_TaskContext *tc)
399 struct RPSPeer *rps_peer = (struct RPSPeer *) cls;
401 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
402 "Requesting one peer\n");
404 (void) GNUNET_RPS_request_peers (rps_peer->rps_handle, 1, handle_reply, rps_peer);
405 //rps_peer->req_handle = GNUNET_RPS_request_peers (rps_peer->rps_handle, 1, handle_reply, rps_peer);
413 seed_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
416 struct RPSPeer *peer = (struct RPSPeer *) cls;
419 // TODO if malicious don't seed mal peers
420 amount = round (.5 * num_peers);
422 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Seeding peers:\n");
423 for (i = 0 ; i < amount ; i++)
424 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Seeding %u. peer: %s\n",
426 GNUNET_i2s (&rps_peer_ids[i]));
428 GNUNET_RPS_seed_ids (peer->rps_handle, amount, rps_peer_ids);
433 * Get the id of peer i.
436 info_cb (void *cb_cls,
437 struct GNUNET_TESTBED_Operation *op,
438 const struct GNUNET_TESTBED_PeerInformation *pinfo,
441 struct OpListEntry *entry = (struct OpListEntry *) cb_cls;
443 if (NULL == pinfo || NULL != emsg)
445 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Got Error: %s\n", emsg);
449 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
452 GNUNET_i2s (pinfo->result.id));
454 rps_peer_ids[entry->index] = *(pinfo->result.id);
455 rps_peers[entry->index].peer_id = &rps_peer_ids[entry->index];
456 rps_peers[entry->index].rec_ids = NULL;
457 rps_peers[entry->index].num_rec_ids = 0;
459 GNUNET_TESTBED_operation_done (entry->op);
461 GNUNET_CONTAINER_DLL_remove (oplist_head, oplist_tail, entry);
467 * Callback to be called when RPS service connect operation is completed
469 * @param cls the callback closure from functions generating an operation
470 * @param op the operation that has been finished
471 * @param ca_result the RPS service handle returned from rps_connect_adapter
472 * @param emsg error message in case the operation has failed; will be NULL if
473 * operation has executed successfully.
476 rps_connect_complete_cb (void *cls,
477 struct GNUNET_TESTBED_Operation *op,
481 struct RPSPeer *rps_peer = cls;
482 struct GNUNET_RPS_Handle *rps = ca_result;
484 rps_peer->rps_handle = rps;
485 rps_peer->online = GNUNET_YES;
488 GNUNET_assert (op == rps_peer->op);
491 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
492 "Failed to connect to RPS service: %s\n",
495 GNUNET_SCHEDULER_shutdown ();
499 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started client successfully\n");
501 cur_test_run.main_test (rps_peer);
506 * Adapter function called to establish a connection to
510 * @param cfg configuration of the peer to connect to; will be available until
511 * GNUNET_TESTBED_operation_done() is called on the operation returned
512 * from GNUNET_TESTBED_service_connect()
513 * @return service handle to return in 'op_result', NULL on error
516 rps_connect_adapter (void *cls,
517 const struct GNUNET_CONFIGURATION_Handle *cfg)
519 struct GNUNET_RPS_Handle *h;
521 h = GNUNET_RPS_connect (cfg);
523 if (NULL != cur_test_run.pre_test)
524 cur_test_run.pre_test (cls, h);
531 * Adapter function called to destroy connection to
535 * @param op_result service handle returned from the connect adapter
538 rps_disconnect_adapter (void *cls,
541 struct GNUNET_RPS_Handle *h = op_result;
542 GNUNET_RPS_disconnect (h);
546 /***********************************************************************
547 * Definition of tests
548 ***********************************************************************/
551 default_eval_cb (void)
553 return evaluate (rps_peers, num_peers, 1);
562 /***********************************
564 ***********************************/
566 mal_pre (void *cls, struct GNUNET_RPS_Handle *h)
568 #ifdef ENABLE_MALICIOUS
569 uint32_t num_mal_peers;
570 struct RPSPeer *rps_peer = (struct RPSPeer *) cls;
572 GNUNET_assert (1 >= portion
574 num_mal_peers = round (portion * num_peers);
576 if (rps_peer->index < num_mal_peers)
578 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
579 "%u. peer [%s] of %" PRIu32 " malicious peers turning malicious\n",
581 GNUNET_i2s (rps_peer->peer_id),
584 GNUNET_RPS_act_malicious (h, mal_type, num_mal_peers, rps_peer_ids);
586 #endif /* ENABLE_MALICIOUS */
590 mal_cb (struct RPSPeer *rps_peer)
592 uint32_t num_mal_peers;
594 #ifdef ENABLE_MALICIOUS
595 GNUNET_assert (1 >= portion
597 num_mal_peers = round (portion * num_peers);
599 if (rps_peer->index >= num_mal_peers)
600 { /* It's useless to ask a malicious peer about a random sample -
602 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
603 seed_peers, rps_peer);
604 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
605 request_peers, rps_peer);
607 #endif /* ENABLE_MALICIOUS */
613 unsigned int num_mal_peers;
615 num_mal_peers = round (num_peers * portion);
616 return evaluate (&rps_peers[num_mal_peers],
617 num_peers - (num_mal_peers),
622 /***********************************
624 ***********************************/
626 single_req_cb (struct RPSPeer *rps_peer)
628 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
629 request_peers, rps_peer);
632 /***********************************
634 ***********************************/
636 delay_req_cb (struct RPSPeer *rps_peer)
638 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
639 request_peers, rps_peer);
640 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
641 request_peers, rps_peer);
644 /***********************************
646 ***********************************/
648 seed_cb (struct RPSPeer *rps_peer)
650 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
651 seed_peers, rps_peer);
654 /***********************************
656 ***********************************/
658 seed_big_cb (struct RPSPeer *rps_peer)
660 // TODO test seeding > GNUNET_SERVER_MAX_MESSAGE_SIZE peers
663 /***********************************
665 ***********************************/
667 single_peer_seed_cb (struct RPSPeer *rps_peer)
672 /***********************************
674 ***********************************/
676 seed_req_cb (struct RPSPeer *rps_peer)
678 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
679 seed_peers, rps_peer);
680 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15),
681 request_peers, rps_peer);
686 /***********************************
688 ***********************************/
690 req_cancel_cb (struct RPSPeer *rps_peer)
695 /***********************************
697 ***********************************/
699 churn (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
701 struct OpListEntry *entry;
704 double portion_online;
705 unsigned int *permut;
706 double prob_go_offline;
707 double portion_go_online;
708 double portion_go_offline;
711 /* Compute the probability for an online peer to go offline
713 portion_online = num_peers_online * 1.0 / num_peers;
714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
715 "Portion online: %f\n",
717 portion_go_online = ((1 - portion_online) * .5 * .66);
718 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
719 "Portion that should go online: %f\n",
721 portion_go_offline = (portion_online + portion_go_online) - .75;
722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
723 "Portion that probably goes offline: %f\n",
725 prob_go_offline = portion_go_offline / (portion_online * .5);
726 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
727 "Probability of a selected online peer to go offline: %f\n",
730 permut = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
731 (unsigned int) num_peers);
733 /* Go over 50% randomly chosen peers */
734 for (i = 0 ; i < .5 * num_peers ; i++)
738 /* If online, shut down with certain probability */
739 if (GNUNET_YES == rps_peers[j].online)
741 prob = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
743 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
744 "%u. selected peer (%u: %s) is online.\n",
747 GNUNET_i2s (rps_peers[j].peer_id));
748 if (prob < prob_go_offline * UINT32_MAX)
750 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
752 GNUNET_i2s (rps_peers[j].peer_id));
754 entry = make_oplist_entry ();
757 entry->op = GNUNET_TESTBED_peer_manage_service (NULL,
766 /* If offline, restart with certain probability */
767 else if (GNUNET_NO == rps_peers[j].online)
769 prob = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
771 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
772 "%u. selected peer (%u: %s) is offline.\n",
775 GNUNET_i2s (rps_peers[j].peer_id));
776 if (prob < .66 * UINT32_MAX)
778 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
780 GNUNET_i2s (rps_peers[j].peer_id));
782 entry = make_oplist_entry ();
785 entry->op = GNUNET_TESTBED_peer_manage_service (NULL,
795 churn_task = GNUNET_SCHEDULER_add_delayed (
796 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
803 profiler_pre (void *cls, struct GNUNET_RPS_Handle *h)
805 //churn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
810 if (NULL == churn_task)
812 churn_task = GNUNET_SCHEDULER_add_delayed (
813 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
820 profiler_cb (struct RPSPeer *rps_peer)
822 // We're not requesting peers
827 /***********************************************************************
828 * /Definition of tests
829 ***********************************************************************/
833 * Actual "main" function for the testcase.
836 * @param h the run handle
837 * @param n_peers number of peers in 'peers'
838 * @param peers handle to peers run in the testbed
839 * @param links_succeeded the number of overlay link connection attempts that
841 * @param links_failed the number of overlay link connection attempts that
846 struct GNUNET_TESTBED_RunHandle *h,
847 unsigned int n_peers,
848 struct GNUNET_TESTBED_Peer **peers,
849 unsigned int links_succeeded,
850 unsigned int links_failed)
853 struct OpListEntry *entry;
855 testbed_peers = peers;
856 num_peers_online = 0;
858 for (i = 0 ; i < num_peers ; i++)
860 entry = make_oplist_entry ();
862 entry->op = GNUNET_TESTBED_peer_get_information (peers[i],
863 GNUNET_TESTBED_PIT_IDENTITY,
869 // This seems not to work
870 //if (NULL != strstr (cur_test_run.name, "profiler"))
872 // churn_task = GNUNET_SCHEDULER_add_delayed (
873 // GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
878 GNUNET_assert (num_peers == n_peers);
879 for (i = 0 ; i < n_peers ; i++)
881 rps_peers[i].index = i;
883 GNUNET_TESTBED_service_connect (&rps_peers[i],
886 &rps_connect_complete_cb,
888 &rps_connect_adapter,
889 &rps_disconnect_adapter,
893 if (NULL != churn_task)
894 GNUNET_SCHEDULER_cancel (churn_task);
896 //GNUNET_SCHEDULER_add_delayed (TIMEOUT, &shutdown_task, NULL);
897 GNUNET_SCHEDULER_add_delayed (timeout, &shutdown_task, NULL);
902 * Entry point for the testcase, sets up the testbed.
906 * @return 0 on success
909 main (int argc, char *argv[])
911 cur_test_run.pre_test = NULL;
912 cur_test_run.eval_cb = default_eval_cb;
915 if (strstr (argv[0], "malicious") != NULL)
917 cur_test_run.pre_test = mal_pre;
918 cur_test_run.main_test = mal_cb;
919 cur_test_run.eval_cb = mal_eval;
921 if (strstr (argv[0], "_1") != NULL)
923 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 1\n");
926 else if (strstr (argv[0], "_2") != NULL)
928 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 2\n");
931 else if (strstr (argv[0], "_3") != NULL)
933 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test malicious peer type 3\n");
938 else if (strstr (argv[0], "_single_req") != NULL)
940 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test single request\n");
941 cur_test_run.main_test = single_req_cb;
943 else if (strstr (argv[0], "_delayed_reqs") != NULL)
945 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test delayed requests\n");
946 cur_test_run.main_test = delay_req_cb;
948 else if (strstr (argv[0], "_seed_big") != NULL)
950 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding (num_peers > GNUNET_SERVER_MAX_MESSAGE_SIZE)\n");
951 cur_test_run.main_test = seed_big_cb;
953 else if (strstr (argv[0], "_single_peer_seed") != NULL)
955 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding and requesting on a single peer\n");
956 cur_test_run.main_test = single_peer_seed_cb;
958 else if (strstr (argv[0], "_seed_request") != NULL)
960 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding and requesting on multiple peers\n");
961 cur_test_run.main_test = seed_req_cb;
963 else if (strstr (argv[0], "_seed") != NULL)
965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding\n");
966 cur_test_run.main_test = seed_cb;
967 cur_test_run.eval_cb = seed_eval;
969 else if (strstr (argv[0], "_req_cancel") != NULL)
971 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test cancelling a request\n");
972 cur_test_run.main_test = req_cancel_cb;
974 else if (strstr (argv[0], "profiler") != NULL)
976 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "This is the profiler\n");
978 cur_test_run.pre_test = profiler_pre;
979 cur_test_run.main_test = profiler_cb;
980 churn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
986 (void) GNUNET_TESTBED_test_run ("test-rps-multipeer",
992 if (NULL != churn_task)
993 GNUNET_SCHEDULER_cancel (churn_task);
995 return cur_test_run.eval_cb();
998 /* end of test_rps_multipeer.c */