+ GNUNET_OK);
+}
+
+
+/**
+ * Handle a PUSH message from another peer.
+ *
+ * Check the proof of work and store the PeerID
+ * in the temporary list for pushed PeerIDs.
+ *
+ * @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_push (void *cls,
+ struct GNUNET_CADET_Channel *channel,
+ void **channel_ctx,
+ const struct GNUNET_MessageHeader *msg)
+{
+ const struct GNUNET_PeerIdentity *peer;
+
+ // (check the proof of work)
+
+ peer = (const 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, "PUSH received (%s)\n", GNUNET_i2s (peer));
+
+ #ifdef ENABLE_MALICIOUS
+ struct AttackedPeer *tmp_att_peer;
+
+ tmp_att_peer = GNUNET_new (struct AttackedPeer);
+ memcpy (&tmp_att_peer->peer_id, peer, sizeof (struct GNUNET_PeerIdentity));
+ if (1 == mal_type)
+ { /* Try to maximise representation */
+ if (NULL == att_peer_set)
+ att_peer_set = GNUNET_CONTAINER_multipeermap_create (1, GNUNET_NO);
+ if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (att_peer_set,
+ peer))
+ {
+ GNUNET_CONTAINER_DLL_insert (att_peers_head,
+ att_peers_tail,
+ tmp_att_peer);
+ add_peer_array_to_set (peer, 1, att_peer_set);
+ }
+ return GNUNET_OK;
+ }
+
+
+ else if (2 == mal_type)
+ { /* We attack one single well-known peer - simply ignore */
+ return GNUNET_OK;
+ }
+
+ #endif /* ENABLE_MALICIOUS */
+
+ /* Add the sending peer to the push_list */
+ if (GNUNET_NO == in_arr (push_list, push_list_size, peer))
+ GNUNET_array_append (push_list, push_list_size, *peer);
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Handle PULL REQUEST request message from another peer.
+ *
+ * Reply with the gossip list of PeerIDs.
+ *
+ * @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_request (void *cls,
+ struct GNUNET_CADET_Channel *channel,
+ void **channel_ctx,
+ const struct GNUNET_MessageHeader *msg)
+{
+ struct GNUNET_PeerIdentity *peer;
+
+ peer = (struct GNUNET_PeerIdentity *)
+ GNUNET_CADET_channel_get_info (channel,
+ GNUNET_CADET_OPTION_PEER);
+ // FIXME wait for cadet to change this function
+
+ #ifdef ENABLE_MALICIOUS
+ if (1 == 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 (GNUNET_YES == GNUNET_CRYPTO_cmp_peer_identity (&attacked_peer, peer))
+ {
+ send_pull_reply (peer, mal_peers, num_mal_peers);
+ }
+ return GNUNET_OK;
+ }
+ #endif /* ENABLE_MALICIOUS */
+
+ send_pull_reply (peer, gossip_list, gossip_list_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)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "PULL REPLY received\n");
+
+ 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;
+
+ /* 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);
+
+ if (GNUNET_YES == get_peer_flag (sender_ctx, PULL_REPLY_PENDING))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_OK;
+ }
+
+
+ /* Do actual logic */
+ peers = (struct GNUNET_PeerIdentity *) &msg[1];
+ for (i = 0 ; i < ntohl (in_msg->num_peers) ; i++)
+ {
+ peer_ctx = get_peer_ctx (peer_map, &peers[i]);
+ if (GNUNET_YES == get_peer_flag (peer_ctx, VALID)
+ || NULL != peer_ctx->send_channel
+ || NULL != peer_ctx->recv_channel)
+ {
+ if (GNUNET_NO == in_arr (pull_list, pull_list_size, &peers[i])
+ && 0 != GNUNET_CRYPTO_cmp_peer_identity (&own_identity, &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);
+ rem_from_list (&pending_pull_reply_list, &pending_pull_reply_list_size, sender);
+
+ 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;