+ unsigned int view_size;
+
+ peer = (struct GNUNET_PeerIdentity *)
+ GNUNET_CADET_channel_get_info (channel,
+ GNUNET_CADET_OPTION_PEER);
+ // FIXME wait for cadet to change this function
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "PULL REQUEST received (%s)\n", GNUNET_i2s (peer));
+
+ #ifdef ENABLE_MALICIOUS
+ if (1 == mal_type
+ || 3 == mal_type)
+ { /* Try to maximise representation */
+ send_pull_reply (peer, mal_peers, num_mal_peers);
+ return GNUNET_OK;
+ }
+
+ else if (2 == mal_type)
+ { /* Try to partition network */
+ if (0 == GNUNET_CRYPTO_cmp_peer_identity (&attacked_peer, peer))
+ {
+ send_pull_reply (peer, mal_peers, num_mal_peers);
+ }
+ return GNUNET_OK;
+ }
+ #endif /* ENABLE_MALICIOUS */
+
+ view_size = GNUNET_CONTAINER_multipeermap_size (view);
+ generate_view_array (view_size);
+
+ send_pull_reply (peer, view_array, view_size);
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Handle PULL REPLY message from another peer.
+ *
+ * Check whether we sent a corresponding request and
+ * whether this reply is the first one.
+ *
+ * @param cls Closure
+ * @param channel The channel the PUSH was received over
+ * @param channel_ctx The context associated with this channel
+ * @param msg The message header
+ */
+ static int
+handle_peer_pull_reply (void *cls,
+ struct GNUNET_CADET_Channel *channel,
+ void **channel_ctx,
+ const struct GNUNET_MessageHeader *msg)
+{
+ struct GNUNET_RPS_P2P_PullReplyMessage *in_msg;
+ struct GNUNET_PeerIdentity *peers;
+ struct PeerContext *peer_ctx;
+ struct GNUNET_PeerIdentity *sender;
+ struct PeerContext *sender_ctx;
+ struct PeerOutstandingOp out_op;
+ uint32_t i;
+#ifdef ENABLE_MALICIOUS
+ struct AttackedPeer *tmp_att_peer;
+#endif /* ENABLE_MALICIOUS */
+
+ /* Check for protocol violation */
+ if (sizeof (struct GNUNET_RPS_P2P_PullReplyMessage) > ntohs (msg->size))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ in_msg = (struct GNUNET_RPS_P2P_PullReplyMessage *) msg;
+ if ((ntohs (msg->size) - sizeof (struct GNUNET_RPS_P2P_PullReplyMessage)) /
+ sizeof (struct GNUNET_PeerIdentity) != ntohl (in_msg->num_peers))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ "message says it sends %" PRIu64 " peers, have space for %i peers\n",
+ ntohl (in_msg->num_peers),
+ (ntohs (msg->size) - sizeof (struct GNUNET_RPS_P2P_PullReplyMessage)) /
+ sizeof (struct GNUNET_PeerIdentity));
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ sender = (struct GNUNET_PeerIdentity *) GNUNET_CADET_channel_get_info (
+ (struct GNUNET_CADET_Channel *) channel, GNUNET_CADET_OPTION_PEER);
+ // Guess simply casting isn't the nicest way...
+ // FIXME wait for cadet to change this function
+ sender_ctx = get_peer_ctx (peer_map, sender);
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "PULL REPLY received (%s)\n", GNUNET_i2s (sender));
+
+ if (GNUNET_YES != get_peer_flag (sender_ctx, PULL_REPLY_PENDING))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Received a pull reply from a peer we didn't request one from!\n");
+ GNUNET_break_op (0);
+ return GNUNET_OK;
+ }
+
+
+ #ifdef ENABLE_MALICIOUS
+ // We shouldn't even receive pull replies as we're not sending
+ if (2 == mal_type)
+ return GNUNET_OK;
+ #endif /* ENABLE_MALICIOUS */
+
+ /* Do actual logic */
+ peers = (struct GNUNET_PeerIdentity *) &in_msg[1];
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "PULL REPLY received, got following %u peers:\n",
+ ntohl (in_msg->num_peers));
+
+ for (i = 0 ; i < ntohl (in_msg->num_peers) ; i++)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "%u. %s\n",
+ i,
+ GNUNET_i2s (&peers[i]));
+
+ #ifdef ENABLE_MALICIOUS
+ if (1 == mal_type
+ || 3 == mal_type)
+ { /* Add attacked peer to local list */
+ // TODO check if we sent a request and this was the first reply
+ if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (att_peer_set,
+ &peers[i])
+ && GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (mal_peer_set,
+ &peers[i])
+ && 0 != GNUNET_CRYPTO_cmp_peer_identity (&peers[i],
+ &own_identity))
+ {
+ tmp_att_peer = GNUNET_new (struct AttackedPeer);
+ tmp_att_peer->peer_id = peers[i];
+ GNUNET_CONTAINER_DLL_insert (att_peers_head,
+ att_peers_tail,
+ tmp_att_peer);
+ add_peer_array_to_set (&peers[i], 1, att_peer_set);
+ }
+ continue;
+ }
+ #endif /* ENABLE_MALICIOUS */
+ if (0 != GNUNET_CRYPTO_cmp_peer_identity (&own_identity,
+ &peers[i]))
+ {
+ peer_ctx = get_peer_ctx (peer_map, &peers[i]);
+ if (GNUNET_YES == get_peer_flag (peer_ctx, VALID))
+ {
+ if (GNUNET_NO == in_arr (pull_list, pull_list_size, &peers[i]))
+ GNUNET_array_append (pull_list, pull_list_size, peers[i]);
+ }
+ else if (GNUNET_NO == insert_in_pull_list_scheduled (peer_ctx))
+ {
+ out_op.op = insert_in_pull_list;
+ out_op.op_cls = NULL;
+ GNUNET_array_append (peer_ctx->outstanding_ops,
+ peer_ctx->num_outstanding_ops,
+ out_op);
+ check_peer_live (peer_ctx);
+ }
+ }
+ }
+
+ unset_peer_flag (sender_ctx, PULL_REPLY_PENDING);
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Compute a random delay.
+ * A uniformly distributed value between mean + spread and mean - spread.
+ *
+ * For example for mean 4 min and spread 2 the minimum is (4 min - (1/2 * 4 min))
+ * It would return a random value between 2 and 6 min.
+ *
+ * @param mean the mean
+ * @param spread the inverse amount of deviation from the mean
+ */
+static struct GNUNET_TIME_Relative
+compute_rand_delay (struct GNUNET_TIME_Relative mean, unsigned int spread)
+{
+ struct GNUNET_TIME_Relative half_interval;
+ struct GNUNET_TIME_Relative ret;
+ unsigned int rand_delay;
+ unsigned int max_rand_delay;
+
+ if (0 == spread)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Not accepting spread of 0\n");
+ GNUNET_break (0);
+ }
+
+ /* Compute random time value between spread * mean and spread * mean */
+ half_interval = GNUNET_TIME_relative_divide (mean, spread);
+
+ max_rand_delay = GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us / mean.rel_value_us * (2/spread);
+ /**
+ * Compute random value between (0 and 1) * round_interval
+ * via multiplying round_interval with a 'fraction' (0 to value)/value
+ */
+ rand_delay = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, max_rand_delay);
+ ret = GNUNET_TIME_relative_multiply (mean, rand_delay);
+ ret = GNUNET_TIME_relative_divide (ret, max_rand_delay);
+ ret = GNUNET_TIME_relative_add (ret, half_interval);
+
+ if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == ret.rel_value_us)
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Returning FOREVER_REL\n");
+
+ return ret;
+}
+
+
+/**
+ * Send single pull request
+ *
+ * @param peer_id the peer to send the pull request to.
+ */
+static void
+send_pull_request (struct GNUNET_PeerIdentity *peer_id)
+{
+ struct GNUNET_MQ_Envelope *ev;