blob: 2dd81a05b1b50c0cbac2bd91e3728b3b987c1550 [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
*
* NFD is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NFD 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NFD_DAEMON_FACE_TRANSPORT_HPP
#define NFD_DAEMON_FACE_TRANSPORT_HPP
#include "face-log.hpp"
#include "common/counter.hpp"
#include <ndn-cxx/encoding/nfd-constants.hpp>
namespace nfd {
namespace face {
class Face;
class LinkService;
/** \brief Identifies a remote endpoint on the link.
*
* This ID is only meaningful in the context of the same Transport.
* Incoming packets from the same remote endpoint have the same EndpointId,
* and incoming packets from different remote endpoints have different EndpointIds.
*
* Typically, a point-to-point Transport has only one meaningful EndpointId (usually 0).
*
* \sa FaceEndpoint
*/
using EndpointId = uint64_t;
/** \brief Indicates the state of a transport.
*/
enum class TransportState {
NONE,
UP, ///< the transport is up and can transmit packets
DOWN, ///< the transport is temporarily down, and is being recovered
CLOSING, ///< the transport is being closed gracefully, either by the peer or by a call to close()
FAILED, ///< the transport is being closed due to a failure
CLOSED ///< the transport is closed, and can be safely deallocated
};
std::ostream&
operator<<(std::ostream& os, TransportState state);
/** \brief Counters provided by a transport.
* \note The type name TransportCounters is an implementation detail.
* Use Transport::Counters in public API.
*/
class TransportCounters
{
public:
/** \brief count of incoming packets
*
* A 'packet' typically means a top-level TLV block.
* For a datagram-based transport, an incoming packet that cannot be parsed as TLV
* would not be counted.
*/
PacketCounter nInPackets;
/** \brief count of outgoing packets
*
* A 'packet' typically means a top-level TLV block.
* This counter is incremented only if transport is UP.
*/
PacketCounter nOutPackets;
/** \brief total incoming bytes
*
* This counter includes headers imposed by NFD (such as NDNLP),
* but excludes overhead of underlying protocol (such as IP header).
* For a datagram-based transport, an incoming packet that cannot be parsed as TLV
* would not be counted.
*/
ByteCounter nInBytes;
/** \brief total outgoing bytes
*
* This counter includes headers imposed by NFD (such as NDNLP),
* but excludes overhead of underlying protocol (such as IP header).
* This counter is increased only if transport is UP.
*/
ByteCounter nOutBytes;
};
/** \brief indicates the transport has no limit on payload size
*/
const ssize_t MTU_UNLIMITED = -1;
/** \brief (for internal use) indicates MTU field is unset
*/
const ssize_t MTU_INVALID = -2;
/** \brief indicates that the transport does not support reading the queue capacity/length
*/
const ssize_t QUEUE_UNSUPPORTED = -1;
/** \brief indicates that the transport was unable to retrieve the queue capacity/length
*/
const ssize_t QUEUE_ERROR = -2;
/** \brief The lower half of a Face.
* \sa Face
*/
class Transport : protected virtual TransportCounters, noncopyable
{
public:
/** \brief Counters provided by a transport.
* \sa TransportCounters
*/
using Counters = TransportCounters;
/** \brief Default constructor.
*
* This constructor initializes static properties to invalid values.
* Subclass constructor must explicitly set every static property.
*
* This constructor initializes TransportState to UP;
* subclass constructor can rely on this default value.
*/
Transport();
virtual
~Transport();
public:
/** \brief set Face and LinkService for Transport
* \pre setFaceAndLinkService has not been called
*/
void
setFaceAndLinkService(Face& face, LinkService& service);
/** \return Face to which this Transport is attached
*/
const Face*
getFace() const;
/** \return LinkService to which this Transport is attached
*/
const LinkService*
getLinkService() const;
/** \return LinkService to which this Transport is attached
*/
LinkService*
getLinkService();
virtual const Counters&
getCounters() const;
public: // upper interface
/** \brief Request the transport to be closed
*
* This operation is effective only if transport is in UP or DOWN state,
* otherwise it has no effect.
* The transport changes state to CLOSING, and performs cleanup procedure.
* The state will be changed to CLOSED when cleanup is complete, which may
* happen synchronously or asynchronously.
*/
void
close();
/** \brief Send a link-layer packet
* \param packet the packet to be sent, must be a valid and well-formed TLV block
* \param endpoint the destination endpoint
* \note This operation has no effect if getState() is neither UP nor DOWN
* \warning Behavior is undefined if packet size exceeds the MTU limit
*/
void
send(const Block& packet, const EndpointId& endpoint = 0);
public: // static properties
/** \return a FaceUri representing local endpoint
*/
FaceUri
getLocalUri() const;
/** \return a FaceUri representing remote endpoint
*/
FaceUri
getRemoteUri() const;
/** \return whether face is local or non-local for scope control purpose
*/
ndn::nfd::FaceScope
getScope() const;
/** \return face persistency setting
*/
ndn::nfd::FacePersistency
getPersistency() const;
/** \brief check whether the face persistency can be changed to \p newPersistency
*
* This function serves as the external API, and invokes the protected function
* canChangePersistencyToImpl to perform further checks if \p newPersistency differs
* from the current persistency.
*
* \return true if the change can be performed, false otherwise
*/
bool
canChangePersistencyTo(ndn::nfd::FacePersistency newPersistency) const;
/** \brief changes face persistency setting
*/
void
setPersistency(ndn::nfd::FacePersistency newPersistency);
/** \return the link type of the transport
*/
ndn::nfd::LinkType
getLinkType() const;
/** \return maximum payload size
* \retval MTU_UNLIMITED transport has no limit on payload size
*
* This size is the maximum packet size that can be sent or received through this transport.
*
* For a datagram-based transport, this is typically the Maximum Transmission Unit (MTU),
* after the overhead of headers introduced by the transport has been accounted for.
* For a stream-based transport, this is typically unlimited (MTU_UNLIMITED).
*/
ssize_t
getMtu() const;
/** \return capacity of the send queue (in bytes)
* \retval QUEUE_UNSUPPORTED transport does not support queue capacity retrieval
* \retval QUEUE_ERROR transport was unable to retrieve the queue capacity
*/
ssize_t
getSendQueueCapacity() const;
public: // dynamic properties
/** \return transport state
*/
TransportState
getState() const;
/** \brief signals when transport state changes
*/
signal::Signal<Transport, TransportState/*old*/, TransportState/*new*/> afterStateChange;
/** \return expiration time of the transport
* \retval time::steady_clock::TimePoint::max() the transport has indefinite lifetime
*/
time::steady_clock::TimePoint
getExpirationTime() const;
/** \return current send queue length of the transport (in octets)
* \retval QUEUE_UNSUPPORTED transport does not support queue length retrieval
* \retval QUEUE_ERROR transport was unable to retrieve the queue length
*/
virtual ssize_t
getSendQueueLength()
{
return QUEUE_UNSUPPORTED;
}
protected: // upper interface to be invoked by subclass
/** \brief Pass a received link-layer packet to the upper layer for further processing
* \param packet the received packet, must be a valid and well-formed TLV block
* \param endpoint the source endpoint
* \warning Behavior is undefined if packet size exceeds the MTU limit
*/
void
receive(const Block& packet, const EndpointId& endpoint = 0);
protected: // properties to be set by subclass
void
setLocalUri(const FaceUri& uri);
void
setRemoteUri(const FaceUri& uri);
void
setScope(ndn::nfd::FaceScope scope);
void
setLinkType(ndn::nfd::LinkType linkType);
void
setMtu(ssize_t mtu);
void
setSendQueueCapacity(ssize_t sendQueueCapacity);
/** \brief set transport state
*
* Only the following transitions are valid:
* UP->DOWN, DOWN->UP, UP/DOWN->CLOSING/FAILED, CLOSING/FAILED->CLOSED
*
* \throw std::runtime_error transition is invalid.
*/
void
setState(TransportState newState);
void
setExpirationTime(const time::steady_clock::TimePoint& expirationTime);
protected: // to be overridden by subclass
/** \brief invoked by canChangePersistencyTo to perform the check
*
* Base class implementation returns false.
*
* \param newPersistency the new persistency, guaranteed to be different from current persistency
*/
virtual bool
canChangePersistencyToImpl(ndn::nfd::FacePersistency newPersistency) const;
/** \brief invoked after the persistency has been changed
*
* The base class implementation does nothing.
* When overridden in a subclass, the function should update internal states
* after persistency setting has been changed.
*/
virtual void
afterChangePersistency(ndn::nfd::FacePersistency oldPersistency);
/** \brief performs Transport specific operations to close the transport
*
* This is invoked once by \p close() after changing state to CLOSING.
* It will not be invoked by Transport class if the transport is already CLOSING or CLOSED.
*
* When the cleanup procedure is complete, this method should change state to CLOSED.
* This transition can happen synchronously or asynchronously.
*/
virtual void
doClose() = 0;
private: // to be overridden by subclass
/** \brief performs Transport specific operations to send a packet
* \param packet the packet to be sent, can be assumed to be valid and well-formed
* \param endpoint the destination endpoint
* \pre transport state is either UP or DOWN
*/
virtual void
doSend(const Block& packet, const EndpointId& endpoint) = 0;
public:
/** \brief minimum MTU that may be set on a transport
*
* This is done to ensure the NDNLPv2 fragmentation feature functions properly.
*/
static constexpr ssize_t MIN_MTU = 64;
private:
Face* m_face;
LinkService* m_service;
FaceUri m_localUri;
FaceUri m_remoteUri;
ndn::nfd::FaceScope m_scope;
ndn::nfd::FacePersistency m_persistency;
ndn::nfd::LinkType m_linkType;
ssize_t m_mtu;
ssize_t m_sendQueueCapacity;
TransportState m_state;
time::steady_clock::TimePoint m_expirationTime;
};
inline const Face*
Transport::getFace() const
{
return m_face;
}
inline const LinkService*
Transport::getLinkService() const
{
return m_service;
}
inline LinkService*
Transport::getLinkService()
{
return m_service;
}
inline const Transport::Counters&
Transport::getCounters() const
{
return *this;
}
inline FaceUri
Transport::getLocalUri() const
{
return m_localUri;
}
inline void
Transport::setLocalUri(const FaceUri& uri)
{
m_localUri = uri;
}
inline FaceUri
Transport::getRemoteUri() const
{
return m_remoteUri;
}
inline void
Transport::setRemoteUri(const FaceUri& uri)
{
m_remoteUri = uri;
}
inline ndn::nfd::FaceScope
Transport::getScope() const
{
return m_scope;
}
inline void
Transport::setScope(ndn::nfd::FaceScope scope)
{
m_scope = scope;
}
inline ndn::nfd::FacePersistency
Transport::getPersistency() const
{
return m_persistency;
}
inline ndn::nfd::LinkType
Transport::getLinkType() const
{
return m_linkType;
}
inline void
Transport::setLinkType(ndn::nfd::LinkType linkType)
{
m_linkType = linkType;
}
inline ssize_t
Transport::getMtu() const
{
return m_mtu;
}
inline void
Transport::setMtu(ssize_t mtu)
{
BOOST_ASSERT(mtu == MTU_UNLIMITED || mtu > 0);
m_mtu = mtu;
}
inline ssize_t
Transport::getSendQueueCapacity() const
{
return m_sendQueueCapacity;
}
inline void
Transport::setSendQueueCapacity(ssize_t sendQueueCapacity)
{
m_sendQueueCapacity = sendQueueCapacity;
}
inline TransportState
Transport::getState() const
{
return m_state;
}
inline time::steady_clock::TimePoint
Transport::getExpirationTime() const
{
return m_expirationTime;
}
inline void
Transport::setExpirationTime(const time::steady_clock::TimePoint& expirationTime)
{
m_expirationTime = expirationTime;
}
std::ostream&
operator<<(std::ostream& os, const FaceLogHelper<Transport>& flh);
template<typename T>
typename std::enable_if<std::is_base_of<Transport, T>::value &&
!std::is_same<Transport, T>::value, std::ostream&>::type
operator<<(std::ostream& os, const FaceLogHelper<T>& flh)
{
return os << FaceLogHelper<Transport>(flh.obj);
}
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_TRANSPORT_HPP