/**
 * Function called to notify transport users that another
 * peer connected to us.
 *
 * @param cls closure
 * @param peer the peer that connected
 * @param ats performance data
 * @param ats_count number of entries in ats
 */
static void
neighbours_connect_notification (void *cls,
                                 const struct GNUNET_PeerIdentity *peer,
                                 const struct GNUNET_ATS_Information *ats,
                                 uint32_t ats_count)
{
  size_t len =
      sizeof (struct ConnectInfoMessage) +
      ats_count * sizeof (struct GNUNET_ATS_Information);
  char buf[len] GNUNET_ALIGN;
  struct ConnectInfoMessage *connect_msg = (struct ConnectInfoMessage *) buf;
  struct GNUNET_ATS_Information *ap;

  connections++;
  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
              "We are now connected to peer `%s' and %u peers in total\n",
              GNUNET_i2s (peer), connections);

  connect_msg->header.size = htons (sizeof (buf));
  connect_msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
  connect_msg->ats_count = htonl (ats_count);
  connect_msg->id = *peer;
  ap = (struct GNUNET_ATS_Information *) &connect_msg[1];
  memcpy (ap, ats, ats_count * sizeof (struct GNUNET_ATS_Information));
  GST_clients_broadcast (&connect_msg->header, GNUNET_NO);
}
/**
 * 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;
}
/**
 * My HELLO has changed. Tell everyone who should know.
 *
 * @param cls unused
 * @param hello new HELLO
 */
static void
process_hello_update (void *cls,
                      const struct GNUNET_MessageHeader *hello)
{
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Broadcasting HELLO to clients\n");
  GST_clients_broadcast (hello, GNUNET_NO);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Broadcasting HELLO to neighbours\n");
  GST_neighbours_iterate (&transmit_our_hello,
                          (void *) hello);
}
/**
 * Function called to notify transport users that another
 * peer disconnected from us.
 *
 * @param cls closure
 * @param peer the peer that disconnected
 */
static void
neighbours_disconnect_notification (void *cls,
                                    const struct GNUNET_PeerIdentity *peer)
{
  struct DisconnectInfoMessage disconnect_msg;

  connections--;
  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
              "Peer `%s' disconnected and we are connected to %u peers\n",
              GNUNET_i2s (peer), connections);

  disconnect_msg.header.size = htons (sizeof (struct DisconnectInfoMessage));
  disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
  disconnect_msg.reserved = htonl (0);
  disconnect_msg.peer = *peer;
  GST_clients_broadcast (&disconnect_msg.header, GNUNET_NO);
}
/**
 * We received some payload.  Prepare to pass it on to our clients.
 *
 * @param address address and (claimed) identity of the other peer
 * @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 message the message to process
 * @return how long the plugin should wait until receiving more data
 */
static struct GNUNET_TIME_Relative
process_payload (const struct GNUNET_HELLO_Address *address,
                 struct GNUNET_ATS_Session *session,
                 const struct GNUNET_MessageHeader *message)
{
  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;
  char buf[size] GNUNET_ALIGN;

  do_forward = GNUNET_SYSERR;
  ret = GST_neighbours_calculate_receive_delay (&address->peer,
						msg_size,
						&do_forward);
  if (! GST_neighbours_test_connected (&address->peer))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Discarded %u bytes type %u payload from peer `%s'\n",
                msg_size,
                ntohs (message->type),
                GNUNET_i2s (&address->peer));
    GNUNET_STATISTICS_update (GST_stats, gettext_noop
                              ("# bytes payload discarded due to not connected peer"),
                              msg_size,
                              GNUNET_NO);
    return ret;
  }

  if (GNUNET_YES != do_forward)
    return ret;
  im = (struct InboundMessage *) buf;
  im->header.size = htons (size);
  im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
  im->peer = address->peer;
  memcpy (&im[1], message, ntohs (message->size));
  GST_clients_broadcast (&im->header, GNUNET_YES);
  return ret;
}
/**
 * My HELLO has changed. Tell everyone who should know.
 *
 * @param cls unused
 * @param hello new HELLO
 */
static void
process_hello_update (void *cls, const struct GNUNET_MessageHeader *hello)
{
  GST_clients_broadcast (hello, GNUNET_NO);
  GST_neighbours_iterate (&transmit_our_hello, (void *) hello);
}