/*
     This file is part of GNUnet.
     Copyright (C) 2009-2016 GNUnet e.V.

     GNUnet is free software: you can redistribute it and/or modify it
     under the terms of the GNU Affero General Public License as published
     by the Free Software Foundation, either version 3 of the License,
     or (at your option) any later version.

     GNUnet is distributed in the hope that it will be useful, but
     WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     Affero General Public License for more details.

     You should have received a copy of the GNU Affero General Public License
     along with this program.  If not, see <http://www.gnu.org/licenses/>.

     SPDX-License-Identifier: AGPL3.0-or-later
 */

/**
 * @addtogroup Backbone
 * @{
 *
 * @author Christian Grothoff
 *
 * @file
 * Monitoring / diagnostics API for the transport service
 *
 * @defgroup TNG Transport Next Generation service
 * Communication with other peers
 *
 * @see [Documentation](https://gnunet.org/transport-service)
 *
 * @{
 */
#ifndef GNUNET_TRANSPORT_MONITOR_SERVICE_H
#define GNUNET_TRANSPORT_MONITOR_SERVICE_H

#ifdef __cplusplus
extern "C"
{
#if 0                           /* keep Emacsens' auto-indent happy */
}
#endif
#endif


#include "gnunet_util_lib.h"
#include "gnunet_transport_communication_service.h"


/**
 * Version number of the transport API.
 */
#define GNUNET_TRANSPORT_MONITOR_VERSION 0x00000000


/**
 * Information about another peer's address.
 */
struct GNUNET_TRANSPORT_MonitorInformation
{
  /**
   * Address we have for the peer, human-readable, 0-terminated, in UTF-8.
   */
  const char *address;

  /**
   * Network type of the address.
   */
  enum GNUNET_NetworkType nt;

  /**
   * Connection status.
   */
  enum GNUNET_TRANSPORT_ConnectionStatus cs;

  /**
   * Number of messages pending transmission for this @e address.
   */
  uint32_t num_msg_pending;

  /**
   * Number of bytes pending transmission for this @e address.
   */
  uint32_t num_bytes_pending;

  /**
   * When was this address last validated.
   */
  struct GNUNET_TIME_Absolute last_validation;

  /**
   * When does this address expire.
   */
  struct GNUNET_TIME_Absolute valid_until;

  /**
   * Time of the next validation operation.
   */
  struct GNUNET_TIME_Absolute next_validation;

  /**
   * Current estimate of the RTT.
   */
  struct GNUNET_TIME_Relative rtt;
};


/**
 * Function to call with information about a peer.
 *
 * If one_shot was set to #GNUNET_YES to iterate over all peers once,
 * a final call with NULL for peer and address will follow when done.
 * In this case state and timeout do not contain valid values.
 *
 * The #GNUNET_TRANSPORT_monitor_peers_cancel() call MUST not be called from
 * within this function!
 *
 *
 * @param cls closure
 * @param peer peer this update is about,
 *        NULL if this is the final last callback for a iteration operation
 * @param mi monitoring data on the peer
 */
typedef void
(*GNUNET_TRANSPORT_MonitorCallback) (void *cls,
                                     const struct GNUNET_PeerIdentity *peer,
                                     const struct
                                     GNUNET_TRANSPORT_MonitorInformation *mi);


/**
 * Handle for a #GNUNET_TRANSPORT_monitor() operation.
 */
struct GNUNET_TRANSPORT_MonitorContext;


/**
 * Return information about a specific peer or all peers currently known to
 * transport service once or in monitoring mode. To obtain information about
 * a specific peer, a peer identity can be passed. To obtain information about
 * all peers currently known to transport service, NULL can be passed as peer
 * identity.
 *
 * For each peer, the callback is called with information about the address used
 * to communicate with this peer, the state this peer is currently in and the
 * the current timeout for this state.
 *
 * Upon completion, the #GNUNET_TRANSPORT_PeerIterateCallback is called one
 * more time with `NULL`. After this, the operation must no longer be
 * explicitly canceled.
 *
 * The #GNUNET_TRANSPORT_monitor_peers_cancel call MUST not be called in the
 * the peer_callback!
 *
 * @param cfg configuration to use
 * @param peer a specific peer identity to obtain information for,
 *      NULL for all peers
 * @param one_shot #GNUNET_YES to return the current state and then end (with NULL+NULL),
 *                 #GNUNET_NO to monitor peers continuously
 * @param cb function to call with the results
 * @param cb_cls closure for @a mc
 */
struct GNUNET_TRANSPORT_MonitorContext *
GNUNET_TRANSPORT_monitor (const struct GNUNET_CONFIGURATION_Handle *cfg,
                          const struct GNUNET_PeerIdentity *peer,
                          int one_shot,
                          GNUNET_TRANSPORT_MonitorCallback cb,
                          void *cb_cls);


/**
 * Cancel request to monitor peers
 *
 * @param mc handle for the request to cancel
 */
void
GNUNET_TRANSPORT_monitor_cancel (struct GNUNET_TRANSPORT_MonitorContext *mc);


/**
 * How is a virtual link routed?
 */
enum GNUNET_TRANSPORT_LinkRoute
{
  /**
   * Over one or more queues to a directly connected neighbour.
   */
  GNUNET_TRANSPORT_LINK_ROUTE_DIRECT = 0,

  /**
   * Over a distance vector path.
   */
  GNUNET_TRANSPORT_LINK_ROUTE_DV = 1
};


/**
 * State of one virtual link, the abstraction CORE sits on top of.
 */
struct GNUNET_TRANSPORT_LinkInformation
{
  /**
   * Comma-separated address prefixes of the communicators currently
   * carrying the link ("tcp", "udp", ...), never NULL but possibly the
   * empty string.  For a DV link these are the communicators to the next
   * hop of the shortest path, not to the target.
   */
  const char *communicators;

  /**
   * How the link is routed.
   */
  enum GNUNET_TRANSPORT_LinkRoute route;

  /**
   * #GNUNET_YES if the link is confirmed, i.e. established.
   */
  int confirmed;

  /**
   * Hops of the shortest DV path, excluding the next hop and the target
   * itself; so 0 already means two hops.  Meaningless if @e route is
   * #GNUNET_TRANSPORT_LINK_ROUTE_DIRECT.
   */
  unsigned int distance;

  /**
   * Number of queues to the neighbour carrying the link.
   */
  unsigned int num_queues;

  /**
   * How many more messages we may hand to CORE before it must
   * acknowledge them.  At or below zero exactly when transport is
   * withholding flow control credit from the communicators; combined with
   * a non-zero @e stalled that is a link CORE has stopped draining.
   */
  int core_recv_window;

  /**
   * Number of messages whose flow control ACK transport is withholding
   * because @e core_recv_window is exhausted.
   */
  unsigned int stalled;

  /**
   * Number of messages queued for transmission to the target.
   */
  unsigned int pending;

  /**
   * Number of flow control retransmissions of the running task.
   */
  unsigned int fc_retransmit_count;

  /**
   * RAM transport is willing to spend on this link.
   */
  uint64_t available_fc_window_size;

  /**
   * RAM currently held for this link.
   */
  uint64_t incoming_fc_window_size_ram;

  /**
   * Window we last granted the other peer.
   */
  uint64_t incoming_fc_window_size;

  /**
   * How much of @e incoming_fc_window_size the other peer used.
   */
  uint64_t incoming_fc_window_size_used;

  /**
   * Current estimate of the message loss rate for the sender.  May be
   * negative on out-of-order delivery.
   */
  int64_t incoming_fc_window_size_loss;

  /**
   * Window the other peer granted us.
   */
  uint64_t outbound_fc_window_size;

  /**
   * How much of @e outbound_fc_window_size we used.
   */
  uint64_t outbound_fc_window_size_used;

  /**
   * RTT of the last flow control exchange.
   */
  struct GNUNET_TIME_Relative last_fc_rtt;

  /**
   * RTT over all DV paths, as calculated by the target.
   */
  struct GNUNET_TIME_Relative other_rtt;

  /**
   * When did we last send a flow control message?
   */
  struct GNUNET_TIME_Absolute last_fc_transmission;
};


/**
 * Function called once per virtual link, and a final time with @a peer
 * and @a li both NULL to signal the end of the listing.
 *
 * @param cls closure
 * @param peer peer at the other end of the link, NULL when done
 * @param li state of the link, NULL when done
 */
typedef void
(*GNUNET_TRANSPORT_LinkCallback) (
  void *cls,
  const struct GNUNET_PeerIdentity *peer,
  const struct GNUNET_TRANSPORT_LinkInformation *li);


/**
 * Handle for a #GNUNET_TRANSPORT_links_list() operation.
 */
struct GNUNET_TRANSPORT_LinkListContext;


/**
 * Ask the transport service for the virtual links it currently has.
 *
 * @a cb is invoked once per link and then a final time with NULL for both
 * @a peer and the link information, after which the operation must no
 * longer be cancelled.
 *
 * @param cfg configuration to use
 * @param peer a specific link to report on, NULL for all links
 * @param include_unconfirmed #GNUNET_YES to also report links that are not
 *                 established yet, #GNUNET_NO for established links only
 * @param cb function to call with the results
 * @param cb_cls closure for @a cb
 * @return NULL if the transport service could not be reached
 */
struct GNUNET_TRANSPORT_LinkListContext *
GNUNET_TRANSPORT_links_list (const struct GNUNET_CONFIGURATION_Handle *cfg,
                             const struct GNUNET_PeerIdentity *peer,
                             int include_unconfirmed,
                             GNUNET_TRANSPORT_LinkCallback cb,
                             void *cb_cls);


/**
 * Cancel a request to list virtual links.  Must not be called once the
 * final callback has run.
 *
 * @param llc handle for the request to cancel
 */
void
GNUNET_TRANSPORT_links_list_cancel (
  struct GNUNET_TRANSPORT_LinkListContext *llc);


#if 0                           /* keep Emacsens' auto-indent happy */
{
#endif
#ifdef __cplusplus
}
#endif

/* ifndef GNUNET_TRANSPORT_MONITOR_SERVICE_H */
#endif

/** @} */  /* end of group */

/** @} */ /* end of group addition */

/* end of gnunet_transport_monitor_service.h */
