+static void
+manage_service_wrapper (unsigned int i, unsigned int j, int delta,
+ double prob_go_on_off)
+{
+ struct OpListEntry *entry;
+ uint32_t prob;
+
+ prob = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+ UINT32_MAX);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "%u. selected peer (%u: %s) is %s.\n",
+ i,
+ j,
+ GNUNET_i2s (rps_peers[j].peer_id),
+ (0 > delta) ? "online" : "offline");
+ if (prob < prob_go_on_off * UINT32_MAX)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "%s goes %s\n",
+ GNUNET_i2s (rps_peers[j].peer_id),
+ (0 > delta) ? "offline" : "online");
+
+ if (0 > delta)
+ cancel_pending_req_rep (&rps_peers[j]);
+ entry = make_oplist_entry ();
+ entry->delta = delta;
+ entry->index = j;
+ entry->op = GNUNET_TESTBED_peer_manage_service (NULL,
+ testbed_peers[j],
+ "rps",
+ &churn_cb,
+ entry,
+ (0 > delta) ? 0 : 1);
+ }
+}
+
+static void
+churn (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ unsigned int i;
+ unsigned int j;
+ double portion_online;
+ unsigned int *permut;
+ double prob_go_offline;
+ double portion_go_online;
+ double portion_go_offline;
+
+ /* Compute the probability for an online peer to go offline
+ * this round */
+ portion_online = num_peers_online * 1.0 / num_peers;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Portion online: %f\n",
+ portion_online);
+ portion_go_online = ((1 - portion_online) * .5 * .66);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Portion that should go online: %f\n",
+ portion_go_online);
+ portion_go_offline = (portion_online + portion_go_online) - .75;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Portion that probably goes offline: %f\n",
+ portion_go_offline);
+ prob_go_offline = portion_go_offline / (portion_online * .5);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Probability of a selected online peer to go offline: %f\n",
+ prob_go_offline);
+
+ permut = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
+ (unsigned int) num_peers);
+
+ /* Go over 50% randomly chosen peers */
+ for (i = 0; i < .5 * num_peers; i++)
+ {
+ j = permut[i];
+
+ /* If online, shut down with certain probability */
+ if (GNUNET_YES == rps_peers[j].online)
+ {
+ manage_service_wrapper (i, j, -1, prob_go_offline);
+ }
+
+ /* If offline, restart with certain probability */
+ else if (GNUNET_NO == rps_peers[j].online)
+ {
+ manage_service_wrapper (i, j, 1, 0.66);
+ }
+ }
+
+ GNUNET_free (permut);
+
+ churn_task = GNUNET_SCHEDULER_add_delayed (
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
+ churn,
+ NULL);
+}
+
+
+/**
+ * Initialise given RPSPeer
+ */
+static void profiler_init_peer (struct RPSPeer *rps_peer)
+{
+ if (num_peers - 1 == rps_peer->index)
+ rps_peer->num_ids_to_request = cur_test_run.num_requests;
+}
+
+
+/**
+ * Callback to call on receipt of a reply
+ *
+ * @param cls closure
+ * @param n number of peers
+ * @param recv_peers the received peers
+ */
+static void
+profiler_reply_handle (void *cls,
+ uint64_t n,
+ const struct GNUNET_PeerIdentity *recv_peers)
+{
+ struct RPSPeer *rps_peer;
+ struct RPSPeer *rcv_rps_peer;
+ char *file_name;
+ char *file_name_dh;
+ unsigned int i;
+ struct PendingReply *pending_rep = (struct PendingReply *) cls;
+
+ rps_peer = pending_rep->rps_peer;
+ file_name = "/tmp/rps/received_ids";
+ file_name_dh = "/tmp/rps/diehard_input";
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "[%s] got %" PRIu64 " peers:\n",
+ GNUNET_i2s (rps_peer->peer_id),
+ n);
+ for (i = 0; i < n; i++)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "%u: %s\n",
+ i,
+ GNUNET_i2s (&recv_peers[i]));
+ tofile (file_name,
+ "%s\n",
+ GNUNET_i2s_full (&recv_peers[i]));
+ rcv_rps_peer = GNUNET_CONTAINER_multipeermap_get (peer_map, &recv_peers[i]);
+ tofile (file_name_dh,
+ "%" PRIu32 "\n",
+ (uint32_t) rcv_rps_peer->index);
+ }
+ default_reply_handle (cls, n, recv_peers);
+}
+
+
+static void
+profiler_cb (struct RPSPeer *rps_peer)
+{
+ /* Start churn */
+ if (NULL == churn_task)
+ {
+ churn_task = GNUNET_SCHEDULER_add_delayed (
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
+ churn,
+ NULL);
+ }
+
+ /* Only request peer ids at one peer.
+ * (It's the before-last because last one is target of the focussed attack.)
+ */
+ if (eval_peer == rps_peer)
+ schedule_missing_requests (rps_peer);
+}
+
+/**
+ * Function called from #profiler_eval with a filename.
+ *
+ * @param cls closure
+ * @param filename complete filename (absolute path)
+ * @return #GNUNET_OK to continue to iterate,
+ * #GNUNET_NO to stop iteration with no error,
+ * #GNUNET_SYSERR to abort iteration with error!
+ */
+int
+file_name_cb (void *cls, const char *filename)
+{
+ if (NULL != strstr (filename, "sampler_el"))
+ {
+ struct RPS_SamplerElement *s_elem;
+ struct GNUNET_CRYPTO_AuthKey auth_key;
+ const char *key_char;
+ uint32_t i;
+
+ key_char = filename + 20; /* Length of "/tmp/rps/sampler_el-" */
+ tofile (filename, "--------------------------\n");
+
+ auth_key = string_to_auth_key (key_char);
+ s_elem = RPS_sampler_elem_create ();
+ RPS_sampler_elem_set (s_elem, auth_key);
+
+ for (i = 0; i < num_peers; i++)
+ {
+ RPS_sampler_elem_next (s_elem, &rps_peer_ids[i]);
+ }
+ }
+ return GNUNET_OK;
+}
+
+/**
+ * This is run after the test finished.
+ *
+ * Compute all perfect samples.
+ */
+int
+profiler_eval (void)
+{
+ /* Compute perfect sample for each sampler element */
+ if (-1 == GNUNET_DISK_directory_scan ("/tmp/rps/", file_name_cb, NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Scan of directory failed\n");
+ }
+
+ return evaluate ();
+}
+
+