| /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
| /* |
| * Copyright (c) 2014-2022, 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-common.hpp" |
| #include "common/counter.hpp" |
| |
| namespace nfd::face { |
| |
| /** \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 that the transport has no limit on payload size |
| */ |
| constexpr ssize_t MTU_UNLIMITED = -1; |
| |
| /** |
| * \brief (for internal use) Indicates that the MTU field is unset |
| */ |
| constexpr ssize_t MTU_INVALID = -2; |
| |
| /** |
| * \brief Indicates that the transport does not support reading the queue capacity/length |
| */ |
| constexpr ssize_t QUEUE_UNSUPPORTED = -1; |
| |
| /** |
| * \brief Indicates that the transport was unable to retrieve the queue capacity/length |
| */ |
| constexpr 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 |
| * \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); |
| |
| 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 |
| * \pre transport state is either UP or DOWN |
| */ |
| virtual void |
| doSend(const Block& packet) = 0; |
| |
| 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 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> |
| std::enable_if_t<std::is_base_of_v<Transport, T> && !std::is_same_v<Transport, T>, |
| std::ostream&> |
| operator<<(std::ostream& os, const FaceLogHelper<T>& flh) |
| { |
| return os << FaceLogHelper<Transport>(flh.obj); |
| } |
| |
| } // namespace nfd::face |
| |
| #endif // NFD_DAEMON_FACE_TRANSPORT_HPP |