/**
 * Function called for all addresses and peers to find the minimum and
 * maximum (averaged) values for a given quality property.  Given
 * those, we can then calculate the normalized score.
 *
 * @param cls the `struct PropertyRange`
 * @param h which peer are we looking at (ignored)
 * @param k the address for that peer
 * @return #GNUNET_OK (continue to iterate)
 */
static int
find_min_max_it (void *cls,
                 const struct GNUNET_PeerIdentity *h,
                 void *k)
{
  struct PropertyRange *pr = cls;
  const struct ATS_Address *a = k;

  pr->max.utilization_out = GNUNET_MAX (pr->max.utilization_out,
                                        a->properties.utilization_out);
  pr->max.utilization_in = GNUNET_MAX (pr->max.utilization_in,
                                       a->properties.utilization_in);
  pr->max.distance = GNUNET_MAX (pr->max.distance,
                                 a->properties.distance);
  pr->max.delay = GNUNET_TIME_relative_max (pr->max.delay,
                                            a->properties.delay);
  pr->min.utilization_out = GNUNET_MIN (pr->min.utilization_out,
                                        a->properties.utilization_out);
  pr->min.utilization_in = GNUNET_MIN (pr->min.utilization_in,
                                       a->properties.utilization_in);
  pr->min.distance = GNUNET_MIN (pr->min.distance,
                                 a->properties.distance);
  pr->min.delay = GNUNET_TIME_relative_min (pr->min.delay,
                                            a->properties.delay);
  return GNUNET_OK;
}
Example #2
0
/**
 * Store content in DHT.
 *
 * @param cls closure
 * @param key key for the content
 * @param size number of bytes in data
 * @param data content stored
 * @param type type of the content
 * @param priority priority of the content
 * @param anonymity anonymity-level for the content
 * @param expiration expiration time for the content
 * @param uid unique identifier for the datum;
 *        maybe 0 if no unique identifier is available
 */
static void
process_dht_put_content (void *cls,
			 const struct GNUNET_HashCode * key,
			 size_t size,
                         const void *data,
			 enum GNUNET_BLOCK_Type type,
                         uint32_t priority, uint32_t anonymity,
                         struct GNUNET_TIME_Absolute expiration, uint64_t uid)
{
  struct PutOperator *po = cls;

  po->dht_qe = NULL;
  if (key == NULL)
  {
    po->zero_anonymity_count_estimate = po->current_offset - 1;
    po->current_offset = 0;
    po->dht_task = GNUNET_SCHEDULER_add_now (&delay_dht_put_task, po);
    return;
  }
  po->zero_anonymity_count_estimate =
      GNUNET_MAX (po->current_offset, po->zero_anonymity_count_estimate);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Retrieved block `%s' of type %u for DHT PUT\n", GNUNET_h2s (key),
              type);
  po->dht_put = GNUNET_DHT_put (GSF_dht, key, DEFAULT_PUT_REPLICATION,
				GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, type, size, data,
				expiration, GNUNET_TIME_UNIT_FOREVER_REL,
				&delay_dht_put_blocks, po);
}
Example #3
0
/**
 * Compute the MAX of two bandwidth values.
 *
 * @param b1 first value
 * @param b2 second value
 * @return the min of b1 and b2
 */
struct GNUNET_BANDWIDTH_Value32NBO
GNUNET_BANDWIDTH_value_max (struct GNUNET_BANDWIDTH_Value32NBO b1,
                            struct GNUNET_BANDWIDTH_Value32NBO b2)
{
  return
      GNUNET_BANDWIDTH_value_init (GNUNET_MAX
                                   (ntohl (b1.value__),
                                    ntohl (b2.value__)));
}
/**
 * Callback that is called when network size estimate is updated.
 *
 * @param cls closure
 * @param timestamp time when the estimate was received from the server (or created by the server)
 * @param logestimate the log(Base 2) value of the current network size estimate
 * @param std_dev standard deviation for the estimate
 *
 */
static void
update_network_size_estimate (void *cls, struct GNUNET_TIME_Absolute timestamp,
                              double logestimate, double std_dev)
{
  GNUNET_STATISTICS_update (GDS_stats,
                            gettext_noop ("# Network size estimates received"),
                            1, GNUNET_NO);
  /* do not allow estimates < 0.5 */
  log_of_network_size_estimate = GNUNET_MAX (0.5, logestimate);
}
Example #5
0
/**
 * Update our flood message to be sent (and our timestamps).
 *
 * @param cls unused
 */
static void
update_flood_message (void *cls)
{
  struct GNUNET_TIME_Relative offset;
  unsigned int i;

  flood_task = NULL;
  offset = GNUNET_TIME_absolute_get_remaining (next_timestamp);
  if (0 != offset.rel_value_us)
  {
    /* somehow run early, delay more */
    flood_task =
        GNUNET_SCHEDULER_add_delayed (offset,
				      &update_flood_message,
				      NULL);
    return;
  }
  estimate_index = (estimate_index + 1) % HISTORY_SIZE;
  if (estimate_count < HISTORY_SIZE)
    estimate_count++;
  current_timestamp = next_timestamp;
  next_timestamp =
      GNUNET_TIME_absolute_add (current_timestamp, gnunet_nse_interval);
  if ( (current_timestamp.abs_value_us ==
	GNUNET_TIME_absolute_ntoh (next_message.timestamp).abs_value_us) &&
       (get_matching_bits (current_timestamp, &my_identity) <
	ntohl(next_message.matching_bits)) )
  {
    /* we received a message for this round way early, use it! */
    size_estimate_messages[estimate_index] = next_message;
    size_estimate_messages[estimate_index].hop_count =
        htonl (1 + ntohl (next_message.hop_count));
  }
  else
    setup_flood_message (estimate_index,
			 current_timestamp);
  next_message.matching_bits = htonl (0);       /* reset for 'next' round */
  hop_count_max = 0;
  for (i = 0; i < HISTORY_SIZE; i++)
    hop_count_max = GNUNET_MAX (ntohl (size_estimate_messages[i].hop_count),
				hop_count_max);
  GNUNET_CONTAINER_multipeermap_iterate (peers,
                                         &schedule_current_round,
                                         NULL);
  flood_task
    = GNUNET_SCHEDULER_add_at (next_timestamp,
                               &update_flood_message,
                               NULL);
}
/**
 * Solicit messages for transmission, starting with those of the highest
 * priority.
 *
 * @param session session to solict messages for
 * @param msize how many bytes do we have already
 */
static void
solicit_messages (struct Session *session,
                  size_t msize)
{
  struct GSC_ClientActiveRequest *car;
  struct GSC_ClientActiveRequest *nxt;
  size_t so_size;
  enum GNUNET_CORE_Priority pmax;

  so_size = msize;
  pmax = GNUNET_CORE_PRIO_BACKGROUND;
  for (car = session->active_client_request_head; NULL != car; car = car->next)
  {
    if (GNUNET_YES == car->was_solicited)
      continue;
    pmax = GNUNET_MAX (pmax, car->priority);
  }
  nxt = session->active_client_request_head;
  while (NULL != (car = nxt))
  {
    nxt = car->next;
    if (car->priority < pmax)
      continue;
    if (so_size + car->msize > GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
      break;
    so_size += car->msize;
    if (GNUNET_YES == car->was_solicited)
      continue;
    car->was_solicited = GNUNET_YES;
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Soliciting message with priority %u\n",
                car->priority);
    GSC_CLIENTS_solicit_request (car);
    /* The above call may *dequeue* requests and thereby
       clobber 'nxt'. Hence we need to restart from the
       head of the list. */
    nxt = session->active_client_request_head;
    so_size = msize;
  }
}
/**
 * Consider using the path @a p for the tunnel @a t.
 * The tunnel destination is at offset @a off in path @a p.
 *
 * @param cls our tunnel
 * @param path a path to our destination
 * @param off offset of the destination on path @a path
 * @return #GNUNET_YES (should keep iterating)
 */
static int
consider_path_cb (void *cls,
                  struct CadetPeerPath *path,
                  unsigned int off)
{
  struct CadetTunnel *t = cls;
  unsigned int min_length = UINT_MAX;
  GNUNET_CONTAINER_HeapCostType max_desire = 0;
  struct CadetTConnection *ct;

  /* Check if we care about the new path. */
  for (ct = t->connection_head;
       NULL != ct;
       ct = ct->next)
  {
    struct CadetPeerPath *ps;

    ps = GCC_get_path (ct->cc);
    if (ps == path)
      return GNUNET_YES; /* duplicate */
    min_length = GNUNET_MIN (min_length,
                             GCPP_get_length (ps));
    max_desire = GNUNET_MAX (max_desire,
                             GCPP_get_desirability (ps));
  }

  /* FIXME: not sure we should really just count
     'num_connections' here, as they may all have
     consistently failed to connect. */

  /* We iterate by increasing path length; if we have enough paths and
     this one is more than twice as long than what we are currently
     using, then ignore all of these super-long ones! */
  if ( (t->num_connections > DESIRED_CONNECTIONS_PER_TUNNEL) &&
       (min_length * 2 < off) )
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Ignoring paths of length %u, they are way too long.\n",
                min_length * 2);
    return GNUNET_NO;
  }
  /* If we have enough paths and this one looks no better, ignore it. */
  if ( (t->num_connections >= DESIRED_CONNECTIONS_PER_TUNNEL) &&
       (min_length < GCPP_get_length (path)) &&
       (max_desire > GCPP_get_desirability (path)) )
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Ignoring path (%u/%llu) to %s, got something better already.\n",
                GCPP_get_length (path),
                (unsigned long long) GCPP_get_desirability (path),
                GCP_2s (t->destination));
    return GNUNET_YES;
  }

  /* Path is interesting (better by some metric, or we don't have
     enough paths yet). */
  ct = GNUNET_new (struct CadetTConnection);
  ct->created = GNUNET_TIME_absolute_get ();
  ct->t = t;
  ct->cc = GCC_create (t->destination,
                       path,
                       ct,
                       &connection_ready_cb,
                       t);
  /* FIXME: schedule job to kill connection (and path?)  if it takes
     too long to get ready! (And track performance data on how long
     other connections took with the tunnel!)
     => Note: to be done within 'connection'-logic! */
  GNUNET_CONTAINER_DLL_insert (t->connection_head,
                               t->connection_tail,
                               ct);
  t->num_connections++;
  return GNUNET_YES;
}
/**
 * Try to perform a transmission on the given session. Will solicit
 * additional messages if the 'sme' queue is not full enough or has
 * only low-priority messages.
 *
 * @param session session to transmit messages from
 */
static void
try_transmission (struct Session *session)
{
  struct SessionMessageEntry *pos;
  size_t msize;
  struct GNUNET_TIME_Absolute now;
  struct GNUNET_TIME_Absolute min_deadline;
  enum GNUNET_CORE_Priority maxp;
  enum GNUNET_CORE_Priority maxpc;
  struct GSC_ClientActiveRequest *car;
  int excess;

  if (GNUNET_YES != session->ready_to_transmit)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Already ready to transmit, not evaluating queue\n");
    return;
  }
  msize = 0;
  min_deadline = GNUNET_TIME_UNIT_FOREVER_ABS;
  /* if the peer has excess bandwidth, background traffic is allowed,
     otherwise not */
  if (MAX_ENCRYPTED_MESSAGE_QUEUE_SIZE <=
      GSC_NEIGHBOURS_get_queue_size (&session->peer))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Transmission queue already very long, waiting...\n");
    return; /* queue already too long */
  }
  excess = GSC_NEIGHBOURS_check_excess_bandwidth (&session->peer);
  if (GNUNET_YES == excess)
    maxp = GNUNET_CORE_PRIO_BACKGROUND;
  else
    maxp = GNUNET_CORE_PRIO_BEST_EFFORT;
  /* determine highest priority of 'ready' messages we already solicited from clients */
  pos = session->sme_head;
  while ((NULL != pos) &&
         (msize + pos->size <= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE))
  {
    GNUNET_assert (pos->size < GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE);
    msize += pos->size;
    maxp = GNUNET_MAX (maxp, pos->priority);
    min_deadline = GNUNET_TIME_absolute_min (min_deadline,
                                             pos->deadline);
    pos = pos->next;
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Calculating transmission set with %u priority (%s) and %s earliest deadline\n",
              maxp,
              (GNUNET_YES == excess) ? "excess bandwidth" : "limited bandwidth",
              GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (min_deadline),
                                                      GNUNET_YES));

  if (maxp < GNUNET_CORE_PRIO_CRITICAL_CONTROL)
  {
    /* if highest already solicited priority from clients is not critical,
       check if there are higher-priority messages to be solicited from clients */
    if (GNUNET_YES == excess)
      maxpc = GNUNET_CORE_PRIO_BACKGROUND;
    else
      maxpc = GNUNET_CORE_PRIO_BEST_EFFORT;
    for (car = session->active_client_request_head; NULL != car; car = car->next)
    {
      if (GNUNET_YES == car->was_solicited)
        continue;
      maxpc = GNUNET_MAX (maxpc,
                          car->priority);
    }
    if (maxpc > maxp)
    {
      /* we have messages waiting for solicitation that have a higher
         priority than those that we already accepted; solicit the
         high-priority messages first */
      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                  "Soliciting messages based on priority (%u > %u)\n",
                  maxpc,
                  maxp);
      solicit_messages (session, 0);
      return;
    }
  }
  else
  {
    /* never solicit more, we have critical messages to process */
    excess = GNUNET_NO;
    maxpc = GNUNET_CORE_PRIO_BACKGROUND;
  }
  now = GNUNET_TIME_absolute_get ();
  if ( ( (GNUNET_YES == excess) ||
         (maxpc >= GNUNET_CORE_PRIO_BEST_EFFORT) ) &&
       ( (0 == msize) ||
         ( (msize < GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE / 2) &&
           (min_deadline.abs_value_us > now.abs_value_us))) )
  {
    /* not enough ready yet (tiny message & cork possible), or no messages at all,
       and either excess bandwidth or best-effort or higher message waiting at
       client; in this case, we try to solicit more */
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Soliciting messages (excess %d, maxpc %d, message size %u, deadline %s)\n",
                excess,
                maxpc,
                msize,
                GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (min_deadline),
                                                        GNUNET_YES));
    solicit_messages (session,
                      msize);
    if (msize > 0)
    {
      /* if there is data to send, just not yet, make sure we do transmit
       * it once the deadline is reached */
      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                  "Corking until %s\n",
                  GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (min_deadline),
                                                          GNUNET_YES));
      if (NULL != session->cork_task)
        GNUNET_SCHEDULER_cancel (session->cork_task);
      session->cork_task =
          GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (min_deadline),
                                        &pop_cork_task,
                                        session);
    }
    else
    {
      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                  "Queue empty, waiting for solicitations\n");
    }
    return;
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Building combined plaintext buffer to transmit message!\n");
  /* create plaintext buffer of all messages (that fit), encrypt and
     transmit */
  {
    static unsigned long long total_bytes;
    static unsigned int total_msgs;
    char pbuf[msize];           /* plaintext */
    size_t used;

    used = 0;
    while ( (NULL != (pos = session->sme_head)) &&
            (used + pos->size <= msize) )
    {
      memcpy (&pbuf[used], &pos[1], pos->size);
      used += pos->size;
      GNUNET_CONTAINER_DLL_remove (session->sme_head,
                                   session->sme_tail,
                                   pos);
      GNUNET_free (pos);
    }
    /* compute average payload size */
    total_bytes += used;
    total_msgs++;
    if (0 == total_msgs)
    {
      /* 2^32 messages, wrap around... */
      total_msgs = 1;
      total_bytes = used;
    }
    GNUNET_STATISTICS_set (GSC_stats,
                           "# avg payload per encrypted message",
                           total_bytes / total_msgs,
                           GNUNET_NO);
    /* now actually transmit... */
    session->ready_to_transmit = GNUNET_NO;
    GSC_KX_encrypt_and_transmit (session->kxinfo,
                                 pbuf,
                                 used);
  }
}
Example #9
0
/**
 * Initialize a message to clients with the current network
 * size estimate.
 *
 * @param em message to fill in
 */
static void
setup_estimate_message (struct GNUNET_NSE_ClientMessage *em)
{
  double mean;
  double sum;
  double std_dev;
  double variance;
  double val;
  double nsize;

#define WEST 1
  /* Weighted incremental algorithm for stddev according to West (1979) */
#if WEST
  double sumweight;
  double weight;
  double q;
  double r;
  double temp;

  mean = 0.0;
  sum = 0.0;
  sumweight = 0.0;
  variance = 0.0;
  for (unsigned int i = 0; i < estimate_count; i++)
  {
    unsigned int j = (estimate_index - i + HISTORY_SIZE) % HISTORY_SIZE;

    val = htonl (size_estimate_messages[j].matching_bits);
    weight = estimate_count + 1 - i;

    temp = weight + sumweight;
    q = val - mean;
    r = q * weight / temp;
    mean += r;
    sum += sumweight * q * r;
    sumweight = temp;
  }
  if (estimate_count > 0)
    variance = (sum / sumweight) * estimate_count / (estimate_count - 1.0);
#else
  /* trivial version for debugging */
  double vsq;

  /* non-weighted trivial version */
  sum = 0.0;
  vsq = 0.0;
  variance = 0.0;
  mean = 0.0;

  for (unsigned int i = 0; i < estimate_count; i++)
  {
    unsigned int j = (estimate_index - i + HISTORY_SIZE) % HISTORY_SIZE;

    val = htonl (size_estimate_messages[j].matching_bits);
    sum += val;
    vsq += val * val;
  }
  if (0 != estimate_count)
  {
    mean = sum / estimate_count;
    variance = (vsq - mean * sum) / (estimate_count - 1.0);     // terrible for numerical stability...
  }
#endif
  if (variance >= 0)
    std_dev = sqrt (variance);
  else
    std_dev = variance;         /* must be infinity due to estimate_count == 0 */
  current_std_dev = std_dev;
  current_size_estimate = mean;

  em->header.size = htons (sizeof (struct GNUNET_NSE_ClientMessage));
  em->header.type = htons (GNUNET_MESSAGE_TYPE_NSE_ESTIMATE);
  em->reserved = htonl (0);
  em->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
  {
    double se = mean - 0.332747;
    unsigned int j = GNUNET_CONTAINER_multipeermap_size (peers);
    if (0 == j)
      j = 1; /* Avoid log2(0); can only happen if CORE didn't report
		connection to self yet */
    nsize = log2 (j);
    em->size_estimate = GNUNET_hton_double (GNUNET_MAX (se,
							nsize));
    em->std_deviation = GNUNET_hton_double (std_dev);
    GNUNET_STATISTICS_set (stats,
			   "# nodes in the network (estimate)",
			   (uint64_t) pow (2, GNUNET_MAX (se,
							  nsize)),
			   GNUNET_NO);
  }
}
Example #10
0
/**
 * Core handler for size estimate flooding messages.
 *
 * @param cls peer this message is from
 * @param incoming_flood received message
 */
static void
handle_p2p_estimate (void *cls,
		     const struct GNUNET_NSE_FloodMessage *incoming_flood)
{
  struct NSEPeerEntry *peer_entry = cls;
  struct GNUNET_TIME_Absolute ts;
  uint32_t matching_bits;
  unsigned int idx;

#if ENABLE_NSE_HISTOGRAM
  {
    uint64_t t;

    t = GNUNET_TIME_absolute_get().abs_value_us;
    if (NULL != lh)
      GNUNET_TESTBED_LOGGER_write (lh, &t, sizeof (uint64_t));
    if (NULL != histogram)
      GNUNET_BIO_write_int64 (histogram, t);
  }
#endif
  GNUNET_STATISTICS_update (stats,
			    "# flood messages received",
			    1,
			    GNUNET_NO);
  matching_bits = ntohl (incoming_flood->matching_bits);
#if DEBUG_NSE
  {
    char origin[5];
    char pred[5];
    struct GNUNET_PeerIdentity os;

    GNUNET_snprintf (origin,
		     sizeof (origin),
		     "%s",
		     GNUNET_i2s (&incoming_flood->origin));
    GNUNET_snprintf (pred,
		     sizeof (pred),
		     "%s",
		     GNUNET_i2s (peer_entry->id));
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Flood at %s from `%s' via `%s' at `%s' with bits %u\n",
                GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp)),
                origin,
		pred,
		GNUNET_i2s (&my_identity),
                (unsigned int) matching_bits);
  }
#endif

#if ENABLE_NSE_HISTOGRAM
  peer_entry->received_messages++;
  if (peer_entry->transmitted_messages > 0 &&
      peer_entry->last_transmitted_size >= matching_bits)
    GNUNET_STATISTICS_update(stats,
			     "# cross messages",
			     1,
			     GNUNET_NO);
#endif

  ts = GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp);
  if (ts.abs_value_us == current_timestamp.abs_value_us)
    idx = estimate_index;
  else if (ts.abs_value_us ==
           current_timestamp.abs_value_us - gnunet_nse_interval.rel_value_us)
    idx = (estimate_index + HISTORY_SIZE - 1) % HISTORY_SIZE;
  else if (ts.abs_value_us == next_timestamp.abs_value_us)
  {
    if (matching_bits <= ntohl (next_message.matching_bits))
      return;         /* ignore, simply too early/late */
    if (GNUNET_YES !=
	verify_message_crypto (incoming_flood))
    {
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  "Peer %s is likely ill-configured!\n",
                  GNUNET_i2s (peer_entry->id));
      GNUNET_break_op (0);
      return;
    }
    next_message = *incoming_flood;
    return;
  }
  else
  {
    GNUNET_STATISTICS_update (stats,
                              "# flood messages discarded (clock skew too large)",
                              1, GNUNET_NO);
    return;
  }
  if (0 == (memcmp (peer_entry->id,
		    &my_identity,
		    sizeof (struct GNUNET_PeerIdentity))))
  {
    /* send to self, update our own estimate IF this also comes from us! */
    if (0 ==
        memcmp (&incoming_flood->origin,
		&my_identity, sizeof (my_identity)))
      update_network_size_estimate ();
    return;
  }
  if (matching_bits ==
      ntohl (size_estimate_messages[idx].matching_bits))
  {
    /* Cancel transmission in the other direction, as this peer clearly has
       up-to-date information already. Even if we didn't talk to this peer in
       the previous round, we should no longer send it stale information as it
       told us about the current round! */
    peer_entry->previous_round = GNUNET_YES;
    if (idx != estimate_index)
    {
      /* do not transmit information for the previous round to this peer
         anymore (but allow current round) */
      return;
    }
    /* got up-to-date information for current round, cancel transmission to
     * this peer altogether */
    if (NULL != peer_entry->transmit_task)
    {
      GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
      peer_entry->transmit_task = NULL;
    }
    return;
  }
  if (matching_bits < ntohl (size_estimate_messages[idx].matching_bits))
  {
    if ( (idx < estimate_index) &&
	 (peer_entry->previous_round == GNUNET_YES))
    {
      peer_entry->previous_round = GNUNET_NO;
    }
    /* push back our result now, that peer is spreading bad information... */
    if (NULL != peer_entry->transmit_task)
      GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
    peer_entry->transmit_task
      = GNUNET_SCHEDULER_add_now (&transmit_task_cb,
				  peer_entry);
    /* Not closer than our most recent message, no need to do work here */
    GNUNET_STATISTICS_update (stats,
                              "# flood messages ignored (had closer already)",
                              1,
			      GNUNET_NO);
    return;
  }
  if (GNUNET_YES !=
      verify_message_crypto (incoming_flood))
  {
    GNUNET_break_op (0);
    return;
  }
  GNUNET_assert (matching_bits >
                 ntohl (size_estimate_messages[idx].matching_bits));
  /* Cancel transmission in the other direction, as this peer clearly has
   * up-to-date information already.
   */
  peer_entry->previous_round = GNUNET_YES;
  if (idx == estimate_index)
  {
    /* cancel any activity for current round */
    if (NULL != peer_entry->transmit_task)
    {
      GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
      peer_entry->transmit_task = NULL;
    }
  }
  size_estimate_messages[idx] = *incoming_flood;
  size_estimate_messages[idx].hop_count =
      htonl (ntohl (incoming_flood->hop_count) + 1);
  hop_count_max =
      GNUNET_MAX (ntohl (incoming_flood->hop_count) + 1,
		  hop_count_max);
  GNUNET_STATISTICS_set (stats,
			 "# estimated network diameter",
			 hop_count_max, GNUNET_NO);

  /* have a new, better size estimate, inform clients */
  update_network_size_estimate ();

  /* flood to rest */
  GNUNET_CONTAINER_multipeermap_iterate (peers,
					 &update_flood_times,
                                         peer_entry);
}