/**
 * Notify ATS about @a delay changes to properties of an @a address.
 * Does nothing if the @a address is not known to us.
 *
 * @param address the address
 * @param delay new delay value
 */
void
GST_ats_update_delay (const struct GNUNET_HELLO_Address *address,
                      struct GNUNET_TIME_Relative delay)
{
  struct AddressInfo *ai;

  ai = find_ai_no_session (address);
  if (NULL == ai)
  {
    /* We do not know about this address, do nothing. */
    return;
  }
  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Updated latency for peer `%s' to %s\n",
       GNUNET_i2s (&address->peer),
       GNUNET_STRINGS_relative_time_to_string (delay,
                                               GNUNET_YES));
  ai->properties.delay = delay;
  /* Give manipulation its chance to change metrics */
  GST_manipulation_manipulate_metrics (address,
                                       ai->session,
                                       &ai->properties);
  /* Address may be blocked, only give ATS if address is
     currently active. */
  if (NULL != ai->ar)
    GNUNET_ATS_address_update (ai->ar,
                               &ai->properties);
}
/**
 * Notify ATS about utilization changes to an @a address.
 * Does nothing if the @a address is not known to us.
 *
 * @param address our information about the address
 * @param bps_in new utilization inbound
 * @param bps_out new utilization outbound
 */
void
GST_ats_update_utilization (const struct GNUNET_HELLO_Address *address,
                            uint32_t bps_in,
                            uint32_t bps_out)
{
  struct AddressInfo *ai;

  ai = find_ai_no_session (address);
  if (NULL == ai)
  {
    /* We do not know about this address, do nothing. */
    return;
  }
  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Updating utilization for peer `%s' address %s: %u/%u\n",
       GNUNET_i2s (&address->peer),
       GST_plugins_a2s (address),
       (unsigned int) bps_in,
       (unsigned int) bps_out);
  ai->properties.utilization_in = bps_in;
  ai->properties.utilization_out = bps_out;
  /* Give manipulation its chance to change metrics */
  GST_manipulation_manipulate_metrics (address,
                                       ai->session,
                                       &ai->properties);
  /* Address may be blocked, only give ATS if address is
     currently active. */
  if (NULL != ai->ar)
    GNUNET_ATS_address_update (ai->ar,
                               &ai->properties);
}
/**
 * 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;
}
/**
 * Notify ATS about DV @a distance change to an @a address.
 * Does nothing if the @a address is not known to us.
 *
 * @param address the address
 * @param distance new distance value
 */
void
GST_ats_update_distance (const struct GNUNET_HELLO_Address *address,
                         uint32_t distance)
{
  struct AddressInfo *ai;

  ai = find_ai_no_session (address);
  if (NULL == ai)
  {
    /* We do not know about this address, do nothing. */
    return;
  }
  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Updated distance for peer `%s' to %u\n",
       GNUNET_i2s (&address->peer),
       distance);
  ai->properties.distance = distance;
  /* Give manipulation its chance to change metrics */
  GST_manipulation_manipulate_metrics (address,
                                       ai->session,
                                       &ai->properties);
  /* Address may be blocked, only give ATS if address is
     currently active. */
  if (NULL != ai->ar)
    GNUNET_ATS_address_update (ai->ar,
                               &ai->properties);
}
/**
 * We received some payload.  Prepare to pass it on to our clients.
 *
 * @param peer (claimed) identity of the other peer
 * @param address the address
 * @param session session used
 * @param message the message to process
 * @param ats performance information
 * @param ats_count number of records in ats
 * @return how long the plugin should wait until receiving more data
 */
static struct GNUNET_TIME_Relative
process_payload (const struct GNUNET_PeerIdentity *peer,
                 const struct GNUNET_HELLO_Address *address,
                 struct Session *session,
                 const struct GNUNET_MessageHeader *message,
                 const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
{
  struct GNUNET_TIME_Relative ret;
  int do_forward;
  struct InboundMessage *im;
  size_t msg_size = ntohs (message->size);
  size_t size =
      sizeof (struct InboundMessage) + msg_size +
      sizeof (struct GNUNET_ATS_Information) * (ats_count + 1);
  char buf[size] GNUNET_ALIGN;
  struct GNUNET_ATS_Information *ap;

  ret = GNUNET_TIME_UNIT_ZERO;
  do_forward = GNUNET_SYSERR;
  ret = GST_neighbours_calculate_receive_delay (peer, msg_size, &do_forward);

  if (!GST_neighbours_test_connected (peer))
  {

    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Discarded %u bytes type %u payload from peer `%s'\n", msg_size,
                ntohs (message->type), GNUNET_i2s (peer));

    GNUNET_STATISTICS_update (GST_stats,
                              gettext_noop
                              ("# bytes payload discarded due to not connected peer "),
                              msg_size, GNUNET_NO);
    return ret;
  }

  if (do_forward != GNUNET_YES)
    return ret;
  im = (struct InboundMessage *) buf;
  im->header.size = htons (size);
  im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
  im->ats_count = htonl (ats_count + 1);
  im->peer = *peer;
  ap = (struct GNUNET_ATS_Information *) &im[1];
  memcpy (ap, ats, ats_count * sizeof (struct GNUNET_ATS_Information));
  ap[ats_count].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY);
  ap[ats_count].value =
      htonl ((uint32_t) GST_neighbour_get_latency (peer).rel_value);
  memcpy (&ap[ats_count + 1], message, ntohs (message->size));

  GNUNET_ATS_address_update (GST_ats, address, session, ap, ats_count + 1);
  GST_clients_broadcast (&im->header, GNUNET_YES);

  return ret;
}
/**
 * Function called by the transport for each received message.
 * This function should also be called with "NULL" for the
 * message to signal that the other peer disconnected.
 *
 * @param cls closure, const char* with the name of the plugin we received the message from
 * @param peer (claimed) identity of the other peer
 * @param message the message, NULL if we only care about
 *                learning about the delay until we should receive again -- FIXME!
 * @param ats performance information
 * @param ats_count number of records in ats
 * @param session identifier used for this session (NULL for plugins
 *                that do not offer bi-directional communication to the sender
 *                using the same "connection")
 * @param sender_address binary address of the sender (if we established the
 *                connection or are otherwise sure of it; should be NULL
 *                for inbound TCP/UDP connections since it it not clear
 *                that we could establish ourselves a connection to that
 *                IP address and get the same system)
 * @param sender_address_len number of bytes in sender_address
 * @return how long the plugin should wait until receiving more data
 *         (plugins that do not support this, can ignore the return value)
 */
static struct GNUNET_TIME_Relative
plugin_env_receive_callback (void *cls, const struct GNUNET_PeerIdentity *peer,
                             const struct GNUNET_MessageHeader *message,
                             const struct GNUNET_ATS_Information *ats,
                             uint32_t ats_count, struct Session *session,
                             const char *sender_address,
                             uint16_t sender_address_len)
{
  const char *plugin_name = cls;
  struct GNUNET_TIME_Relative ret;
  struct GNUNET_HELLO_Address address;
  uint16_t type;

  address.peer = *peer;
  address.address = sender_address;
  address.address_length = sender_address_len;
  address.transport_name = plugin_name;
  ret = GNUNET_TIME_UNIT_ZERO;
  if (NULL == message)
    goto end;
  type = ntohs (message->type);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received Message with type %u from peer `%s'\n", type, GNUNET_i2s (peer));

  GNUNET_STATISTICS_update (GST_stats,
                        gettext_noop
                        ("# bytes total received"),
                            ntohs (message->size), GNUNET_NO);

  switch (type)
  {
  case GNUNET_MESSAGE_TYPE_HELLO:
    GST_validation_handle_hello (message);
    return ret;
  case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
                "Processing `%s' from `%s'\n", "PING",
                (sender_address !=
                 NULL) ? GST_plugins_a2s (&address) : "<inbound>");
    GST_validation_handle_ping (peer, message, &address, session);
    break;
  case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
                "Processing `%s' from `%s'\n", "PONG",
                (sender_address !=
                 NULL) ? GST_plugins_a2s (&address) : "<inbound>");
    GST_validation_handle_pong (peer, message);
    break;
  case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT:
    GST_neighbours_handle_connect (message, peer, &address, session, ats,
                                   ats_count);
    break;
  case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT_ACK:
    GST_neighbours_handle_connect_ack (message, peer, &address, session, ats,
                                       ats_count);
    break;
  case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK:
    GST_neighbours_handle_session_ack (message, peer, &address, session, ats,
				       ats_count);
    break;
  case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT:
    GST_neighbours_handle_disconnect_message (peer, message);
    break;
  case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE:
    GST_neighbours_keepalive (peer);
    break;
  case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE:
    GST_neighbours_keepalive_response (peer, ats, ats_count);
    break;
  default:
    /* should be payload */
    GNUNET_STATISTICS_update (GST_stats,
                              gettext_noop
                              ("# bytes payload received"),
                              ntohs (message->size), GNUNET_NO);
    ret = process_payload (peer, &address, session, message, ats, ats_count);
    break;
  }
end:
#if 1
  /* FIXME: this should not be needed, and not sure it's good to have it, but without
   * this connections seem to go extra-slow */
  GNUNET_ATS_address_update (GST_ats, &address, session, ats, ats_count);
#endif
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Allowing receive from peer %s to continue in %llu ms\n",
              GNUNET_i2s (peer), (unsigned long long) ret.rel_value);
  return ret;
}
static void
address_suggest_cb (void *cls, const struct GNUNET_HELLO_Address *address,
                    struct Session *session,
                    struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
                    struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
                    const struct GNUNET_ATS_Information *atsi,
                    uint32_t ats_count)
{
  static int stage = 0;
  if (0 == stage)
  {
    GNUNET_ATS_suggest_address_cancel (sched_ats, &p.id);
    if (GNUNET_OK == compare_addresses(address, session, &test_hello_address, test_session))
    {
      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stage 0: Callback for correct address `%s'\n",
                  GNUNET_i2s (&address->peer));
      ret = 0;
    }
    else
    {
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Stage 0: Callback with incorrect address `%s'\n",
                    GNUNET_i2s (&address->peer));
      ret = 1;
      GNUNET_SCHEDULER_add_now (&end, NULL);
      return;
    }

    if (GNUNET_OK != compare_ats(atsi, ats_count, test_ats_info, test_ats_count))
    {
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Stage 0: Callback with incorrect ats info \n");
      ret = 1;
      GNUNET_SCHEDULER_add_now (&end, NULL);
      return;
    }

    /* Update address */
    /* Prepare ATS Information */
    test_ats_info[0].type = htonl (GNUNET_ATS_NETWORK_TYPE);
    test_ats_info[0].value = htonl(GNUNET_ATS_NET_WAN);
    test_ats_info[1].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE);
    test_ats_info[1].value = htonl(3);
    test_ats_info[1].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY);
    test_ats_info[1].value = htonl(30);
    test_ats_count = 2;

    GNUNET_ATS_address_update (sched_ats, &test_hello_address, test_session, test_ats_info, test_ats_count);

    /* Request address */
    GNUNET_ATS_suggest_address (sched_ats, &p.id);
    stage ++;
  }
  else if (1 == stage)
  {
      GNUNET_ATS_suggest_address_cancel (sched_ats, &p.id);
      if (GNUNET_OK == compare_addresses(address, session, &test_hello_address, test_session))
      {
        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stage 1: Callback with correct address `%s'\n",
                    GNUNET_i2s (&address->peer));
        ret = 0;
      }
      else
      {
        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Stage 1: Callback with incorrect address `%s'\n",
                    GNUNET_i2s (&address->peer));
        ret = 1;
      }

      if (GNUNET_OK != compare_ats(atsi, ats_count, test_ats_info, test_ats_count))
      {
        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Stage 1: Callback with incorrect ats info \n");
        ret = 1;
        GNUNET_SCHEDULER_add_now (&end, NULL);
        return;
      }

      GNUNET_SCHEDULER_add_now (&end, NULL);
  }
}
Exemple #8
0
/**
 * Main interpreter loop. Runs the steps of the test.
 *
 * @param cls NULL
 * @param tc unused
 */
static void
interpreter (void *cls,
             const struct GNUNET_SCHEDULER_TaskContext *tc)

{
  struct Command *cmd;

  interpreter_task = NULL;
  while (1)
  {
    cmd = &test_commands[off];
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "#%u: %d %s\n",
                off,
                (int) cmd->code,
                (NULL != cmd->label) ? cmd->label : "");
    switch (cmd->code)
    {
    case CMD_END_PASS:
      ret = 0;
      GNUNET_SCHEDULER_shutdown ();
      return;
    case CMD_ADD_ADDRESS:
      {
        struct GNUNET_HELLO_Address *addr;
        struct GNUNET_ATS_Session *session;

        addr = make_address (cmd->details.add_address.pid,
                             cmd->details.add_address.addr_num,
                             cmd->details.add_address.addr_flags);
        session = make_session (cmd->details.add_address.session);
        if (cmd->details.add_address.expect_fail)
          GNUNET_log_skip (1, GNUNET_NO);
        cmd->details.add_address.ar
          = GNUNET_ATS_address_add (sched_ats,
                                    addr,
                                    session,
                                    &cmd->details.add_address.properties);
        GNUNET_free (addr);
        if (cmd->details.add_address.expect_fail)
        {
          GNUNET_log_skip (0, GNUNET_YES);
        }
        else if (NULL == cmd->details.add_address.ar)
        {
          GNUNET_break (0);
          GNUNET_SCHEDULER_shutdown ();
          return;
        }
        off++;
        break;
      }
    case CMD_DEL_ADDRESS:
      {
        struct Command *add;

        add = find_command (CMD_ADD_ADDRESS,
                            cmd->details.del_address.add_label);
        GNUNET_assert (NULL != add->details.add_address.ar);
        GNUNET_ATS_address_destroy (add->details.add_address.ar);
        add->details.add_address.ar = NULL;
        off++;
        break;
      }
    case CMD_AWAIT_ADDRESS_SUGGESTION:
      {
        struct GNUNET_PeerIdentity pid;
        struct GNUNET_HELLO_Address *addr;
        struct Command *add;
        struct AddressSuggestData *asd;
        int done;

        make_peer (cmd->details.await_address_suggestion.pid,
                   &pid);
        asd = find_address_suggestion (&pid);
        if (NULL == asd)
          return;
        if (GNUNET_NO == asd->active)
          return; /* last suggestion was to disconnect, wait longer */
        done = GNUNET_YES;
        if (NULL != cmd->details.await_address_suggestion.add_label)
        {
          done = GNUNET_NO;
          add = find_command (CMD_ADD_ADDRESS,
                              cmd->details.await_address_suggestion.add_label);
          addr = make_address (add->details.add_address.pid,
                               add->details.add_address.addr_num,
                               add->details.add_address.addr_flags);
          if ( (asd->session ==
                make_session (add->details.add_address.session)) &&
               (0 ==
                GNUNET_HELLO_address_cmp (addr,
                                          asd->address)) )
            done = GNUNET_YES;
          GNUNET_free (addr);
        }
        if (GNUNET_NO == done)
          return;
        off++;
        break;
      }
    case CMD_AWAIT_DISCONNECT_SUGGESTION:
      {
        struct GNUNET_PeerIdentity pid;
        struct AddressSuggestData *asd;

        make_peer (cmd->details.await_disconnect_suggestion.pid,
                   &pid);
        asd = find_address_suggestion (&pid);
        if (NULL == asd)
          return; /* odd, no suggestion at all yet!? */
        if (GNUNET_YES == asd->active)
          return; /* last suggestion was to activate, wait longer */
        /* last suggestion was to deactivate, condition satisfied! */
        off++;
        break;
      }
    case CMD_REQUEST_CONNECTION_START:
      {
        struct GNUNET_PeerIdentity pid;

        make_peer (cmd->details.request_connection_start.pid,
                   &pid);
        cmd->details.request_connection_start.csh
          = GNUNET_ATS_connectivity_suggest (con_ats,
                                             &pid,
                                             1);
        off++;
        break;
      }
    case CMD_REQUEST_CONNECTION_STOP:
      {
        struct Command *start;

        start = find_command (CMD_REQUEST_CONNECTION_START,
                              cmd->details.request_connection_stop.connect_label);
        GNUNET_ATS_connectivity_suggest_cancel (start->details.request_connection_start.csh);
        start->details.request_connection_start.csh = NULL;
        off++;
        break;
      }
    case CMD_AWAIT_ADDRESS_INFORMATION:
      {
        struct AddressInformationData *aid;
        struct Command *add;
        struct Command *update;
        struct GNUNET_HELLO_Address *addr;
        const struct GNUNET_ATS_Properties *cmp;

        add = find_command (CMD_ADD_ADDRESS,
                            cmd->details.await_address_information.add_label);
        update = find_command (CMD_UPDATE_ADDRESS,
                               cmd->details.await_address_information.update_label);
        addr = make_address (add->details.add_address.pid,
                             add->details.add_address.addr_num,
                             add->details.add_address.addr_flags);
        aid = find_address_information (addr);
        GNUNET_free (addr);
        if (NULL == update)
          cmp = &add->details.add_address.properties;
        else
          cmp = &update->details.update_address.properties;
        if ( (NULL != aid) &&
             (cmp->delay.rel_value_us == aid->properties.delay.rel_value_us) &&
             (cmp->utilization_out == aid->properties.utilization_out) &&
             (cmp->utilization_in == aid->properties.utilization_in) &&
             (cmp->distance == aid->properties.distance) &&
             (cmp->scope == aid->properties.scope) )
        {
          off++;
          break;
        }
        return;
      }
    case CMD_UPDATE_ADDRESS:
      {
        struct Command *add;

        add = find_command (CMD_ADD_ADDRESS,
                            cmd->details.update_address.add_label);
        GNUNET_assert (NULL != add->details.add_address.ar);
        GNUNET_ATS_address_update (add->details.add_address.ar,
                                   &cmd->details.update_address.properties);
        off++;
        break;
      }
    case CMD_ADD_SESSION:
      {
        struct Command *add;
        struct GNUNET_ATS_Session *session;

        add = find_command (CMD_ADD_ADDRESS,
                            cmd->details.add_session.add_label);
        session = make_session (cmd->details.add_session.session);
        GNUNET_assert (NULL != add->details.add_address.ar);
        GNUNET_ATS_address_add_session (add->details.add_address.ar,
                                        session);
        off++;
        break;
      }
    case CMD_DEL_SESSION:
      {
        struct Command *add_address;
        struct Command *add_session;
        struct GNUNET_ATS_Session *session;

        add_session = find_command (CMD_ADD_SESSION,
                                    cmd->details.del_session.add_session_label);
        add_address = find_command (CMD_ADD_ADDRESS,
                                    add_session->details.add_session.add_label);
        GNUNET_assert (NULL != add_address->details.add_address.ar);
        session = make_session (add_session->details.add_session.session);
        GNUNET_ATS_address_del_session (add_address->details.add_address.ar,
                                        session);
        off++;
        break;
      }
    case CMD_CHANGE_PREFERENCE:
      {
        struct GNUNET_PeerIdentity pid;

        make_peer (cmd->details.change_preference.pid,
                   &pid);
        GNUNET_ATS_performance_change_preference (perf_ats,
                                                  &pid,
                                                  GNUNET_ATS_PREFERENCE_END);
        off++;
        break;
      }
    case CMD_PROVIDE_FEEDBACK:
      {
        struct GNUNET_PeerIdentity pid;

        make_peer (cmd->details.provide_feedback.pid,
                   &pid);
        GNUNET_ATS_performance_give_feedback (perf_ats,
                                              &pid,
                                              cmd->details.provide_feedback.scope,
                                              GNUNET_ATS_PREFERENCE_END);
        off++;
        break;
      }
    case CMD_LIST_ADDRESSES:
      {
        struct GNUNET_PeerIdentity pid;

        make_peer (cmd->details.list_addresses.pid,
                   &pid);
        cmd->details.list_addresses.alh
          = GNUNET_ATS_performance_list_addresses (perf_ats,
                                                   &pid,
                                                   cmd->details.list_addresses.all,
                                                   &info_cb,
                                                   cmd);
        return;
      }
    case CMD_RESERVE_BANDWIDTH:
      {
        struct GNUNET_PeerIdentity pid;

        make_peer (cmd->details.reserve_bandwidth.pid,
                   &pid);
        cmd->details.reserve_bandwidth.rc
          = GNUNET_ATS_reserve_bandwidth (perf_ats,
                                          &pid,
                                          cmd->details.reserve_bandwidth.amount,
                                          &reservation_cb,
                                          cmd);
        return;
      }
    case CMD_SLEEP:
      off++;
      interpreter_task = GNUNET_SCHEDULER_add_delayed (cmd->details.sleep.delay,
                                                       &interpreter,
                                                       NULL);
      return;
    } /* end switch */
  } /* end while(1) */
}
/**
 * We've received a PONG.  Check if it matches a pending PING and
 * mark the respective address as confirmed.
 *
 * @param sender peer sending the PONG
 * @param hdr the PONG
 */
void
GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender,
                            const struct GNUNET_MessageHeader *hdr)
{
  const struct TransportPongMessage *pong;
  struct ValidationEntry *ve;
  const char *tname;
  const char *addr;
  size_t addrlen;
  size_t slen;
  size_t size;
  struct GNUNET_HELLO_Message *hello;
  struct GNUNET_HELLO_Address address;

  if (ntohs (hdr->size) < sizeof (struct TransportPongMessage))
  {
    GNUNET_break_op (0);
    return;
  }
  GNUNET_STATISTICS_update (GST_stats,
                            gettext_noop ("# PONG messages received"), 1,
                            GNUNET_NO);

  pong = (const struct TransportPongMessage *) hdr;
  tname = (const char *) &pong[1];
  size = ntohs (hdr->size) - sizeof (struct TransportPongMessage);
  addr = memchr (tname, '\0', size);
  if (NULL == addr)
  {
    GNUNET_break_op (0);
    return;
  }
  addr++;
  slen = strlen (tname) + 1;
  addrlen = size - slen;
  address.peer = *sender;
  address.address = addr;
  address.address_length = addrlen;
  address.transport_name = tname;
  ve = find_validation_entry (NULL, &address);
  if ((NULL == ve) || (ve->expecting_pong == GNUNET_NO))
  {
    GNUNET_STATISTICS_update (GST_stats,
                              gettext_noop
                              ("# PONGs dropped, no matching pending validation"),
                              1, GNUNET_NO);
    return;
  }
  /* now check that PONG is well-formed */
  if (0 != memcmp (&ve->pid, sender, sizeof (struct GNUNET_PeerIdentity)))
  {
    GNUNET_break_op (0);
    return;
  }

  if (GNUNET_OK !=
      GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
                                &pong->purpose, &pong->signature,
                                &ve->public_key))
  {
    GNUNET_break_op (0);
    return;
  }

  if (GNUNET_TIME_absolute_get_remaining
      (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
  {
    GNUNET_STATISTICS_update (GST_stats,
                              gettext_noop
                              ("# PONGs dropped, signature expired"), 1,
                              GNUNET_NO);
    return;
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Address validated for peer `%s' with plugin `%s': `%s'\n",

              GNUNET_i2s (sender), tname, GST_plugins_a2s (ve->address));
  /* validity achieved, remember it! */
  ve->expecting_pong = GNUNET_NO;
  ve->valid_until = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
  ve->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
  {
    struct GNUNET_ATS_Information ats;

    ats.type = htonl (GNUNET_ATS_QUALITY_NET_DELAY);
    ats.value = htonl ((uint32_t) ve->latency.rel_value);
    GNUNET_ATS_address_update (GST_ats, ve->address, NULL, &ats, 1);
  }
  /* build HELLO to store in PEERINFO */
  ve->copied = GNUNET_NO;
  hello = GNUNET_HELLO_create (&ve->public_key, &add_valid_peer_address, ve);
  GNUNET_PEERINFO_add_peer (GST_peerinfo, hello, NULL, NULL);
  GNUNET_free (hello);
}