+
+/**
+ * How long should we delay a message to go the given number of
+ * matching bits?
+ *
+ * @param matching_bits number of matching bits to consider
+ */
+static double
+get_matching_bits_delay (uint32_t matching_bits)
+{
+ /* Calculated as: S + f/2 - (f / pi) * (atan(x - p')) */
+ // S is next_timestamp (ignored in return value)
+ // f is frequency (gnunet_nse_interval)
+ // x is matching_bits
+ // p' is current_size_estimate
+ return ((double) gnunet_nse_interval.rel_value / (double) 2.0) -
+ ((gnunet_nse_interval.rel_value / M_PI) *
+ atan (matching_bits - current_size_estimate));
+}
+
+
+/**
+ * What delay randomization should we apply for a given number of matching bits?
+ *
+ * @param matching_bits number of matching bits
+ * @return random delay to apply
+ */
+static struct GNUNET_TIME_Relative
+get_delay_randomization (uint32_t matching_bits)
+{
+#if USE_RANDOM_DELAYS
+ struct GNUNET_TIME_Relative ret;
+ uint32_t i;
+ double d;
+
+ d = get_matching_bits_delay (matching_bits);
+ i = (uint32_t) (d / (double) (hop_count_max + 1));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Randomizing flood using latencies up to %u ms\n",
+ (unsigned int) i);
+ ret.rel_value = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, i + 1);
+ return ret;
+#else
+ return GNUNET_TIME_UNIT_ZERO;
+#endif
+}
+
+
+/**
+ * Get the number of matching bits that the given timestamp has to the given peer ID.
+ *
+ * @param timestamp time to generate key
+ * @param id peer identity to compare with
+ * @return number of matching bits
+ */
+static uint32_t
+get_matching_bits (struct GNUNET_TIME_Absolute timestamp,
+ const struct GNUNET_PeerIdentity *id)
+{
+ struct GNUNET_HashCode timestamp_hash;
+
+ GNUNET_CRYPTO_hash (×tamp.abs_value, sizeof (timestamp.abs_value),
+ ×tamp_hash);
+ return GNUNET_CRYPTO_hash_matching_bits (×tamp_hash, &id->hashPubKey);
+}
+
+
+/**
+ * Get the transmission delay that should be applied for a
+ * particular round.
+ *
+ * @param round_offset -1 for the previous round (random delay between 0 and 50ms)
+ * 0 for the current round (based on our proximity to time key)
+ * @return delay that should be applied
+ */
+static struct GNUNET_TIME_Relative
+get_transmit_delay (int round_offset)
+{
+ struct GNUNET_TIME_Relative ret;
+ struct GNUNET_TIME_Absolute tgt;
+ double dist_delay;
+ uint32_t matching_bits;
+
+ switch (round_offset)
+ {
+ case -1:
+ /* previous round is randomized between 0 and 50 ms */
+#if USE_RANDOM_DELAYS
+ ret.rel_value = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, 50);
+#else
+ ret = GNUNET_TIME_UNIT_ZERO;
+#endif
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmitting previous round behind schedule in %llu ms\n",
+ (unsigned long long) ret.rel_value);
+ return ret;
+ case 0:
+ /* current round is based on best-known matching_bits */
+ matching_bits =
+ ntohl (size_estimate_messages[estimate_index].matching_bits);
+ dist_delay = get_matching_bits_delay (matching_bits);
+ dist_delay += get_delay_randomization (matching_bits).rel_value;
+ ret.rel_value = (uint64_t) dist_delay;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "For round %llu, delay for %u matching bits is %llu ms\n",
+ (unsigned long long) current_timestamp.abs_value,
+ (unsigned int) matching_bits,
+ (unsigned long long) ret.rel_value);
+ /* now consider round start time and add delay to it */
+ tgt = GNUNET_TIME_absolute_add (current_timestamp, ret);
+ return GNUNET_TIME_absolute_get_remaining (tgt);
+ }
+ GNUNET_break (0);
+ return GNUNET_TIME_UNIT_FOREVER_REL;
+}
+
+
+/**
+ * Task that triggers a NSE P2P transmission.
+ *
+ * @param cls the 'struct NSEPeerEntry'
+ * @param tc scheduler context
+ */
+static void
+transmit_task_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+