/**
 * Iterator which adds the given address to the set of validated
 * addresses.
 *
 * @param cls original HELLO message
 * @param address the address
 * @param expiration expiration time
 * @return GNUNET_OK (keep the address)
 */
static int
add_valid_address (void *cls, const struct GNUNET_HELLO_Address *address,
                   struct GNUNET_TIME_Absolute expiration)
{
  const struct GNUNET_HELLO_Message *hello = cls;
  struct ValidationEntry *ve;
  struct GNUNET_PeerIdentity pid;
  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;

  if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value == 0)
    return GNUNET_OK;           /* expired */
  if ((GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid)) ||
      (GNUNET_OK != GNUNET_HELLO_get_key (hello, &public_key)))
  {
    GNUNET_break (0);
    return GNUNET_OK;           /* invalid HELLO !? */
  }
  if (0 == memcmp (&GST_my_identity, &pid, sizeof (struct GNUNET_PeerIdentity)))
  {
    /* Peerinfo returned own identity, skip validation */
    return GNUNET_OK;
  }

  ve = find_validation_entry (&public_key, address);
  ve->valid_until = GNUNET_TIME_absolute_max (ve->valid_until, expiration);

  if (GNUNET_SCHEDULER_NO_TASK == ve->revalidation_task)
    ve->revalidation_task = GNUNET_SCHEDULER_add_now (&revalidate_address, ve);
  GNUNET_ATS_address_update (GST_ats, address, NULL, NULL, 0);
  return GNUNET_OK;
}
/**
 * We've received a HELLO, check which addresses are new and trigger
 * validation.
 *
 * @param hello the HELLO we received
 */
void
GST_validation_handle_hello (const struct GNUNET_MessageHeader *hello)
{
  const struct GNUNET_HELLO_Message *hm =
      (const struct GNUNET_HELLO_Message *) hello;
  struct ValidateAddressContext vac;
  struct GNUNET_HELLO_Message *h;

  if ((GNUNET_OK != GNUNET_HELLO_get_id (hm, &vac.pid)) ||
      (GNUNET_OK != GNUNET_HELLO_get_key (hm, &vac.public_key)))
  {
    /* malformed HELLO */
    GNUNET_break (0);
    return;
  }
  if (0 ==
      memcmp (&GST_my_identity, &vac.pid, sizeof (struct GNUNET_PeerIdentity)))
    return;
  /* Add peer identity without addresses to peerinfo service */
  h = GNUNET_HELLO_create (&vac.public_key, NULL, NULL);
  GNUNET_PEERINFO_add_peer (GST_peerinfo, h, NULL, NULL);
#if VERBOSE_VALIDATION
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              _("Adding `%s' without addresses for peer `%s'\n"), "HELLO",
              GNUNET_i2s (&vac.pid));
#endif
  GNUNET_free (h);
  GNUNET_assert (NULL ==
                 GNUNET_HELLO_iterate_addresses (hm, GNUNET_NO,
                                                 &validate_address_iterator,
                                                 &vac));
}
/**
 * We've gotten a HELLO from another peer.  Consider it for
 * advertising.
 *
 * @param hello the HELLO we got
 */
static void
consider_for_advertising (const struct GNUNET_HELLO_Message *hello)
{
  int have_address;
  struct GNUNET_PeerIdentity pid;
  struct GNUNET_TIME_Absolute dt;
  struct GNUNET_HELLO_Message *nh;
  struct Peer *peer;
  uint16_t size;

  if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid))
  {
    GNUNET_break (0);
    return;
  }
  if (0 == memcmp (&pid, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
    return;                     /* that's me! */
  have_address = GNUNET_NO;
  GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &address_iterator,
                                  &have_address);
  if (GNUNET_NO == have_address)
    return;                     /* no point in advertising this one... */
  peer = GNUNET_CONTAINER_multihashmap_get (peers, &pid.hashPubKey);
  if (NULL == peer)
  {
    peer = make_peer (&pid, hello, GNUNET_NO);
  }
  else if (peer->hello != NULL)
  {
    dt = GNUNET_HELLO_equals (peer->hello, hello, GNUNET_TIME_absolute_get ());
    if (dt.abs_value == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value)
      return;                   /* nothing new here */
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Found `%s' from peer `%s' for advertising\n", "HELLO",
              GNUNET_i2s (&pid));
  if (peer->hello != NULL)
  {
    nh = GNUNET_HELLO_merge (peer->hello, hello);
    GNUNET_free (peer->hello);
    peer->hello = nh;
  }
  else
  {
    size = GNUNET_HELLO_size (hello);
    peer->hello = GNUNET_malloc (size);
    memcpy (peer->hello, hello, size);
  }
  if (peer->filter != NULL)
    GNUNET_CONTAINER_bloomfilter_free (peer->filter);
  setup_filter (peer);
  /* since we have a new HELLO to pick from, re-schedule all
   * HELLO requests that are not bound by the HELLO send rate! */
  GNUNET_CONTAINER_multihashmap_iterate (peers, &reschedule_hellos, peer);
}
/**
 * Function that is called on each HELLO file in a particular directory.
 * Try to parse the file and add the HELLO to our list.
 *
 * @param cls pointer to 'unsigned int' to increment for each file, or NULL
 *            if the file is from a read-only, read-once resource directory
 * @param fullname name of the file to parse
 * @return GNUNET_OK (continue iteration)
 */
static int
hosts_directory_scan_callback (void *cls, const char *fullname)
{
  unsigned int *matched = cls;
  struct GNUNET_PeerIdentity identity;
  const char *filename;
  struct HostEntry *entry;
  struct GNUNET_HELLO_Message *hello;

  if (GNUNET_DISK_file_test (fullname) != GNUNET_YES)
    return GNUNET_OK;           /* ignore non-files */
  if (strlen (fullname) < sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded))
  {
    if (NULL != matched)
      remove_garbage (fullname);
    return GNUNET_OK;
  }
  filename =
      &fullname[strlen (fullname) -
                sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1];
  if (filename[-1] != DIR_SEPARATOR)
  {
    if (NULL != matched)
      remove_garbage (fullname);
    return GNUNET_OK;
  }
  if (GNUNET_OK !=
      GNUNET_CRYPTO_hash_from_string (filename, &identity.hashPubKey))
  {
    if (NULL != (hello = read_host_file (filename)))
    {
      entry = GNUNET_malloc (sizeof (struct HostEntry));
      if (GNUNET_OK ==
	  GNUNET_HELLO_get_id (hello,
			       &entry->identity))
      {
	GNUNET_CONTAINER_multihashmap_put (hostmap, &entry->identity.hashPubKey, entry,
					   GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
	entry->hello = hello;
	notify_all (entry);
	return GNUNET_OK;
      }
      GNUNET_free (entry);
    }
    if (NULL != matched)
      remove_garbage (fullname);
    return GNUNET_OK;
  }
  if (NULL != matched)
    (*matched)++;
  add_host_to_known_hosts (&identity);
  return GNUNET_OK;
}
/**
 * This function is called whenever an encrypted HELLO message is
 * received.
 *
 * @param cls closure with the peer identity of the sender
 * @param message the actual HELLO message
 * @return #GNUNET_OK if @a message is well-formed
 *         #GNUNET_SYSERR if @a message is invalid
 */
static int
check_hello (void *cls,
	     const struct GNUNET_HELLO_Message *message)
{
  struct GNUNET_PeerIdentity pid;
    
  if (GNUNET_OK !=
      GNUNET_HELLO_get_id (message,
			   &pid))
  {
    GNUNET_break_op (0);
    return GNUNET_SYSERR;
  }
  return GNUNET_OK;
}
/**
 * Handle HELLO-message.
 *
 * @param cls closure
 * @param client identification of the client
 * @param message the actual message
 */
static void
handle_hello (void *cls, struct GNUNET_SERVER_Client *client,
              const struct GNUNET_MessageHeader *message)
{
  const struct GNUNET_HELLO_Message *hello;
  struct GNUNET_PeerIdentity pid;

  hello = (const struct GNUNET_HELLO_Message *) message;
  if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid))
  {
    GNUNET_break (0);
    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
    return;
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' message received for peer `%4s'\n",
              "HELLO", GNUNET_i2s (&pid));
  bind_address (&pid, hello);
  GNUNET_SERVER_receive_done (client, GNUNET_OK);
}
/**
 * This function is called whenever an encrypted HELLO message is
 * received.
 *
 * @param cls closure with the peer identity of the sender
 * @param message the actual HELLO message
 */
static void
handle_hello (void *cls,
	      const struct GNUNET_HELLO_Message *message)
{
  const struct GNUNET_PeerIdentity *other = cls;
  struct Peer *peer;
  struct GNUNET_PeerIdentity pid;

  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Received encrypted HELLO from peer `%s'",
              GNUNET_i2s (other));
  GNUNET_assert (GNUNET_OK ==
		 GNUNET_HELLO_get_id (message,
				      &pid));
  GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# HELLO messages received"),
                            1,
                            GNUNET_NO);
  peer = GNUNET_CONTAINER_multipeermap_get (peers,
					    &pid);
  if (NULL == peer)
  {
    if ( (GNUNET_YES == friends_only) ||
         (friend_count < minimum_friend_count) )
      return;
  }
  else
  {
    if ( (GNUNET_YES != peer->is_friend) &&
         (GNUNET_YES == friends_only) )
      return;
    if ((GNUNET_YES != peer->is_friend) &&
        (friend_count < minimum_friend_count))
      return;
  }
  if (NULL != oh)
    GNUNET_TRANSPORT_offer_hello_cancel (oh);
  oh = GNUNET_TRANSPORT_offer_hello (cfg,
                                     &message->header,
                                     &done_offer_hello,
                                     NULL);
}
static void
get_hello (void *cb_cls, const struct GNUNET_MessageHeader *message)
{
  struct PeerContext *p = cb_cls;
  struct GNUNET_PeerIdentity hello_id;

  GNUNET_assert (message != NULL);
  GNUNET_assert (GNUNET_OK ==
                 GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *)
                                      message, &hello_id));
  GNUNET_assert (0 == memcmp (&hello_id, &p->id, sizeof (hello_id)));
  GNUNET_free_non_null (p->hello);
  p->hello = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (message);

  if (NULL != p->start_cb)
  {
    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
                     "Peer %u (`%s') successfully started\n", p->no,
                     GNUNET_i2s (&p->id));
    p->start_cb (p, p->cb_cls);
    p->start_cb = NULL;
  }
}
/**
 * This function is called whenever an encrypted HELLO message is
 * received.
 *
 * @param cls closure
 * @param other the other peer involved (sender or receiver, NULL
 *        for loopback messages where we are both sender and receiver)
 * @param message the actual HELLO message
 * @param atsi performance data
 * @param atsi_count number of records in 'atsi'
 * @return GNUNET_OK to keep the connection open,
 *         GNUNET_SYSERR to close it (signal serious error)
 */
static int
handle_encrypted_hello (void *cls, const struct GNUNET_PeerIdentity *other,
                        const struct GNUNET_MessageHeader *message,
                        const struct GNUNET_ATS_Information *atsi,
                        unsigned int atsi_count)
{
  struct Peer *peer;
  struct GNUNET_PeerIdentity pid;

  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received encrypted `%s' from peer `%s'",
              "HELLO", GNUNET_i2s (other));
  if (GNUNET_OK !=
      GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) message, &pid))
  {
    GNUNET_break_op (0);
    return GNUNET_SYSERR;
  }
  GNUNET_STATISTICS_update (stats, gettext_noop ("# HELLO messages received"),
                            1, GNUNET_NO);
  peer = GNUNET_CONTAINER_multihashmap_get (peers, &pid.hashPubKey);
  if (NULL == peer)
  {
    if ((GNUNET_YES == friends_only) || (friend_count < minimum_friend_count))
      return GNUNET_OK;
  }
  else
  {
    if ((GNUNET_YES != peer->is_friend) && (GNUNET_YES == friends_only))
      return GNUNET_OK;
    if ((GNUNET_YES != peer->is_friend) &&
        (friend_count < minimum_friend_count))
      return GNUNET_OK;
  }
  if (transport != NULL)
    GNUNET_TRANSPORT_offer_hello (transport, message, NULL, NULL);
  return GNUNET_OK;
}
Exemple #10
0
/**
 * Function called to obtain the key for a block.
 *
 * @param cls closure
 * @param type block type
 * @param block block to get the key for
 * @param block_size number of bytes @a block
 * @param key set to the key (query) for the given block
 * @return #GNUNET_OK on success, #GNUNET_SYSERR if type not supported
 *         (or if extracting a key from a block of this type does not work)
 */
static int
block_plugin_dht_get_key (void *cls, enum GNUNET_BLOCK_Type type,
                          const void *block, size_t block_size,
                          struct GNUNET_HashCode * key)
{
  const struct GNUNET_MessageHeader *msg;
  const struct GNUNET_HELLO_Message *hello;
  struct GNUNET_PeerIdentity *pid;

  if (type != GNUNET_BLOCK_TYPE_DHT_HELLO)
    return GNUNET_SYSERR;
  if (block_size < sizeof (struct GNUNET_MessageHeader))
  {
    GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "block-dht",
                     _("Block not of type %u\n"), GNUNET_BLOCK_TYPE_DHT_HELLO);
    return GNUNET_NO;
  }
  msg = block;
  if (block_size != ntohs (msg->size))
  {
    GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "block-dht",
                     _("Size mismatch for block\n"),
                     GNUNET_BLOCK_TYPE_DHT_HELLO);
    return GNUNET_NO;
  }
  hello = block;
  memset (key, 0, sizeof (*key));
  pid = (struct GNUNET_PeerIdentity *) key;
  if (GNUNET_OK != GNUNET_HELLO_get_id (hello, pid))
  {
    GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "block-dht",
                     _("Block of type %u is malformed\n"),
                     GNUNET_BLOCK_TYPE_DHT_HELLO);
    return GNUNET_NO;
  }
  return GNUNET_OK;
}
/**
 * Add a host to the persistent list.  This method operates in
 * semi-reliable mode: if the transmission is not completed by
 * the time 'GNUNET_PEERINFO_disconnect' is called, it will be
 * aborted.  Furthermore, if a second HELLO is added for the
 * same peer before the first one was transmitted, PEERINFO may
 * merge the two HELLOs prior to transmission to the service.
 *
 * @param h handle to the peerinfo service
 * @param hello the verified (!) HELLO message
 * @param cont continuation to call when done, NULL is allowed
 * @param cont_cls closure for 'cont'
 * @return handle to cancel add operation; all pending
 *         'add' operations will be cancelled automatically
 *        on disconnect, so it is not necessary to keep this
 *        handle (unless 'cont' is NULL and at some point
 *        calling 'cont' must be prevented)
 */
struct GNUNET_PEERINFO_AddContext *
GNUNET_PEERINFO_add_peer (struct GNUNET_PEERINFO_Handle *h,
                          const struct GNUNET_HELLO_Message *hello,
			  GNUNET_PEERINFO_Continuation cont,
			  void *cont_cls)
{
  uint16_t hs = GNUNET_HELLO_size (hello);
  struct GNUNET_PEERINFO_AddContext *ac;
  struct GNUNET_PeerIdentity peer;

  GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (hello, &peer));
  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Adding peer `%s' to PEERINFO database (%u bytes of `%s')\n",
       GNUNET_i2s (&peer), hs, "HELLO");
  ac = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_AddContext) + hs);
  ac->h = h;
  ac->size = hs;
  ac->cont = cont;
  ac->cont_cls = cont_cls;
  memcpy (&ac[1], hello, hs);
  GNUNET_CONTAINER_DLL_insert_tail (h->ac_head, h->ac_tail, ac);
  trigger_transmit (h);
  return ac;
}
/**
 * Type of a function to call when we receive a message from the
 * service.  Call the iterator with the result and (if applicable)
 * continue to receive more messages or trigger processing the next
 * event (if applicable).
 *
 * @param cls closure
 * @param msg message received, NULL on timeout or fatal error
 */
static void
peerinfo_handler (void *cls, const struct GNUNET_MessageHeader *msg)
{
  struct GNUNET_PEERINFO_Handle *h = cls;
  struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
  const struct InfoMessage *im;
  const struct GNUNET_HELLO_Message *hello;
  GNUNET_PEERINFO_Processor cb;
  struct GNUNET_PeerIdentity id;
  void *cb_cls;
  uint16_t ms;

  GNUNET_assert (NULL != ic);
  h->in_receive = GNUNET_NO;
  ic->in_receive = GNUNET_NO;
  cb = ic->callback;
  cb_cls = ic->callback_cls;
  if (NULL == msg)
  {
    /* peerinfo service died, signal error */
    GNUNET_PEERINFO_iterate_cancel (ic);
    reconnect (h);
    if (NULL != cb)
      cb (cb_cls, NULL, NULL,
	  _("Failed to receive response from `PEERINFO' service."));
    return;
  }

  if (GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END == ntohs (msg->type))
  {
    /* normal end of list of peers, signal end, process next pending request */
    LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Received end of list of peers from `%s' service\n", "PEERINFO");
    GNUNET_PEERINFO_iterate_cancel (ic);   
    trigger_transmit (h);
    if (NULL != cb)
      cb (cb_cls, NULL, NULL, NULL);
    return;
  }

  ms = ntohs (msg->size);
  if ((ms < sizeof (struct InfoMessage)) ||
      (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_PEERINFO_INFO))
  {
    /* malformed message */
    GNUNET_break (0);
    GNUNET_PEERINFO_iterate_cancel (ic);
    reconnect (h);
    if (NULL != cb)
      cb (cb_cls, NULL, NULL,
	  _("Received invalid message from `PEERINFO' service."));
    return;
  }
  im = (const struct InfoMessage *) msg;
  GNUNET_break (0 == ntohl (im->reserved));
  if ( (GNUNET_YES == ic->have_peer) &&
       (0 != memcmp (&ic->peer, &im->peer, sizeof (struct GNUNET_PeerIdentity))) )
  {
    /* bogus message (from a different iteration call?); out of sequence! */
    LOG (GNUNET_ERROR_TYPE_ERROR,
         "Received HELLO for peer `%s', expected peer `%s'\n",
	 GNUNET_h2s (&im->peer.hashPubKey),
	 GNUNET_i2s (&ic->peer));
    
    GNUNET_break (0);
    GNUNET_PEERINFO_iterate_cancel (ic);
    reconnect (h);
    if (NULL != cb)      
      cb (cb_cls, NULL, NULL,
	  _("Received invalid message from `PEERINFO' service."));
    return;
  }
  hello = NULL;
  if (ms > sizeof (struct InfoMessage) + sizeof (struct GNUNET_MessageHeader))
  {
    hello = (const struct GNUNET_HELLO_Message *) &im[1];
    if (ms != sizeof (struct InfoMessage) + GNUNET_HELLO_size (hello))
    {
      /* malformed message */
      GNUNET_break (0);
      GNUNET_PEERINFO_iterate_cancel (ic);
      reconnect (h);
      if (NULL != cb)      
        cb (cb_cls, NULL, NULL,
	    _("Received invalid message from `PEERINFO' service."));
      return;
    }
    if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &id))
    {
      /* malformed message */
      GNUNET_break (0);
      GNUNET_PEERINFO_iterate_cancel (ic);
      reconnect (h);
      if (NULL != cb)      
        cb (cb_cls, NULL, NULL,
	    _("Received invalid message from `PEERINFO' service."));
      return;
    }
    if (0 != memcmp (&im->peer, &id, sizeof (struct GNUNET_PeerIdentity)))
    {
      /* malformed message */
      GNUNET_break (0);
      GNUNET_PEERINFO_iterate_cancel (ic);
      reconnect (h);
      if (NULL != cb)      
        cb (cb_cls, NULL, NULL,
	    _("Received invalid message from `PEERINFO' service."));
      return;
    }
  }

  /* normal data message */
  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Received %u bytes of `%s' information about peer `%s' from `%s' service\n",
       (hello == NULL) ? 0 : (unsigned int) GNUNET_HELLO_size (hello), "HELLO",
       GNUNET_i2s (&im->peer), "PEERINFO");
  h->in_receive = GNUNET_YES;
  ic->in_receive = GNUNET_YES;
  GNUNET_CLIENT_receive (h->client, &peerinfo_handler, h,
                         GNUNET_TIME_absolute_get_remaining (ic->timeout));
  if (NULL != cb)
    cb (cb_cls, &im->peer, hello, NULL);
}
Exemple #13
0
/**
 * Function called to validate a reply or a request.  For
 * request evaluation, simply pass "NULL" for the @a reply_block.
 *
 * @param cls closure
 * @param type block type
 * @param eo control flags
 * @param query original query (hash)
 * @param bf pointer to bloom filter associated with query; possibly updated (!)
 * @param bf_mutator mutation value for @a bf
 * @param xquery extended query data (can be NULL, depending on type)
 * @param xquery_size number of bytes in @a xquery
 * @param reply_block response to validate
 * @param reply_block_size number of bytes in @a reply_block
 * @return characterization of result
 */
static enum GNUNET_BLOCK_EvaluationResult
block_plugin_dht_evaluate (void *cls,
                           enum GNUNET_BLOCK_Type type,
                           enum GNUNET_BLOCK_EvaluationOptions eo,
                           const struct GNUNET_HashCode *query,
                           struct GNUNET_CONTAINER_BloomFilter **bf,
                           int32_t bf_mutator,
                           const void *xquery,
                           size_t xquery_size,
                           const void *reply_block,
                           size_t reply_block_size)
{
  struct GNUNET_HashCode mhash;
  const struct GNUNET_HELLO_Message *hello;
  struct GNUNET_PeerIdentity pid;
  const struct GNUNET_MessageHeader *msg;
  struct GNUNET_HashCode phash;

  if (type != GNUNET_BLOCK_TYPE_DHT_HELLO)
    return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
  if (xquery_size != 0)
  {
    GNUNET_break_op (0);
    return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
  }
  if (NULL == reply_block)
    return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
  if (reply_block_size < sizeof (struct GNUNET_MessageHeader))
  {
    GNUNET_break_op (0);
    return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
  }
  msg = reply_block;
  if (reply_block_size != ntohs (msg->size))
  {
    GNUNET_break_op (0);
    return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
  }
  hello = reply_block;
  if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid))
  {
    GNUNET_break_op (0);
    return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
  }
  if (NULL != bf)
  {
    GNUNET_CRYPTO_hash (&pid, sizeof (pid), &phash);
    GNUNET_BLOCK_mingle_hash (&phash, bf_mutator, &mhash);
    if (NULL != *bf)
    {
      if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash))
        return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
    }
    else
    {
      *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8,
                                               GNUNET_CONSTANTS_BLOOMFILTER_K);
    }
    GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash);
  }
  return GNUNET_BLOCK_EVALUATION_OK_MORE;
}