blob: 18d860896f4d98b631a1d99533742e738c8abded [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, 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/>.
*/
#include "transport.hpp"
#include "face.hpp"
namespace nfd {
namespace face {
NFD_LOG_INIT(Transport);
const ssize_t Transport::MIN_MTU;
std::ostream&
operator<<(std::ostream& os, TransportState state)
{
switch (state) {
case TransportState::UP:
return os << "UP";
case TransportState::DOWN:
return os << "DOWN";
case TransportState::CLOSING:
return os << "CLOSING";
case TransportState::FAILED:
return os << "FAILED";
case TransportState::CLOSED:
return os << "CLOSED";
default:
return os << "NONE";
}
}
Transport::Transport()
: m_face(nullptr)
, m_service(nullptr)
, m_scope(ndn::nfd::FACE_SCOPE_NONE)
, m_persistency(ndn::nfd::FACE_PERSISTENCY_NONE)
, m_linkType(ndn::nfd::LINK_TYPE_NONE)
, m_mtu(MTU_INVALID)
, m_sendQueueCapacity(QUEUE_UNSUPPORTED)
, m_state(TransportState::UP)
, m_expirationTime(time::steady_clock::TimePoint::max())
{
}
Transport::~Transport() = default;
void
Transport::setFaceAndLinkService(Face& face, LinkService& service)
{
BOOST_ASSERT(m_face == nullptr);
BOOST_ASSERT(m_service == nullptr);
m_face = &face;
m_service = &service;
}
void
Transport::close()
{
if (m_state != TransportState::UP && m_state != TransportState::DOWN) {
return;
}
this->setState(TransportState::CLOSING);
this->doClose();
// warning: don't access any members after this:
// the Transport may be deallocated if doClose changes state to CLOSED
}
void
Transport::send(const Block& packet, const EndpointId& endpoint)
{
BOOST_ASSERT(packet.isValid());
BOOST_ASSERT(this->getMtu() == MTU_UNLIMITED ||
packet.size() <= static_cast<size_t>(this->getMtu()));
TransportState state = this->getState();
if (state != TransportState::UP && state != TransportState::DOWN) {
NFD_LOG_FACE_TRACE("send ignored in " << state << " state");
return;
}
if (state == TransportState::UP) {
++this->nOutPackets;
this->nOutBytes += packet.size();
}
this->doSend(packet, endpoint);
}
void
Transport::receive(const Block& packet, const EndpointId& endpoint)
{
BOOST_ASSERT(packet.isValid());
BOOST_ASSERT(this->getMtu() == MTU_UNLIMITED ||
packet.size() <= static_cast<size_t>(this->getMtu()));
++this->nInPackets;
this->nInBytes += packet.size();
m_service->receivePacket(packet, endpoint);
}
void
Transport::setMtu(ssize_t mtu)
{
BOOST_ASSERT(mtu == MTU_UNLIMITED || mtu >= 0);
if (mtu == m_mtu) {
return;
}
if (m_mtu != MTU_INVALID) {
NFD_LOG_FACE_INFO("setMtu " << m_mtu << " -> " << mtu);
}
m_mtu = mtu;
}
bool
Transport::canChangePersistencyTo(ndn::nfd::FacePersistency newPersistency) const
{
// not changing, or setting initial persistency in subclass constructor
if (m_persistency == newPersistency || m_persistency == ndn::nfd::FACE_PERSISTENCY_NONE) {
return true;
}
if (newPersistency == ndn::nfd::FACE_PERSISTENCY_NONE) {
NFD_LOG_FACE_TRACE("cannot change persistency to NONE");
return false;
}
return this->canChangePersistencyToImpl(newPersistency);
}
bool
Transport::canChangePersistencyToImpl(ndn::nfd::FacePersistency newPersistency) const
{
return false;
}
void
Transport::setPersistency(ndn::nfd::FacePersistency newPersistency)
{
BOOST_ASSERT(canChangePersistencyTo(newPersistency));
if (m_persistency == newPersistency) {
return;
}
auto oldPersistency = m_persistency;
m_persistency = newPersistency;
if (oldPersistency != ndn::nfd::FACE_PERSISTENCY_NONE) {
NFD_LOG_FACE_INFO("setPersistency " << oldPersistency << " -> " << newPersistency);
this->afterChangePersistency(oldPersistency);
}
}
void
Transport::afterChangePersistency(ndn::nfd::FacePersistency oldPersistency)
{
}
void
Transport::setState(TransportState newState)
{
if (m_state == newState) {
return;
}
bool isValid = false;
switch (m_state) {
case TransportState::UP:
isValid = newState == TransportState::DOWN ||
newState == TransportState::CLOSING ||
newState == TransportState::FAILED;
break;
case TransportState::DOWN:
isValid = newState == TransportState::UP ||
newState == TransportState::CLOSING ||
newState == TransportState::FAILED;
break;
case TransportState::CLOSING:
case TransportState::FAILED:
isValid = newState == TransportState::CLOSED;
break;
default:
break;
}
if (!isValid) {
NDN_THROW(std::runtime_error("Invalid state transition"));
}
NFD_LOG_FACE_INFO("setState " << m_state << " -> " << newState);
TransportState oldState = m_state;
m_state = newState;
afterStateChange(oldState, newState);
// warning: don't access any members after this:
// the Transport may be deallocated in the signal handler if newState is CLOSED
}
std::ostream&
operator<<(std::ostream& os, const FaceLogHelper<Transport>& flh)
{
const Transport& transport = flh.obj;
const Face* face = transport.getFace();
FaceId faceId = face == nullptr ? INVALID_FACEID : face->getId();
os << "[id=" << faceId << ",local=" << transport.getLocalUri()
<< ",remote=" << transport.getRemoteUri() << "] ";
return os;
}
} // namespace face
} // namespace nfd