/**
 * Try to read the HELLO in the given filename and discard expired addresses.
 * 
 * @param fn name of the file
 * @return HELLO of the file, NULL on error
 */
static struct GNUNET_HELLO_Message *
read_host_file (const char *fn)
{
  char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
  const struct GNUNET_HELLO_Message *hello;
  struct GNUNET_HELLO_Message *hello_clean;
  int size;
  struct GNUNET_TIME_Absolute now;

  if (GNUNET_YES != GNUNET_DISK_file_test (fn))
    return NULL;
  size = GNUNET_DISK_fn_read (fn, buffer, sizeof (buffer));
  hello = (const struct GNUNET_HELLO_Message *) buffer;
  if ((size < sizeof (struct GNUNET_MessageHeader)) ||
      (size != ntohs ((((const struct GNUNET_MessageHeader *) hello)->size)))
      || (size != GNUNET_HELLO_size (hello)))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
		_("Failed to parse HELLO in file `%s'\n"),
		fn);
    return NULL;
  }
  now = GNUNET_TIME_absolute_get ();
  hello_clean =
    GNUNET_HELLO_iterate_addresses (hello, GNUNET_YES, &discard_expired,
				    &now);
  return hello_clean; 
}
/**
 * Find a peer that would be reasonable for advertising.
 *
 * @param cls closure
 * @param pid identity of a peer
 * @param value 'struct Peer*' for the peer we are considering
 * @return GNUNET_YES (continue iteration)
 */
static int
find_advertisable_hello (void *cls, const struct GNUNET_HashCode * pid, void *value)
{
  struct FindAdvHelloContext *fah = cls;
  struct Peer *pos = value;
  struct GNUNET_TIME_Relative rst_time;
  size_t hs;

  if (pos == fah->peer)
    return GNUNET_YES;
  if (pos->hello == NULL)
    return GNUNET_YES;
  rst_time = GNUNET_TIME_absolute_get_remaining (pos->filter_expiration);
  if (0 == rst_time.rel_value)
  {
    /* time to discard... */
    GNUNET_CONTAINER_bloomfilter_free (pos->filter);
    setup_filter (pos);
  }
  fah->next_adv = GNUNET_TIME_relative_min (rst_time, fah->next_adv);
  hs = GNUNET_HELLO_size (pos->hello);
  if (hs > fah->max_size)
    return GNUNET_YES;
  if (GNUNET_NO ==
      GNUNET_CONTAINER_bloomfilter_test (pos->filter,
                                         &fah->peer->pid.hashPubKey))
    fah->result = pos;
  return GNUNET_YES;
}
Ejemplo n.º 3
0
/**
 * Check that a peerinfo information message is well-formed.
 *
 * @param cls closure
 * @param im message received
 * @return #GNUNET_OK if the message is well-formed
 */
static int
check_notification (void *cls,
                    const struct InfoMessage *im)
{
  uint16_t ms = ntohs (im->header.size) - sizeof (*im);

  if (ms >= sizeof (struct GNUNET_MessageHeader))
  {
    const struct GNUNET_HELLO_Message *hello;

    hello = (const struct GNUNET_HELLO_Message *) &im[1];
    if (ms != GNUNET_HELLO_size (hello))
    {
      GNUNET_break (0);
      return GNUNET_SYSERR;
    }
    return GNUNET_OK;
  }
  if (0 != ms)
  {
    GNUNET_break (0);
    return GNUNET_SYSERR;
  }
  return GNUNET_OK;  /* odd... */
}
Ejemplo n.º 4
0
/**
 * Function to process paths received for a new peer addition. The recorded
 * paths form the initial tunnel, which can be optimized later.
 * Called on each result obtained for the DHT search.
 *
 * @param cls closure
 * @param exp when will this value expire
 * @param key key of the result
 * @param get_path path of the get request
 * @param get_path_length lenght of @a get_path
 * @param put_path path of the put request
 * @param put_path_length length of the @a put_path
 * @param type type of the result
 * @param size number of bytes in data
 * @param data pointer to the result data
 */
static void
dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
                    const struct GNUNET_HashCode *key,
                    const struct GNUNET_PeerIdentity *get_path,
                    unsigned int get_path_length,
                    const struct GNUNET_PeerIdentity *put_path,
                    unsigned int put_path_length,
                    enum GNUNET_BLOCK_Type type,
                    size_t size,
                    const void *data)
{
  const struct GNUNET_HELLO_Message *hello = data;
  struct CadetPeer *peer;

  GCPP_try_path_from_dht (get_path,
                          get_path_length,
                          put_path,
                          put_path_length);
  if ( (size >= sizeof (struct GNUNET_HELLO_Message)) &&
       (ntohs (hello->header.size) == size) &&
       (size == GNUNET_HELLO_size (hello)) )
  {
    peer = GCP_get (&put_path[0],
                    GNUNET_YES);
    LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Got HELLO for %s\n",
         GCP_2s (peer));
    GCP_set_hello (peer,
                   hello);
  }
}
/**
 * Construct our HELLO message from all of the addresses of
 * all of the transports.
 *
 * @param cls unused
 * @param tc scheduler context
 */
static void
refresh_hello_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
  struct GeneratorContext gc;
  int friend_only;

  hello_task = GNUNET_SCHEDULER_NO_TASK;
  gc.addr_pos = oal_head;
  gc.expiration = GNUNET_TIME_relative_to_absolute (hello_expiration);


  friend_only = GNUNET_HELLO_is_friend_only (our_hello);
  GNUNET_free (our_hello);
  our_hello = GNUNET_HELLO_create (&GST_my_public_key, &address_generator, &gc, friend_only);
  GNUNET_assert (NULL != our_hello);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Refreshed my %s `%s', new size is %d\n",
              (GNUNET_YES == GNUNET_HELLO_is_friend_only (our_hello)) ? "friend-only" : "public",
              "HELLO", GNUNET_HELLO_size (our_hello));
  GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# refreshed my HELLO"), 1,
                            GNUNET_NO);
  if (NULL != hello_cb)
    hello_cb (hello_cb_cls, GST_hello_get ());
  GNUNET_PEERINFO_add_peer (GST_peerinfo, our_hello, NULL, NULL);
  hello_task =
      GNUNET_SCHEDULER_add_delayed (HELLO_REFRESH_PERIOD, &refresh_hello_task,
                                    NULL);

}
/**
 * Do transmit info about peer to given host.
 *
 * @param cls NULL to hit all hosts, otherwise specifies a particular target
 * @param key hostID
 * @param value information to transmit
 * @return GNUNET_YES (continue to iterate)
 */
static int
add_to_tc (void *cls, const GNUNET_HashCode * key, void *value)
{
  struct GNUNET_SERVER_TransmitContext *tc = cls;
  struct HostEntry *pos = value;
  struct InfoMessage *im;
  uint16_t hs;
  char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;

  hs = 0;
  im = (struct InfoMessage *) buf;
  if (pos->hello != NULL)
  {
    hs = GNUNET_HELLO_size (pos->hello);
    GNUNET_assert (hs <
                   GNUNET_SERVER_MAX_MESSAGE_SIZE -
                   sizeof (struct InfoMessage));
    memcpy (&im[1], pos->hello, hs);
  }
  im->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_INFO);
  im->header.size = htons (sizeof (struct InfoMessage) + hs);
  im->reserved = htonl (0);
  im->peer = pos->identity;
  GNUNET_SERVER_transmit_context_append_message (tc, &im->header);
  return GNUNET_YES;
}
Ejemplo n.º 7
0
static void
try_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
  struct ConnectingContext *cc = cls;
  struct PeerContext *p1 = cc->p1;
  struct PeerContext *p2 = cc->p2;

  cc->tct = GNUNET_SCHEDULER_NO_TASK;
  if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
    return;

  GNUNET_assert (cc != NULL);
  GNUNET_assert (cc->p1 != NULL);
  GNUNET_assert (cc->p2 != NULL);

  char *p2_s = GNUNET_strdup (GNUNET_i2s (&p2->id));

  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
                   "Asking peer %u (`%s') to connect peer %u (`%s'), providing HELLO with %u bytes\n",
                   p1->no, GNUNET_i2s (&p1->id), p2->no, p2_s,
                   GNUNET_HELLO_size (cc->p2->hello));
  GNUNET_free (p2_s);

  GNUNET_TRANSPORT_offer_hello (cc->th_p1,
                                (const struct GNUNET_MessageHeader *) cc->
                                p2->hello, NULL, NULL);
  GNUNET_TRANSPORT_try_connect (cc->th_p1, &p2->id, NULL, NULL); /*FIXME TRY_CONNECT change */

  cc->tct =
      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &try_connect, cc);
}
Ejemplo n.º 8
0
/**
 * Calculate when we would like to send the next HELLO to this
 * peer and ask for it.
 *
 * @param cls for which peer to schedule the HELLO
 */
static void
schedule_next_hello (void *cls)
{
  struct Peer *pl = cls;
  struct FindAdvHelloContext fah;
  struct GNUNET_MQ_Envelope *env;
  size_t want;
  struct GNUNET_TIME_Relative delay;
  struct GNUNET_HashCode hc;

  pl->hello_delay_task = NULL;
  GNUNET_assert (NULL != pl->mq);
  /* find applicable HELLOs */
  fah.peer = pl;
  fah.result = NULL;
  fah.max_size = GNUNET_SERVER_MAX_MESSAGE_SIZE - 1;
  fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL;
  GNUNET_CONTAINER_multipeermap_iterate (peers,
                                         &find_advertisable_hello,
                                         &fah);
  pl->hello_delay_task =
      GNUNET_SCHEDULER_add_delayed (fah.next_adv,
                                    &schedule_next_hello,
                                    pl);
  if (NULL == fah.result)
    return;
  delay = GNUNET_TIME_absolute_get_remaining (pl->next_hello_allowed);
  if (0 != delay.rel_value_us)
    return;

  want = GNUNET_HELLO_size (fah.result->hello);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
	      "Sending HELLO with %u bytes",
	      (unsigned int) want);
  env = GNUNET_MQ_msg_copy (&fah.result->hello->header);
  GNUNET_MQ_send (pl->mq,
		  env);

  /* avoid sending this one again soon */
  GNUNET_CRYPTO_hash (&pl->pid,
		      sizeof (struct GNUNET_PeerIdentity),
		      &hc);
  GNUNET_CONTAINER_bloomfilter_add (fah.result->filter,
				    &hc);

  GNUNET_STATISTICS_update (stats,
			    gettext_noop ("# HELLO messages gossipped"),
			    1,
			    GNUNET_NO);
  /* prepare to send the next one */
  if (NULL != pl->hello_delay_task)
    GNUNET_SCHEDULER_cancel (pl->hello_delay_task);
  pl->next_hello_allowed
    = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY);
  pl->hello_delay_task
    = GNUNET_SCHEDULER_add_now (&schedule_next_hello,
				pl);
}
/**
 * Bind a host address (hello) to a hostId.
 *
 * @param peer the peer for which this is a hello
 * @param hello the verified (!) hello message
 */
static void
bind_address (const struct GNUNET_PeerIdentity *peer,
              const struct GNUNET_HELLO_Message *hello)
{
  char *fn;
  struct HostEntry *host;
  struct GNUNET_HELLO_Message *mrg;
  struct GNUNET_TIME_Absolute delta;

  add_host_to_known_hosts (peer);
  host = GNUNET_CONTAINER_multihashmap_get (hostmap, &peer->hashPubKey);
  GNUNET_assert (host != NULL);
  if (host->hello == NULL)
  {
    host->hello = GNUNET_malloc (GNUNET_HELLO_size (hello));
    memcpy (host->hello, hello, GNUNET_HELLO_size (hello));
  }
  else
  {
    mrg = GNUNET_HELLO_merge (host->hello, hello);
    delta = GNUNET_HELLO_equals (mrg, host->hello, GNUNET_TIME_absolute_get ());
    if (delta.abs_value == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value)
    {
      GNUNET_free (mrg);
      return;
    }
    GNUNET_free (host->hello);
    host->hello = mrg;
  }
  fn = get_host_filename (peer);
  if (GNUNET_OK == GNUNET_DISK_directory_create_for_file (fn))
  {
    if (GNUNET_SYSERR ==
        GNUNET_DISK_fn_write (fn, host->hello, GNUNET_HELLO_size (host->hello),
                              GNUNET_DISK_PERM_USER_READ |
                              GNUNET_DISK_PERM_USER_WRITE |
                              GNUNET_DISK_PERM_GROUP_READ |
                              GNUNET_DISK_PERM_OTHER_READ))
      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", fn);

  }
  GNUNET_free (fn);
  notify_all (host);
}
Ejemplo n.º 10
0
/**
 * 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);
}
Ejemplo n.º 11
0
/**
 * Create a new entry in the peer list.
 *
 * @param peer identity of the new entry
 * @param hello hello message, can be NULL
 * @param is_friend is the new entry for a friend?
 * @return the new entry
 */
static struct Peer *
make_peer (const struct GNUNET_PeerIdentity *peer,
           const struct GNUNET_HELLO_Message *hello, int is_friend)
{
  struct Peer *ret;

  ret = GNUNET_malloc (sizeof (struct Peer));
  ret->pid = *peer;
  ret->is_friend = is_friend;
  if (hello != NULL)
  {
    ret->hello = GNUNET_malloc (GNUNET_HELLO_size (hello));
    memcpy (ret->hello, hello, GNUNET_HELLO_size (hello));
  }
  GNUNET_break (GNUNET_OK ==
                GNUNET_CONTAINER_multihashmap_put (peers, &peer->hashPubKey,
                                                   ret,
                                                   GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  return ret;
}
Ejemplo n.º 12
0
/**
 * Periodically announce self id in the DHT
 *
 * @param cls closure
 * @param tc task context
 */
static void
announce_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
  struct GNUNET_HashCode phash;
  const struct GNUNET_HELLO_Message *hello;
  size_t size;
  struct GNUNET_TIME_Absolute expiration;
  struct GNUNET_TIME_Relative retry_time;

  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
  {
    announce_id_task = NULL;
    return;
  }
  LOG (GNUNET_ERROR_TYPE_DEBUG, "Announce ID\n");
  /* TODO
   * - Set data expiration in function of X
   * - Adapt X to churn
   */
  hello = GCH_get_mine ();
  if (NULL == hello || (size = GNUNET_HELLO_size (hello)) == 0)
  {
    /* Peerinfo gave us no hello yet, try again in a second. */
    announce_id_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
                                                     &announce_id, cls);
    LOG (GNUNET_ERROR_TYPE_DEBUG, "  no hello, waiting!\n");
    GNUNET_STATISTICS_update (stats, "# DHT announce skipped (no hello)",
                              1, GNUNET_NO);

    return;
  }
  expiration = GNUNET_HELLO_get_last_expiration (hello);
  retry_time = GNUNET_TIME_absolute_get_remaining (expiration);

  LOG (GNUNET_ERROR_TYPE_DEBUG, "Hello %p size: %u\n", hello, size);
  GNUNET_STATISTICS_update (stats, "# DHT announce",
                            1, GNUNET_NO);
  memset (&phash, 0, sizeof (phash));
  memcpy (&phash, &my_full_id, sizeof (my_full_id));
  GNUNET_DHT_put (dht_handle,   /* DHT handle */
                  &phash,       /* Key to use */
                  dht_replication_level,     /* Replication level */
                  GNUNET_DHT_RO_RECORD_ROUTE
                  | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,    /* DHT options */
                  GNUNET_BLOCK_TYPE_DHT_HELLO,       /* Block type */
                  size,  /* Size of the data */
                  (const char *) hello, /* Data itself */
                  expiration,  /* Data expiration */
                  retry_time, /* Retry time */
                  NULL,         /* Continuation */
                  NULL);        /* Continuation closure */
  announce_id_task =
      GNUNET_SCHEDULER_add_delayed (id_announce_time, &announce_id, cls);
}
/**
 * Notify all clients in the notify list about the
 * given host entry changing.
 *
 * @param he entry of the host for which we generate a notification
 * @return generated notification message
 */
static struct InfoMessage *
make_info_message (const struct HostEntry *he)
{
  struct InfoMessage *im;
  size_t hs;

  hs = (he->hello == NULL) ? 0 : GNUNET_HELLO_size (he->hello);
  im = GNUNET_malloc (sizeof (struct InfoMessage) + hs);
  im->header.size = htons (hs + sizeof (struct InfoMessage));
  im->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_INFO);
  im->peer = he->identity;
  if (he->hello != NULL)
    memcpy (&im[1], he->hello, hs);
  return im;
}
Ejemplo n.º 14
0
/**
 * Receive a peerinfo information message, process it and
 * go for more.
 *
 * @param cls closure
 * @param msg message received, NULL on timeout or fatal error
 */
static void
process_notification (void *cls, const struct GNUNET_MessageHeader *msg)
{
  struct GNUNET_PEERINFO_NotifyContext *nc = cls;
  const struct InfoMessage *im;
  const struct GNUNET_HELLO_Message *hello;
  uint16_t ms;

  if (msg == NULL)
  {
    GNUNET_CLIENT_disconnect (nc->client);
    reconnect (nc, NULL);
    return;
  }
  ms = ntohs (msg->size);
  if ((ms < sizeof (struct InfoMessage)) ||
      (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_PEERINFO_INFO))
  {
    GNUNET_break (0);
    GNUNET_CLIENT_disconnect (nc->client);
    nc->client = GNUNET_CLIENT_connect ("peerinfo", nc->cfg);
    request_notifications (nc);
    return;
  }
  im = (const struct InfoMessage *) msg;
  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))
    {
      GNUNET_break (0);
      GNUNET_CLIENT_disconnect (nc->client);
      nc->client = GNUNET_CLIENT_connect ("peerinfo", nc->cfg);
      request_notifications (nc);
      return;
    }
  }

  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Received information about peer `%s' from peerinfo database\n",
       GNUNET_i2s (&im->peer));
  nc->callback (nc->callback_cls, &im->peer, hello, NULL);
  receive_notifications (nc);
}
Ejemplo n.º 15
0
/**
 * Notify all clients in the notify list about the
 * given host entry changing.
 *
 * @param he entry of the host for which we generate a notification
 * @param include_friend_only create public of friend-only message
 * @return generated notification message
 */
static struct InfoMessage *
make_info_message (const struct HostEntry *he,
                   int include_friend_only)
{
  struct InfoMessage *im;
  struct GNUNET_HELLO_Message *src;
  size_t hs;

  if (GNUNET_YES == include_friend_only)
  	src = he->friend_only_hello;
  else
  	src = he->hello;

  hs = (NULL == src) ? 0 : GNUNET_HELLO_size (src);
  im = GNUNET_malloc (sizeof (struct InfoMessage) + hs);
  im->header.size = htons (hs + sizeof (struct InfoMessage));
  im->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_INFO);
  im->peer = he->identity;
  if (NULL != src)
    memcpy (&im[1], src, hs);
  return im;
}
static unsigned int
prepare_beacon (struct Plugin *plugin, struct UDP_Beacon_Message *msg)
{
  uint16_t hello_size;
  uint16_t msg_size;

  const struct GNUNET_MessageHeader *hello;
  hello = plugin->env->get_our_hello ();
  if (NULL == hello)
    return 0;
  hello_size = GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello);
  msg_size = hello_size + sizeof (struct UDP_Beacon_Message);

  if (hello_size < (sizeof (struct GNUNET_MessageHeader)) ||
      (msg_size > (UDP_MTU)))
    return 0;

  msg->sender = *(plugin->env->my_identity);
  msg->header.size = htons (msg_size);
  msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON);
  memcpy (&msg[1], hello, hello_size);
  return msg_size;
}
/**
 * @brief delete expired HELLO entries in data/hosts/
 *
 * @param cls pointer to current time (struct GNUNET_TIME_Absolute)
 * @param fn filename to test to see if the HELLO expired
 * @return GNUNET_OK (continue iteration)
 */
static int
discard_hosts_helper (void *cls, const char *fn)
{
  struct GNUNET_TIME_Absolute *now = cls;
  char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
  const struct GNUNET_HELLO_Message *hello;
  struct GNUNET_HELLO_Message *new_hello;
  int size;

  size = GNUNET_DISK_fn_read (fn, buffer, sizeof (buffer));
  if (size < sizeof (struct GNUNET_MessageHeader))
  {
    if (0 != UNLINK (fn))
      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING |
                                GNUNET_ERROR_TYPE_BULK, "unlink", fn);
    return GNUNET_OK;
  }
  hello = (const struct GNUNET_HELLO_Message *) buffer;
  new_hello =
      GNUNET_HELLO_iterate_addresses (hello, GNUNET_YES, &discard_expired, now);
  if (new_hello != NULL)
  {
    GNUNET_DISK_fn_write (fn, new_hello, GNUNET_HELLO_size (new_hello),
                          GNUNET_DISK_PERM_USER_READ |
                          GNUNET_DISK_PERM_USER_WRITE |
                          GNUNET_DISK_PERM_GROUP_READ |
                          GNUNET_DISK_PERM_OTHER_READ);
    GNUNET_free (new_hello);
  }
  else
  {
    if (0 != UNLINK (fn))
      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING |
                                GNUNET_ERROR_TYPE_BULK, "unlink", fn);
  }
  return GNUNET_OK;
}
Ejemplo n.º 18
0
/**
 * Calculate when we would like to send the next HELLO to this
 * peer and ask for it.
 *
 * @param cls for which peer to schedule the HELLO
 * @param tc task context
 */
static void
schedule_next_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
  struct Peer *pl = cls;
  struct FindAdvHelloContext fah;
  size_t next_want;
  struct GNUNET_TIME_Relative delay;

  pl->hello_delay_task = GNUNET_SCHEDULER_NO_TASK;
  GNUNET_assert (GNUNET_YES == pl->is_connected);
  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
    return;                     /* we're out of here */
  if (pl->hello_req != NULL)
    return;                     /* did not finish sending the previous one */
  /* find applicable HELLOs */
  fah.peer = pl;
  fah.result = NULL;
  fah.max_size = GNUNET_SERVER_MAX_MESSAGE_SIZE - 1;
  fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL;
  GNUNET_CONTAINER_multihashmap_iterate (peers, &find_advertisable_hello, &fah);
  pl->hello_delay_task =
      GNUNET_SCHEDULER_add_delayed (fah.next_adv, &schedule_next_hello, pl);
  if (fah.result == NULL)
    return;
  next_want = GNUNET_HELLO_size (fah.result->hello);
  delay = GNUNET_TIME_absolute_get_remaining (pl->next_hello_allowed);
  if (delay.rel_value == 0)
  {
    /* now! */
    pl->hello_req =
        GNUNET_CORE_notify_transmit_ready (handle, GNUNET_YES, 0,
                                           GNUNET_CONSTANTS_SERVICE_TIMEOUT,
                                           &pl->pid, next_want,
                                           &hello_advertising_ready, pl);
  }
}
Ejemplo n.º 19
0
/**
 * 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;
}
Ejemplo n.º 20
0
/**
 * Function to fill send buffer with HELLO.
 *
 * @param cls 'struct Peer' of the target peer
 * @param size number of bytes available in buf
 * @param buf where the callee should write the message
 * @return number of bytes written to buf
 */
static size_t
hello_advertising_ready (void *cls, size_t size, void *buf)
{
  struct Peer *pl = cls;
  struct FindAdvHelloContext fah;
  size_t want;

  pl->hello_req = NULL;
  GNUNET_assert (GNUNET_YES == pl->is_connected);
  /* find applicable HELLOs */
  fah.peer = pl;
  fah.result = NULL;
  fah.max_size = size;
  fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL;
  GNUNET_CONTAINER_multihashmap_iterate (peers, &find_advertisable_hello, &fah);
  want = 0;
  if (fah.result != NULL)
  {
    want = GNUNET_HELLO_size (fah.result->hello);
    GNUNET_assert (want <= size);
    memcpy (buf, fah.result->hello, want);
    GNUNET_CONTAINER_bloomfilter_add (fah.result->filter, &pl->pid.hashPubKey);
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' with %u bytes", "HELLO",
                (unsigned int) want);
    GNUNET_STATISTICS_update (stats,
                              gettext_noop ("# HELLO messages gossipped"), 1,
                              GNUNET_NO);
  }

  if (pl->hello_delay_task != GNUNET_SCHEDULER_NO_TASK)
    GNUNET_SCHEDULER_cancel (pl->hello_delay_task);
  pl->next_hello_allowed =
      GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY);
  pl->hello_delay_task = GNUNET_SCHEDULER_add_now (&schedule_next_hello, pl);
  return want;
}
Ejemplo n.º 21
0
/**
 * 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);
}
Ejemplo n.º 22
0
/**
 * Iterate over all of the addresses in the HELLO.
 *
 * @param msg HELLO to iterate over
 * @param return_modified if a modified copy should be returned,
 *         otherwise NULL will be returned
 * @param it iterator to call on each address
 * @param it_cls closure for it
 */
struct GNUNET_HELLO_Message *
GNUNET_HELLO_iterate_addresses (const struct GNUNET_HELLO_Message *msg,
                                int return_modified,
                                GNUNET_HELLO_AddressIterator it, void *it_cls)
{
  struct GNUNET_HELLO_Address address;
  uint16_t msize;
  struct GNUNET_HELLO_Message *ret;
  const char *inptr;
  size_t insize;
  size_t esize;
  size_t wpos;
  char *woff;
  uint16_t alen;
  struct GNUNET_TIME_AbsoluteNBO expire;
  int iret;

  msize = GNUNET_HELLO_size (msg);
  if ((msize < sizeof (struct GNUNET_HELLO_Message)) ||
      (ntohs (msg->header.type) != GNUNET_MESSAGE_TYPE_HELLO))
    return NULL;
  ret = NULL;
  if (return_modified)
  {
    ret = GNUNET_malloc (msize);
    memcpy (ret, msg, msize);
  }
  inptr = (const char *) &msg[1];
  insize = msize - sizeof (struct GNUNET_HELLO_Message);
  wpos = 0;
  woff = (ret != NULL) ? (char *) &ret[1] : NULL;
  GNUNET_CRYPTO_hash (&msg->publicKey,
                      sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
                      &address.peer.hashPubKey);
  while (insize > 0)
  {
    esize = get_hello_address_size (inptr, insize, &alen);
    if (esize == 0)
    {
      GNUNET_break (0);
      GNUNET_free_non_null (ret);
      return NULL;
    }
    memcpy (&expire,
            &inptr[esize - alen - sizeof (struct GNUNET_TIME_AbsoluteNBO)],
            sizeof (struct GNUNET_TIME_AbsoluteNBO));
    address.address = &inptr[esize - alen];
    address.address_length = alen;
    address.transport_name = inptr;
    iret = it (it_cls, &address, GNUNET_TIME_absolute_ntoh (expire));
    if (iret == GNUNET_SYSERR)
    {
      if (ret != NULL)
        ret->header.size = ntohs (sizeof (struct GNUNET_HELLO_Message) + wpos);
      return ret;
    }
    if ((iret == GNUNET_OK) && (ret != NULL))
    {
      memcpy (woff, inptr, esize);
      woff += esize;
      wpos += esize;
    }
    insize -= esize;
    inptr += esize;
  }
  if (ret != NULL)
    ret->header.size = ntohs (sizeof (struct GNUNET_HELLO_Message) + wpos);
  return ret;
}
Ejemplo n.º 23
0
int
main (int argc, char *argv[])
{
  struct GNUNET_DISK_FileHandle *fh;
  struct GNUNET_HELLO_Message *orig;
  struct GNUNET_HELLO_Message *result;
  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
  uint64_t fsize;

  GNUNET_log_setup ("gnunet-hello", "INFO", NULL);
  if (argc != 2)
  {
    FPRINTF (stderr,
	     "%s",
	     _("Call with name of HELLO file to modify.\n"));
    return 1;
  }
  if (GNUNET_OK != GNUNET_DISK_file_size (argv[1], &fsize, GNUNET_YES, GNUNET_YES))
  {
    FPRINTF (stderr,
	     _("Error accessing file `%s': %s\n"),
	     argv[1],
	     STRERROR (errno));
    return 1;
  }
  if (fsize > 65536)
  {
    FPRINTF (stderr,
	     _("File `%s' is too big to be a HELLO\n"),
	     argv[1]);
    return 1;
  }
  if (fsize < sizeof (struct GNUNET_MessageHeader))
  {
    FPRINTF (stderr,
	     _("File `%s' is too small to be a HELLO\n"),
	     argv[1]);
    return 1;
  }
  fh = GNUNET_DISK_file_open (argv[1], 
			      GNUNET_DISK_OPEN_READ,
			      GNUNET_DISK_PERM_USER_READ);
  if (NULL == fh)
  {
    FPRINTF (stderr,
	     _("Error opening file `%s': %s\n"),
	     argv[1],
	     STRERROR (errno));
    return 1;
  }
  {
    char buf[fsize] GNUNET_ALIGN;
    
    GNUNET_assert (fsize == 
		   GNUNET_DISK_file_read (fh, buf, fsize));
    GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
    orig = (struct GNUNET_HELLO_Message *) buf;
    if ( (fsize != GNUNET_HELLO_size (orig)) ||
	 (GNUNET_OK != GNUNET_HELLO_get_key (orig, &pk)) )
    {
      FPRINTF (stderr,
	       _("Did not find well-formed HELLO in file `%s'\n"),
	       argv[1]);
      return 1;
    }
    result = GNUNET_HELLO_create (&pk, &add_from_hello, &orig);
    GNUNET_assert (NULL != result);
     fh = GNUNET_DISK_file_open (argv[1], 
				 GNUNET_DISK_OPEN_WRITE,
				 GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
     if (NULL == fh)
     {
       FPRINTF (stderr,
		_("Error opening file `%s': %s\n"),
		argv[1],
		STRERROR (errno));
       GNUNET_free (result);
       return 1;
     }
     fsize = GNUNET_HELLO_size (result);
     if (fsize != GNUNET_DISK_file_write (fh,
					  result,
					  fsize))
     {
       FPRINTF (stderr,
		_("Error writing HELLO to file `%s': %s\n"),
		argv[1],
		STRERROR (errno));
       (void) GNUNET_DISK_file_close (fh);
       return 1;
     }
    GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
  }
  return 0;
}
Ejemplo n.º 24
0
/**
 * Try to read the HELLOs in the given filename and discard expired
 * addresses.  Removes the file if one the HELLO is malformed.  If all
 * addresses are expired, the HELLO is also removed (but the HELLO
 * with the public key is still returned if it was found and valid).
 * The file can contain multiple HELLO messages.
 *
 * @param fn name of the file
 * @param unlink_garbage if #GNUNET_YES, try to remove useless files
 * @param r ReadHostFileContext to store the resutl
 */
static void
read_host_file (const char *fn,
                int unlink_garbage,
                struct ReadHostFileContext *r)
{
  char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
  unsigned int size_total;
  struct GNUNET_TIME_Absolute now;
  unsigned int left;
  const struct GNUNET_HELLO_Message *hello;
  struct GNUNET_HELLO_Message *hello_clean;
  unsigned read_pos;
  int size_hello;

  r->friend_only_hello = NULL;
  r->hello = NULL;

  if (GNUNET_YES != GNUNET_DISK_file_test (fn))
    return;
  size_total = GNUNET_DISK_fn_read (fn, buffer, sizeof (buffer));
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Read %u bytes from `%s'\n",
              size_total,
              fn);
  if (size_total < sizeof (struct GNUNET_MessageHeader))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
		_("Failed to parse HELLO in file `%s': %s\n"),
		fn, "Fail has invalid size");
    if ( (GNUNET_YES == unlink_garbage) &&
	 (0 != UNLINK (fn)) &&
	 (ENOENT != errno) )
      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
                                "unlink",
                                fn);
    return;
  }

  read_pos = 0;
  while (read_pos < size_total)
  {
    hello = (const struct GNUNET_HELLO_Message *) &buffer[read_pos];
    size_hello = GNUNET_HELLO_size (hello);
    if ( (0 == size_hello) ||
         (size_total - read_pos < size_hello) )
    {
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  _("Failed to parse HELLO in file `%s'\n"),
                  fn);
      if (0 == read_pos)
      {
        if ((GNUNET_YES == unlink_garbage) &&
            (0 != UNLINK (fn)) &&
            (ENOENT != errno) )
          GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
                                    "unlink",
                                    fn);
      }
      else
      {
        if ((GNUNET_YES == unlink_garbage) &&
            (0 != TRUNCATE (fn, read_pos)) &&
            (ENOENT != errno) )
          GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
                                    "truncate",
                                    fn);
      }
      return;
    }

    now = GNUNET_TIME_absolute_get ();
    hello_clean = GNUNET_HELLO_iterate_addresses (hello, GNUNET_YES,
						  &discard_expired, &now);
    if (NULL == hello_clean)
    {
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  _("Failed to parse HELLO in file `%s'\n"),
                  fn);
      if ((GNUNET_YES == unlink_garbage) &&
          (0 != UNLINK (fn)) &&
          (ENOENT != errno) )
        GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
                                  "unlink",
                                  fn);
      return;
    }
    left = 0;
    (void) GNUNET_HELLO_iterate_addresses (hello_clean, GNUNET_NO,
					   &count_addresses, &left);

    if (0 == left)
    {
      GNUNET_free (hello_clean);
      break;
    }

    if (GNUNET_NO == GNUNET_HELLO_is_friend_only (hello_clean))
    {
      if (NULL == r->hello)
	r->hello = hello_clean;
      else
      {
	GNUNET_break (0);
	GNUNET_free (r->hello);
	r->hello = hello_clean;
      }
    }
    else
    {
      if (NULL == r->friend_only_hello)
	r->friend_only_hello = hello_clean;
      else
      {
	GNUNET_break (0);
	GNUNET_free (r->friend_only_hello);
	r->friend_only_hello = hello_clean;
      }
    }
    read_pos += size_hello;
  }

  if (0 == left)
  {
    /* no addresses left, remove from disk */
    if ( (GNUNET_YES == unlink_garbage) &&
         (0 != UNLINK (fn)) )
      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
                                "unlink",
                                fn);
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
	      "Found `%s' and `%s' HELLO message in file\n",
	      (NULL != r->hello) ? "public" : "NON-public",
	      (NULL != r->friend_only_hello) ? "friend only" : "NO friend only");
}
Ejemplo n.º 25
0
/**
 * Periodically announce self id in the DHT
 *
 * @param cls closure
 */
static void
announce_id (void *cls)
{
  struct GNUNET_HashCode phash;
  const struct GNUNET_HELLO_Message *hello;
  size_t size;
  struct GNUNET_TIME_Absolute expiration;
  struct GNUNET_TIME_Relative next_put;

  hello = GCH_get_mine ();
  size = (NULL != hello) ? GNUNET_HELLO_size (hello) : 0;
  if (0 == size)
  {
    expiration = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
                                           announce_delay);
    announce_delay = GNUNET_TIME_STD_BACKOFF (announce_delay);
  }
  else
  {
    expiration = GNUNET_HELLO_get_last_expiration (hello);
    announce_delay = GNUNET_TIME_UNIT_SECONDS;
  }

  /* Call again in id_announce_time, unless HELLO expires first,
   * but wait at least 1s. */
  next_put
    = GNUNET_TIME_absolute_get_remaining (expiration);
  next_put
    = GNUNET_TIME_relative_min (next_put,
                                id_announce_time);
  next_put
    = GNUNET_TIME_relative_max (next_put,
                                GNUNET_TIME_UNIT_SECONDS);
  announce_id_task
    = GNUNET_SCHEDULER_add_delayed (next_put,
                                    &announce_id,
                                    cls);
  GNUNET_STATISTICS_update (stats,
                            "# DHT announce",
                            1,
                            GNUNET_NO);
  memset (&phash,
          0,
          sizeof (phash));
  GNUNET_memcpy (&phash,
                 &my_full_id,
                 sizeof (my_full_id));
  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Announcing my HELLO (%u bytes) in the DHT\n",
       size);
  GNUNET_DHT_put (dht_handle,   /* DHT handle */
                  &phash,       /* Key to use */
                  dht_replication_level,     /* Replication level */
                  GNUNET_DHT_RO_RECORD_ROUTE
                  | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,    /* DHT options */
                  GNUNET_BLOCK_TYPE_DHT_HELLO,       /* Block type */
                  size,  /* Size of the data */
                  (const char *) hello, /* Data itself */
                  expiration,  /* Data expiration */
                  NULL,         /* Continuation */
                  NULL);        /* Continuation closure */
}
/**
 * Callback that processes each of the known HELLOs for the
 * hostlist response construction.
 *
 * @param cls closure, NULL
 * @param peer id of the peer, NULL for last call
 * @param hello hello message for the peer (can be NULL)
 * @param err_msg message
 */
static void
host_processor (void *cls,
                const struct GNUNET_PeerIdentity *peer,
                const struct GNUNET_HELLO_Message *hello,
                const char *err_msg)
{
  size_t old;
  size_t s;
  int has_addr;

  if (NULL != err_msg)
  {
    GNUNET_assert (NULL == peer);
    builder->pitr = NULL;
    GNUNET_free_non_null (builder->data);
    GNUNET_free (builder);
    builder = NULL;
    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                _("Error in communication with PEERINFO service: %s\n"),
                err_msg);
    return;
  }
  if (NULL == peer)
  {
    builder->pitr = NULL;
    finish_response ();
    return;
  }
  if (NULL == hello)
    return;
  has_addr = GNUNET_NO;
  GNUNET_HELLO_iterate_addresses (hello,
                                  GNUNET_NO,
                                  &check_has_addr,
                                  &has_addr);
  if (GNUNET_NO == has_addr)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "HELLO for peer `%4s' has no address, not suitable for hostlist!\n",
                GNUNET_i2s (peer));
    GNUNET_STATISTICS_update (stats,
                              gettext_noop
                              ("HELLOs without addresses encountered (ignored)"),
                              1, GNUNET_NO);
    return;
  }
  old = builder->size;
  s = GNUNET_HELLO_size (hello);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Received %u bytes of `%s' from peer `%s' for hostlist.\n",
              (unsigned int) s,
              "HELLO",
              GNUNET_i2s (peer));
  if ( (old + s >= GNUNET_MAX_MALLOC_CHECKED) ||
       (old + s >= MAX_BYTES_PER_HOSTLISTS) )
  {
    /* too large, skip! */
    GNUNET_STATISTICS_update (stats,
                              gettext_noop
                              ("bytes not included in hostlist (size limit)"),
                              s, GNUNET_NO);
    return;
  }
  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
              "Adding peer `%s' to hostlist (%u bytes)\n",
              GNUNET_i2s (peer),
              (unsigned int) s);
  GNUNET_array_grow (builder->data,
                     builder->size,
                     old + s);
  memcpy (&builder->data[old],
          hello,
          s);
}