face: Transport::getMtu

refs #3253

Change-Id: Ia4c5cfe210a99b798ce7d05f74ebdd7cfab214f4
diff --git a/daemon/face/multicast-udp-transport.cpp b/daemon/face/multicast-udp-transport.cpp
index 7befa78..a1f376b 100644
--- a/daemon/face/multicast-udp-transport.cpp
+++ b/daemon/face/multicast-udp-transport.cpp
@@ -24,6 +24,7 @@
  */
 
 #include "multicast-udp-transport.hpp"
+#include "udp-protocol.hpp"
 
 namespace nfd {
 namespace face {
@@ -41,8 +42,10 @@
 {
   this->setLocalUri(FaceUri(localEndpoint));
   this->setRemoteUri(FaceUri(multicastGroup));
+  this->setScope(ndn::nfd::FACE_SCOPE_NON_LOCAL);
   this->setPersistency(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
   this->setLinkType(ndn::nfd::LINK_TYPE_MULTI_ACCESS);
+  this->setMtu(udp::computeMtu(localEndpoint));
 
   NFD_LOG_FACE_INFO("Creating transport");
 }
diff --git a/daemon/face/transport.cpp b/daemon/face/transport.cpp
index fa1159d..d6008f7 100644
--- a/daemon/face/transport.cpp
+++ b/daemon/face/transport.cpp
@@ -53,6 +53,7 @@
 
 Transport::Packet::Packet(Block&& packet1)
   : packet(std::move(packet1))
+  , remoteEndpoint(0)
 {
 }
 
@@ -62,9 +63,12 @@
   , m_scope(ndn::nfd::FACE_SCOPE_NON_LOCAL)
   , m_persistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT)
   , m_linkType(ndn::nfd::LINK_TYPE_POINT_TO_POINT)
+  , m_mtu(MTU_UNLIMITED)
   , m_state(TransportState::UP)
   , m_counters(nullptr)
 {
+  // warning: Subclass constructor must explicitly initialize all static properties
+  // using setters, and should not rely on the defaults here.
 }
 
 Transport::~Transport()
@@ -96,8 +100,17 @@
 }
 
 void
-Transport::send(Transport::Packet&& packet)
+Transport::send(Packet&& packet)
 {
+  BOOST_ASSERT(this->getMtu() == MTU_UNLIMITED ||
+               packet.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;
+  }
+
   // TODO#3177 increment LpPacket counter
   m_counters->getNOutBytes() += packet.packet.size();
 
@@ -105,8 +118,11 @@
 }
 
 void
-Transport::receive(Transport::Packet&& packet)
+Transport::receive(Packet&& packet)
 {
+  BOOST_ASSERT(this->getMtu() == MTU_UNLIMITED ||
+               packet.packet.size() <= static_cast<size_t>(this->getMtu()));
+
   // TODO#3177 increment LpPacket counter
   m_counters->getNInBytes() += packet.packet.size();
 
diff --git a/daemon/face/transport.hpp b/daemon/face/transport.hpp
index 144e0dc..b7f1c30 100644
--- a/daemon/face/transport.hpp
+++ b/daemon/face/transport.hpp
@@ -51,6 +51,10 @@
 std::ostream&
 operator<<(std::ostream& os, TransportState state);
 
+/** \brief indicates the transport has no limit on payload size
+ */
+const ssize_t MTU_UNLIMITED = -1;
+
 /** \brief the lower part of an LpFace
  *  \sa LpFace
  */
@@ -125,12 +129,15 @@
   close();
 
   /** \brief send a link-layer packet
+   *  \note This operation has no effect if \p getState() is neither UP nor DOWN
+   *  \warning undefined behavior if packet size exceeds MTU limit
    */
   void
   send(Packet&& packet);
 
 protected: // upper interface to be invoked by subclass
   /** \brief receive a link-layer packet
+   *  \warning undefined behavior if packet size exceeds MTU limit
    */
   void
   receive(Packet&& packet);
@@ -166,6 +173,18 @@
   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;
+
 public: // dynamic properties
   /** \return transport state
    */
@@ -189,6 +208,9 @@
   void
   setLinkType(ndn::nfd::LinkType linkType);
 
+  void
+  setMtu(ssize_t mtu);
+
   /** \brief set transport state
    *
    *  Only the following transitions are valid:
@@ -213,8 +235,11 @@
 
   /** \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 can happen synchronously or asynchronously.
+   *  This transition can happen synchronously or asynchronously.
    */
   virtual void
   doClose() = 0;
@@ -222,6 +247,7 @@
 private: // to be overridden by subclass
   /** \brief performs Transport specific operations to send a packet
    *  \param packet the packet, which must be a well-formed TLV block
+   *  \pre state is either UP or DOWN
    */
   virtual void
   doSend(Packet&& packet) = 0;
@@ -234,6 +260,7 @@
   ndn::nfd::FaceScope m_scope;
   ndn::nfd::FacePersistency m_persistency;
   ndn::nfd::LinkType m_linkType;
+  ssize_t m_mtu;
   TransportState m_state;
   LinkLayerCounters* m_counters; // TODO#3177 change into LinkCounters
 };
@@ -262,18 +289,36 @@
   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
 {
@@ -293,36 +338,31 @@
   return m_linkType;
 }
 
-inline TransportState
-Transport::getState() const
-{
-  return m_state;
-}
-
-inline void
-Transport::setLocalUri(const FaceUri& uri)
-{
-  m_localUri = uri;
-}
-
-inline void
-Transport::setRemoteUri(const FaceUri& uri)
-{
-  m_remoteUri = uri;
-}
-
-inline void
-Transport::setScope(ndn::nfd::FaceScope scope)
-{
-  m_scope = scope;
-}
-
 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 TransportState
+Transport::getState() const
+{
+  return m_state;
+}
+
 std::ostream&
 operator<<(std::ostream& os, const FaceLogHelper<Transport>& flh);
 
diff --git a/daemon/face/udp-protocol.cpp b/daemon/face/udp-protocol.cpp
new file mode 100644
index 0000000..fb51a3a
--- /dev/null
+++ b/daemon/face/udp-protocol.cpp
@@ -0,0 +1,47 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015,  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 "udp-protocol.hpp"
+
+namespace nfd {
+namespace udp {
+
+ssize_t
+computeMtu(const boost::asio::ip::udp::endpoint& localEndpoint)
+{
+  size_t mtu = 0;
+  if (localEndpoint.address().is_v4()) { // IPv4
+    mtu = std::numeric_limits<uint16_t>::max(); // maximum Total Length
+    mtu -= sizeof(uint32_t) * ((1 << 4) - 1); // maximum Internet Header Length
+  }
+  else { // IPv6
+    mtu = std::numeric_limits<uint16_t>::max(); // maximum Payload Length
+  }
+  mtu -= sizeof(uint16_t) * 4; // size of UDP header
+  return mtu;
+}
+
+} // namespace udp
+} // namespace nfd
diff --git a/daemon/face/udp-protocol.hpp b/daemon/face/udp-protocol.hpp
new file mode 100644
index 0000000..76a7bed
--- /dev/null
+++ b/daemon/face/udp-protocol.hpp
@@ -0,0 +1,42 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015,  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_UDP_PROTOCOL_HPP
+#define NFD_DAEMON_FACE_UDP_PROTOCOL_HPP
+
+#include "common.hpp"
+
+namespace nfd {
+namespace udp {
+
+/** \brief computes maximum payload size in a UDP packet
+ */
+ssize_t
+computeMtu(const boost::asio::ip::udp::endpoint& localEndpoint);
+
+} // namespace udp
+} // namespace nfd
+
+#endif // NFD_DAEMON_FACE_UDP_PROTOCOL_HPP
diff --git a/daemon/face/unicast-udp-transport.cpp b/daemon/face/unicast-udp-transport.cpp
index eb8ab66..a5fb3e7 100644
--- a/daemon/face/unicast-udp-transport.cpp
+++ b/daemon/face/unicast-udp-transport.cpp
@@ -24,6 +24,7 @@
  */
 
 #include "unicast-udp-transport.hpp"
+#include "udp-protocol.hpp"
 
 #ifdef __linux__
 #include <cerrno>       // for errno
@@ -47,8 +48,10 @@
 {
   this->setLocalUri(FaceUri(m_socket.local_endpoint()));
   this->setRemoteUri(FaceUri(m_socket.remote_endpoint()));
+  this->setScope(ndn::nfd::FACE_SCOPE_NON_LOCAL);
   this->setPersistency(persistency);
   this->setLinkType(ndn::nfd::LINK_TYPE_POINT_TO_POINT);
+  this->setMtu(udp::computeMtu(m_socket.local_endpoint()));
 
   NFD_LOG_FACE_INFO("Creating transport");
 
diff --git a/daemon/face/unicast-udp-transport.hpp b/daemon/face/unicast-udp-transport.hpp
index 2622e4b..0a9beed 100644
--- a/daemon/face/unicast-udp-transport.hpp
+++ b/daemon/face/unicast-udp-transport.hpp
@@ -23,8 +23,8 @@
  * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef NFD_DAEMON_FACE_UDP_TRANSPORT_HPP
-#define NFD_DAEMON_FACE_UDP_TRANSPORT_HPP
+#ifndef NFD_DAEMON_FACE_UNICAST_UDP_TRANSPORT_HPP
+#define NFD_DAEMON_FACE_UNICAST_UDP_TRANSPORT_HPP
 
 #include "datagram-transport.hpp"
 #include "core/scheduler.hpp"
@@ -35,7 +35,7 @@
 /**
  * \brief A Transport that communicates on a unicast UDP socket
  */
-class UnicastUdpTransport : public DatagramTransport<boost::asio::ip::udp>
+class UnicastUdpTransport : public DatagramTransport<boost::asio::ip::udp, Unicast>
 {
 public:
   UnicastUdpTransport(protocol::socket&& socket,
@@ -55,4 +55,4 @@
 } // namespace face
 } // namespace nfd
 
-#endif // NFD_DAEMON_FACE_UDP_TRANSPORT_HPP
+#endif // NFD_DAEMON_FACE_UNICAST_UDP_TRANSPORT_HPP
diff --git a/daemon/face/unix-stream-transport.cpp b/daemon/face/unix-stream-transport.cpp
index 17351f0..e9e2eab 100644
--- a/daemon/face/unix-stream-transport.cpp
+++ b/daemon/face/unix-stream-transport.cpp
@@ -43,6 +43,8 @@
   this->setRemoteUri(FaceUri::fromFd(m_socket.native_handle()));
   this->setScope(ndn::nfd::FACE_SCOPE_LOCAL);
   this->setPersistency(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
+  this->setLinkType(ndn::nfd::LINK_TYPE_POINT_TO_POINT);
+  this->setMtu(MTU_UNLIMITED);
 
   NFD_LOG_FACE_INFO("Creating Transport");
 }