face: override Transport::beforeChangePersistency in all subclasses

This commit also adds the final specifier to some Transport
subclasses in order to improve code generation.

Change-Id: If2979fa1614476a98019ba79cee3961663fc447b
Refs: #3318
diff --git a/daemon/face/datagram-transport.hpp b/daemon/face/datagram-transport.hpp
index f9cf2fc..b435a18 100644
--- a/daemon/face/datagram-transport.hpp
+++ b/daemon/face/datagram-transport.hpp
@@ -54,12 +54,6 @@
   explicit
   DatagramTransport(typename protocol::socket&& socket);
 
-  virtual void
-  doSend(Transport::Packet&& packet) DECL_OVERRIDE;
-
-  virtual void
-  doClose() DECL_OVERRIDE;
-
   /** \brief Receive datagram, translate buffer into packet, deliver to parent class.
    */
   void
@@ -67,15 +61,21 @@
                   const boost::system::error_code& error);
 
 protected:
-  void
-  handleReceive(const boost::system::error_code& error,
-                size_t nBytesReceived);
+  virtual void
+  doClose() DECL_OVERRIDE;
+
+  virtual void
+  doSend(Transport::Packet&& packet) DECL_OVERRIDE;
 
   void
   handleSend(const boost::system::error_code& error,
              size_t nBytesSent, const Block& payload);
 
   void
+  handleReceive(const boost::system::error_code& error,
+                size_t nBytesReceived);
+
+  void
   processErrorCode(const boost::system::error_code& error);
 
   bool
@@ -96,7 +96,6 @@
 
 
 template<class T, class U>
-inline
 DatagramTransport<T, U>::DatagramTransport(typename DatagramTransport::protocol::socket&& socket)
   : m_socket(std::move(socket))
 {
@@ -107,20 +106,7 @@
 }
 
 template<class T, class U>
-inline void
-DatagramTransport<T, U>::doSend(Transport::Packet&& packet)
-{
-  NFD_LOG_FACE_TRACE(__func__);
-
-  m_socket.async_send(boost::asio::buffer(packet.packet),
-                      bind(&DatagramTransport<T, U>::handleSend, this,
-                           boost::asio::placeholders::error,
-                           boost::asio::placeholders::bytes_transferred,
-                           packet.packet));
-}
-
-template<class T, class U>
-inline void
+void
 DatagramTransport<T, U>::doClose()
 {
   NFD_LOG_FACE_TRACE(__func__);
@@ -141,7 +127,20 @@
 }
 
 template<class T, class U>
-inline void
+void
+DatagramTransport<T, U>::doSend(Transport::Packet&& packet)
+{
+  NFD_LOG_FACE_TRACE(__func__);
+
+  m_socket.async_send(boost::asio::buffer(packet.packet),
+                      bind(&DatagramTransport<T, U>::handleSend, this,
+                           boost::asio::placeholders::error,
+                           boost::asio::placeholders::bytes_transferred,
+                           packet.packet));
+}
+
+template<class T, class U>
+void
 DatagramTransport<T, U>::receiveDatagram(const uint8_t* buffer, size_t nBytesReceived,
                                          const boost::system::error_code& error)
 {
@@ -169,7 +168,7 @@
 }
 
 template<class T, class U>
-inline void
+void
 DatagramTransport<T, U>::handleReceive(const boost::system::error_code& error,
                                        size_t nBytesReceived)
 {
@@ -183,7 +182,7 @@
 }
 
 template<class T, class U>
-inline void
+void
 DatagramTransport<T, U>::handleSend(const boost::system::error_code& error,
                                     size_t nBytesSent, const Block& payload)
 // 'payload' is unused; it's needed to retain the underlying Buffer
@@ -195,7 +194,7 @@
 }
 
 template<class T, class U>
-inline void
+void
 DatagramTransport<T, U>::processErrorCode(const boost::system::error_code& error)
 {
   NFD_LOG_FACE_TRACE(__func__);
diff --git a/daemon/face/internal-transport.cpp b/daemon/face/internal-transport.cpp
index 070a4b5..cc3e0a6 100644
--- a/daemon/face/internal-transport.cpp
+++ b/daemon/face/internal-transport.cpp
@@ -46,6 +46,15 @@
 }
 
 void
+InternalForwarderTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
+{
+  if (newPersistency != ndn::nfd::FACE_PERSISTENCY_PERMANENT) {
+    BOOST_THROW_EXCEPTION(
+      std::invalid_argument("InternalForwarderTransport supports only FACE_PERSISTENCY_PERMANENT"));
+  }
+}
+
+void
 InternalForwarderTransport::receiveFromLink(const Block& packet)
 {
   NFD_LOG_FACE_TRACE(__func__);
diff --git a/daemon/face/internal-transport.hpp b/daemon/face/internal-transport.hpp
index a282638..53bd379 100644
--- a/daemon/face/internal-transport.hpp
+++ b/daemon/face/internal-transport.hpp
@@ -63,6 +63,9 @@
 
 protected:
   virtual void
+  beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_OVERRIDE;
+
+  virtual void
   doClose() DECL_OVERRIDE;
 
 private:
diff --git a/daemon/face/multicast-udp-transport.cpp b/daemon/face/multicast-udp-transport.cpp
index a1f376b..544b4ff 100644
--- a/daemon/face/multicast-udp-transport.cpp
+++ b/daemon/face/multicast-udp-transport.cpp
@@ -51,6 +51,15 @@
 }
 
 void
+MulticastUdpTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
+{
+  if (newPersistency != ndn::nfd::FACE_PERSISTENCY_PERMANENT) {
+    BOOST_THROW_EXCEPTION(
+      std::invalid_argument("MulticastUdpTransport supports only FACE_PERSISTENCY_PERMANENT"));
+  }
+}
+
+void
 MulticastUdpTransport::doSend(Transport::Packet&& packet)
 {
   NFD_LOG_FACE_TRACE(__func__);
diff --git a/daemon/face/multicast-udp-transport.hpp b/daemon/face/multicast-udp-transport.hpp
index 14371f7..2998f42 100644
--- a/daemon/face/multicast-udp-transport.hpp
+++ b/daemon/face/multicast-udp-transport.hpp
@@ -34,7 +34,7 @@
 /**
  * \brief A Transport that communicates on a UDP multicast group
  */
-class MulticastUdpTransport : public DatagramTransport<boost::asio::ip::udp, Multicast>
+class MulticastUdpTransport DECL_FINAL : public DatagramTransport<boost::asio::ip::udp, Multicast>
 {
 public:
   /**
@@ -46,14 +46,19 @@
    */
   MulticastUdpTransport(const protocol::endpoint& localEndpoint,
                         const protocol::endpoint& multicastGroup,
-                        protocol::socket&& recvSocket, protocol::socket&& sendSocket);
+                        protocol::socket&& recvSocket,
+                        protocol::socket&& sendSocket);
+
+protected:
+  virtual void
+  beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_FINAL;
 
 private:
   virtual void
-  doSend(Transport::Packet&& packet) DECL_OVERRIDE;
+  doSend(Transport::Packet&& packet) DECL_FINAL;
 
   virtual void
-  doClose() DECL_OVERRIDE;
+  doClose() DECL_FINAL;
 
 private:
   protocol::endpoint m_multicastGroup;
diff --git a/daemon/face/stream-transport.hpp b/daemon/face/stream-transport.hpp
index e9ec78d..1c9b720 100644
--- a/daemon/face/stream-transport.hpp
+++ b/daemon/face/stream-transport.hpp
@@ -51,16 +51,16 @@
   explicit
   StreamTransport(typename protocol::socket&& socket);
 
-  virtual void
-  doSend(Transport::Packet&& packet) DECL_OVERRIDE;
-
+protected:
   virtual void
   doClose() DECL_OVERRIDE;
 
-protected:
   void
   deferredClose();
 
+  virtual void
+  doSend(Transport::Packet&& packet) DECL_OVERRIDE;
+
   void
   sendFromQueue();
 
@@ -81,42 +81,25 @@
   NFD_LOG_INCLASS_DECLARE();
 
 private:
-  uint8_t m_inputBuffer[ndn::MAX_NDN_PACKET_SIZE];
-  size_t m_inputBufferSize;
+  uint8_t m_receiveBuffer[ndn::MAX_NDN_PACKET_SIZE];
+  size_t m_receiveBufferSize;
   std::queue<Block> m_sendQueue;
 };
 
-// All derived classes must use
-// NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(StreamTransport, <specialization-parameter>, "Name");
-
 
 template<class T>
-inline
 StreamTransport<T>::StreamTransport(typename StreamTransport::protocol::socket&& socket)
   : m_socket(std::move(socket))
-  , m_inputBufferSize(0)
+  , m_receiveBufferSize(0)
 {
-  m_socket.async_receive(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE),
+  m_socket.async_receive(boost::asio::buffer(m_receiveBuffer, ndn::MAX_NDN_PACKET_SIZE),
                          bind(&StreamTransport<T>::handleReceive, this,
                               boost::asio::placeholders::error,
                               boost::asio::placeholders::bytes_transferred));
 }
 
 template<class T>
-inline void
-StreamTransport<T>::doSend(Transport::Packet&& packet)
-{
-  NFD_LOG_FACE_TRACE(__func__);
-
-  bool wasQueueEmpty = m_sendQueue.empty();
-  m_sendQueue.push(packet.packet);
-
-  if (wasQueueEmpty)
-    sendFromQueue();
-}
-
-template<class T>
-inline void
+void
 StreamTransport<T>::doClose()
 {
   NFD_LOG_FACE_TRACE(__func__);
@@ -148,7 +131,7 @@
 }
 
 template<class T>
-inline void
+void
 StreamTransport<T>::deferredClose()
 {
   NFD_LOG_FACE_TRACE(__func__);
@@ -165,7 +148,20 @@
 }
 
 template<class T>
-inline void
+void
+StreamTransport<T>::doSend(Transport::Packet&& packet)
+{
+  NFD_LOG_FACE_TRACE(__func__);
+
+  bool wasQueueEmpty = m_sendQueue.empty();
+  m_sendQueue.push(packet.packet);
+
+  if (wasQueueEmpty)
+    sendFromQueue();
+}
+
+template<class T>
+void
 StreamTransport<T>::sendFromQueue()
 {
   boost::asio::async_write(m_socket, boost::asio::buffer(m_sendQueue.front()),
@@ -175,7 +171,7 @@
 }
 
 template<class T>
-inline void
+void
 StreamTransport<T>::handleSend(const boost::system::error_code& error,
                                size_t nBytesSent)
 {
@@ -192,7 +188,7 @@
 }
 
 template<class T>
-inline void
+void
 StreamTransport<T>::handleReceive(const boost::system::error_code& error,
                                   size_t nBytesReceived)
 {
@@ -201,26 +197,24 @@
 
   NFD_LOG_FACE_TRACE("Received: " << nBytesReceived << " bytes");
 
-  m_inputBufferSize += nBytesReceived;
+  m_receiveBufferSize += nBytesReceived;
 
   size_t offset = 0;
 
   bool isOk = true;
   Block element;
-  while (m_inputBufferSize - offset > 0) {
-    std::tie(isOk, element) = Block::fromBuffer(m_inputBuffer + offset, m_inputBufferSize - offset);
+  while (m_receiveBufferSize - offset > 0) {
+    std::tie(isOk, element) = Block::fromBuffer(m_receiveBuffer + offset, m_receiveBufferSize - offset);
     if (!isOk)
       break;
 
     offset += element.size();
+    BOOST_ASSERT(offset <= m_receiveBufferSize);
 
-    BOOST_ASSERT(offset <= m_inputBufferSize);
-
-    Transport::Packet packet(std::move(element));
-    this->receive(std::move(packet));
+    this->receive(Transport::Packet(std::move(element)));
   }
 
-  if (!isOk && m_inputBufferSize == ndn::MAX_NDN_PACKET_SIZE && offset == 0) {
+  if (!isOk && m_receiveBufferSize == ndn::MAX_NDN_PACKET_SIZE && offset == 0) {
     NFD_LOG_FACE_WARN("Failed to parse incoming packet or packet too large to process");
     this->setState(TransportState::FAILED);
     doClose();
@@ -228,24 +222,24 @@
   }
 
   if (offset > 0) {
-    if (offset != m_inputBufferSize) {
-      std::copy(m_inputBuffer + offset, m_inputBuffer + m_inputBufferSize, m_inputBuffer);
-      m_inputBufferSize -= offset;
+    if (offset != m_receiveBufferSize) {
+      std::copy(m_receiveBuffer + offset, m_receiveBuffer + m_receiveBufferSize, m_receiveBuffer);
+      m_receiveBufferSize -= offset;
     }
     else {
-      m_inputBufferSize = 0;
+      m_receiveBufferSize = 0;
     }
   }
 
-  m_socket.async_receive(boost::asio::buffer(m_inputBuffer + m_inputBufferSize,
-                                             ndn::MAX_NDN_PACKET_SIZE - m_inputBufferSize),
+  m_socket.async_receive(boost::asio::buffer(m_receiveBuffer + m_receiveBufferSize,
+                                             ndn::MAX_NDN_PACKET_SIZE - m_receiveBufferSize),
                          bind(&StreamTransport<T>::handleReceive, this,
                               boost::asio::placeholders::error,
                               boost::asio::placeholders::bytes_transferred));
 }
 
 template<class T>
-inline void
+void
 StreamTransport<T>::processErrorCode(const boost::system::error_code& error)
 {
   NFD_LOG_FACE_TRACE(__func__);
diff --git a/daemon/face/tcp-transport.hpp b/daemon/face/tcp-transport.hpp
index 654f224..b2d9fcf 100644
--- a/daemon/face/tcp-transport.hpp
+++ b/daemon/face/tcp-transport.hpp
@@ -33,7 +33,7 @@
 /**
  * \brief A Transport that communicates on a connected TCP socket
  */
-class TcpTransport : public StreamTransport<boost::asio::ip::tcp>
+class TcpTransport DECL_FINAL : public StreamTransport<boost::asio::ip::tcp>
 {
 public:
   TcpTransport(protocol::socket&& socket,
@@ -41,7 +41,7 @@
 
 protected:
   virtual void
-  beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_OVERRIDE;
+  beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_FINAL;
 };
 
 } // namespace face
diff --git a/daemon/face/transport.cpp b/daemon/face/transport.cpp
index 0c4f4ee..1b7832e 100644
--- a/daemon/face/transport.cpp
+++ b/daemon/face/transport.cpp
@@ -128,6 +128,25 @@
 }
 
 void
+Transport::setPersistency(ndn::nfd::FacePersistency newPersistency)
+{
+  if (m_persistency == newPersistency) {
+    return;
+  }
+
+  if (newPersistency == ndn::nfd::FACE_PERSISTENCY_NONE) {
+    throw std::runtime_error("invalid persistency transition");
+  }
+
+  if (m_persistency != ndn::nfd::FACE_PERSISTENCY_NONE) {
+    this->beforeChangePersistency(newPersistency);
+    NFD_LOG_FACE_DEBUG("setPersistency " << m_persistency << " -> " << newPersistency);
+  }
+
+  m_persistency = newPersistency;
+}
+
+void
 Transport::setState(TransportState newState)
 {
   if (m_state == newState) {
diff --git a/daemon/face/transport.hpp b/daemon/face/transport.hpp
index 55efe3b..d069a0e 100644
--- a/daemon/face/transport.hpp
+++ b/daemon/face/transport.hpp
@@ -237,13 +237,9 @@
   /** \brief invoked before persistency is changed
    *  \throw std::invalid_argument new persistency is not supported
    *  \throw std::runtime_error transition is disallowed
-   *
-   *  Base class implementation does nothing.
    */
   virtual void
-  beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
-  {
-  }
+  beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) = 0;
 
   /** \brief performs Transport specific operations to close the transport
    *
@@ -337,13 +333,6 @@
   return m_persistency;
 }
 
-inline void
-Transport::setPersistency(ndn::nfd::FacePersistency persistency)
-{
-  this->beforeChangePersistency(persistency);
-  m_persistency = persistency;
-}
-
 inline ndn::nfd::LinkType
 Transport::getLinkType() const
 {
diff --git a/daemon/face/unicast-udp-transport.cpp b/daemon/face/unicast-udp-transport.cpp
index a5fb3e7..3bd4759 100644
--- a/daemon/face/unicast-udp-transport.cpp
+++ b/daemon/face/unicast-udp-transport.cpp
@@ -41,10 +41,9 @@
 
 UnicastUdpTransport::UnicastUdpTransport(protocol::socket&& socket,
                                          ndn::nfd::FacePersistency persistency,
-                                         const time::seconds& idleTimeout)
+                                         time::nanoseconds idleTimeout)
   : DatagramTransport(std::move(socket))
   , m_idleTimeout(idleTimeout)
-  , m_lastIdleCheck(time::steady_clock::now())
 {
   this->setLocalUri(FaceUri(m_socket.local_endpoint()));
   this->setRemoteUri(FaceUri(m_socket.remote_endpoint()));
@@ -76,29 +75,36 @@
 #endif
 
   if (getPersistency() == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND &&
-      m_idleTimeout > time::seconds::zero()) {
-    m_closeIfIdleEvent = scheduler::schedule(m_idleTimeout, bind(&UnicastUdpTransport::closeIfIdle, this));
+      m_idleTimeout > time::nanoseconds::zero()) {
+    scheduleClosureWhenIdle();
   }
 }
 
 void
-UnicastUdpTransport::closeIfIdle()
+UnicastUdpTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
 {
-  // transport can be switched from on-demand to non-on-demand mode
-  // (non-on-demand -> on-demand transition is not allowed)
-  if (getPersistency() == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
+  if (newPersistency == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND &&
+      m_idleTimeout > time::nanoseconds::zero()) {
+    scheduleClosureWhenIdle();
+  }
+  else {
+    m_closeIfIdleEvent.cancel();
+  }
+}
+
+void
+UnicastUdpTransport::scheduleClosureWhenIdle()
+{
+  m_closeIfIdleEvent = scheduler::schedule(m_idleTimeout, [this] {
     if (!hasBeenUsedRecently()) {
       NFD_LOG_FACE_INFO("Closing due to inactivity");
       this->close();
     }
     else {
       resetRecentUsage();
-
-      m_lastIdleCheck = time::steady_clock::now();
-      m_closeIfIdleEvent = scheduler::schedule(m_idleTimeout, bind(&UnicastUdpTransport::closeIfIdle, this));
+      scheduleClosureWhenIdle();
     }
-  }
-  // else do nothing and do not reschedule the event
+  });
 }
 
 } // namespace face
diff --git a/daemon/face/unicast-udp-transport.hpp b/daemon/face/unicast-udp-transport.hpp
index 0a9beed..0c7c277 100644
--- a/daemon/face/unicast-udp-transport.hpp
+++ b/daemon/face/unicast-udp-transport.hpp
@@ -35,20 +35,23 @@
 /**
  * \brief A Transport that communicates on a unicast UDP socket
  */
-class UnicastUdpTransport : public DatagramTransport<boost::asio::ip::udp, Unicast>
+class UnicastUdpTransport DECL_FINAL : public DatagramTransport<boost::asio::ip::udp, Unicast>
 {
 public:
   UnicastUdpTransport(protocol::socket&& socket,
                       ndn::nfd::FacePersistency persistency,
-                      const time::seconds& idleTimeout);
+                      time::nanoseconds idleTimeout);
+
+protected:
+  virtual void
+  beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_FINAL;
 
 private:
   void
-  closeIfIdle();
+  scheduleClosureWhenIdle();
 
 private:
-  const time::seconds m_idleTimeout;
-  time::steady_clock::TimePoint m_lastIdleCheck;
+  const time::nanoseconds m_idleTimeout;
   scheduler::ScopedEventId m_closeIfIdleEvent;
 };
 
diff --git a/daemon/face/unix-stream-transport.cpp b/daemon/face/unix-stream-transport.cpp
index 0e37a42..6df0efb 100644
--- a/daemon/face/unix-stream-transport.cpp
+++ b/daemon/face/unix-stream-transport.cpp
@@ -49,5 +49,14 @@
   NFD_LOG_FACE_INFO("Creating transport");
 }
 
+void
+UnixStreamTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
+{
+  if (newPersistency != ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
+    BOOST_THROW_EXCEPTION(
+      std::invalid_argument("UnixStreamTransport supports only FACE_PERSISTENCY_ON_DEMAND"));
+  }
+}
+
 } // namespace face
 } // namespace nfd
diff --git a/daemon/face/unix-stream-transport.hpp b/daemon/face/unix-stream-transport.hpp
index 27f4eaa..dc6e74e 100644
--- a/daemon/face/unix-stream-transport.hpp
+++ b/daemon/face/unix-stream-transport.hpp
@@ -38,11 +38,15 @@
 /**
  * \brief A Transport that communicates on a stream-oriented Unix domain socket
  */
-class UnixStreamTransport : public StreamTransport<boost::asio::local::stream_protocol>
+class UnixStreamTransport DECL_FINAL : public StreamTransport<boost::asio::local::stream_protocol>
 {
 public:
   explicit
   UnixStreamTransport(protocol::socket&& socket);
+
+protected:
+  virtual void
+  beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_FINAL;
 };
 
 } // namespace face
diff --git a/daemon/face/websocket-transport.cpp b/daemon/face/websocket-transport.cpp
index 4fbed81..cf3da37 100644
--- a/daemon/face/websocket-transport.cpp
+++ b/daemon/face/websocket-transport.cpp
@@ -56,7 +56,8 @@
   NFD_LOG_FACE_INFO("Creating transport");
 }
 
-void WebSocketTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
+void
+WebSocketTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
 {
   if (newPersistency != ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
     BOOST_THROW_EXCEPTION(
diff --git a/daemon/face/websocket-transport.hpp b/daemon/face/websocket-transport.hpp
index 6bfbdc3..91a99c1 100644
--- a/daemon/face/websocket-transport.hpp
+++ b/daemon/face/websocket-transport.hpp
@@ -36,7 +36,7 @@
 /**
  * \brief A Transport that communicates on a WebSocket connection
  */
-class WebSocketTransport : public Transport
+class WebSocketTransport DECL_FINAL : public Transport
 {
 public:
   WebSocketTransport(websocketpp::connection_hdl hdl,
@@ -57,14 +57,14 @@
 
 protected:
   virtual void
-  beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_OVERRIDE;
+  beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_FINAL;
 
   virtual void
-  doClose() DECL_OVERRIDE;
+  doClose() DECL_FINAL;
 
 private:
   virtual void
-  doSend(Transport::Packet&& packet) DECL_OVERRIDE;
+  doSend(Transport::Packet&& packet) DECL_FINAL;
 
   void
   schedulePing();