face: refactor handling of LinkType face trait

This commit also includes some cleanups, fixes EthernetFace to report
the correct LinkType, and makes (get|set)Description non-virtual.

Change-Id: I53909d7bfa02a92641b523a766359413c966aae6
Refs: #2563
diff --git a/daemon/face/channel.hpp b/daemon/face/channel.hpp
index 810d726..ea4b751 100644
--- a/daemon/face/channel.hpp
+++ b/daemon/face/channel.hpp
@@ -25,10 +25,12 @@
 #ifndef NFD_DAEMON_FACE_CHANNEL_HPP
 #define NFD_DAEMON_FACE_CHANNEL_HPP
 
-#include "face.hpp"
+#include "common.hpp"
 
 namespace nfd {
 
+class Face;
+
 class Channel : noncopyable
 {
 public:
diff --git a/daemon/face/datagram-face.hpp b/daemon/face/datagram-face.hpp
index 4fb075e..886a8b3 100644
--- a/daemon/face/datagram-face.hpp
+++ b/daemon/face/datagram-face.hpp
@@ -31,10 +31,10 @@
 
 namespace nfd {
 
-class Unicast {};
-class Multicast {};
+struct Unicast {};
+struct Multicast {};
 
-template<class Protocol, class Type = Unicast>
+template<class Protocol, class Addressing = Unicast>
 class DatagramFace : public Face
 {
 public:
@@ -43,12 +43,9 @@
   /** \brief Construct datagram face
    *
    * \param socket      Protocol-specific socket for the created face
-   * \param isOnDemand  If true, the face can be closed after it remains
-   *                    unused for a certain amount of time
    */
   DatagramFace(const FaceUri& remoteUri, const FaceUri& localUri,
-               const shared_ptr<typename protocol::socket>& socket,
-               bool isOnDemand);
+               const shared_ptr<typename protocol::socket>& socket);
 
   // from Face
   void
@@ -65,9 +62,6 @@
                   size_t nBytesReceived,
                   const boost::system::error_code& error);
 
-  void
-  setOnDemand(bool isOnDemand);
-
 protected:
   void
   processErrorCode(const boost::system::error_code& error);
@@ -110,15 +104,12 @@
 template<class T, class U>
 inline
 DatagramFace<T, U>::DatagramFace(const FaceUri& remoteUri, const FaceUri& localUri,
-                                 const shared_ptr<typename DatagramFace::protocol::socket>& socket,
-                                 bool isOnDemand)
-  : Face(remoteUri, localUri)
+                                 const shared_ptr<typename DatagramFace::protocol::socket>& socket)
+  : Face(remoteUri, localUri, false, std::is_same<U, Multicast>::value)
   , m_socket(socket)
 {
   NFD_LOG_FACE_INFO("Creating face");
 
-  setOnDemand(isOnDemand);
-
   m_socket->async_receive(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE), 0,
                           bind(&DatagramFace<T, U>::handleReceive, this, _1, _2));
 }
@@ -276,13 +267,6 @@
 }
 
 template<class T, class U>
-inline void
-DatagramFace<T, U>::setOnDemand(bool isOnDemand)
-{
-  Face::setOnDemand(isOnDemand);
-}
-
-template<class T, class U>
 inline bool
 DatagramFace<T, U>::hasBeenUsedRecently() const
 {
diff --git a/daemon/face/ethernet-face.cpp b/daemon/face/ethernet-face.cpp
index 9ba95e0..8bd2c7b 100644
--- a/daemon/face/ethernet-face.cpp
+++ b/daemon/face/ethernet-face.cpp
@@ -65,7 +65,7 @@
 EthernetFace::EthernetFace(const shared_ptr<boost::asio::posix::stream_descriptor>& socket,
                            const NetworkInterfaceInfo& interface,
                            const ethernet::Address& address)
-  : Face(FaceUri(address), FaceUri::fromDev(interface.name))
+  : Face(FaceUri(address), FaceUri::fromDev(interface.name), false, true)
   , m_pcap(nullptr, pcap_close)
   , m_socket(socket)
 #if defined(__linux__)
diff --git a/daemon/face/face.cpp b/daemon/face/face.cpp
index 06bae23..0974cf2 100644
--- a/daemon/face/face.cpp
+++ b/daemon/face/face.cpp
@@ -29,12 +29,13 @@
 
 namespace nfd {
 
-Face::Face(const FaceUri& remoteUri, const FaceUri& localUri, bool isLocal)
+Face::Face(const FaceUri& remoteUri, const FaceUri& localUri, bool isLocal, bool isMultiAccess)
   : m_id(INVALID_FACEID)
-  , m_isLocal(isLocal)
   , m_remoteUri(remoteUri)
   , m_localUri(localUri)
+  , m_isLocal(isLocal)
   , m_isOnDemand(false)
+  , m_isMultiAccess(isMultiAccess)
   , m_isFailed(false)
 {
   onReceiveInterest.connect([this] (const ndn::Interest&) { ++m_counters.getNInInterests(); });
@@ -47,37 +48,6 @@
 {
 }
 
-FaceId
-Face::getId() const
-{
-  return m_id;
-}
-
-// this method is private and should be used only by the FaceTable
-void
-Face::setId(FaceId faceId)
-{
-  m_id = faceId;
-}
-
-void
-Face::setDescription(const std::string& description)
-{
-  m_description = description;
-}
-
-const std::string&
-Face::getDescription() const
-{
-  return m_description;
-}
-
-bool
-Face::isMultiAccess() const
-{
-  return false;
-}
-
 bool
 Face::isUp() const
 {
diff --git a/daemon/face/face.hpp b/daemon/face/face.hpp
index 142d14f..58deb3d 100644
--- a/daemon/face/face.hpp
+++ b/daemon/face/face.hpp
@@ -30,7 +30,6 @@
 #include "core/logger.hpp"
 #include "face-counters.hpp"
 
-#include <ndn-cxx/util/face-uri.hpp>
 #include <ndn-cxx/management/nfd-face-status.hpp>
 
 namespace nfd {
@@ -52,7 +51,6 @@
 /// upper bound of reserved FaceIds
 const FaceId FACEID_RESERVED_MAX = 255;
 
-using ndn::util::FaceUri;
 
 /** \brief represents a face
  */
@@ -72,7 +70,8 @@
     }
   };
 
-  Face(const FaceUri& remoteUri, const FaceUri& localUri, bool isLocal = false);
+  Face(const FaceUri& remoteUri, const FaceUri& localUri,
+       bool isLocal = false, bool isMultiAccess = false);
 
   virtual
   ~Face();
@@ -112,27 +111,31 @@
   FaceId
   getId() const;
 
-  /** \brief Set the description
-   *
-   *  This is typically invoked by mgmt on set description command
+  /** \brief Get the description
    */
-  virtual void
-  setDescription(const std::string& description);
-
-  /// Get the description
-  virtual const std::string&
+  const std::string&
   getDescription() const;
 
+  /** \brief Set the face description
+   *
+   *  This is typically invoked by management on set description command
+   */
+  void
+  setDescription(const std::string& description);
+
   /** \brief Get whether face is connected to a local app
    */
   bool
   isLocal() const;
 
-  /** \brief Get whether packets sent this Face may reach multiple peers
-   *
-   *  In this base class this property is always false.
+  /** \brief Get whether face is created on demand or explicitly via FaceManagement protocol
    */
-  virtual bool
+  bool
+  isOnDemand() const;
+
+  /** \brief Get whether packets sent by this face may reach multiple peers
+   */
+  bool
   isMultiAccess() const;
 
   /** \brief Get whether underlying communication is up
@@ -142,11 +145,6 @@
   virtual bool
   isUp() const;
 
-  /** \brief Get whether face is created on demand or explicitly via FaceManagement protocol
-   */
-  bool
-  isOnDemand() const;
-
   const FaceCounters&
   getCounters() const;
 
@@ -171,51 +169,95 @@
   virtual ndn::nfd::FaceStatus
   getFaceStatus() const;
 
-protected:
-  // this is a non-virtual method
-  bool
-  decodeAndDispatchInput(const Block& element);
-
-  FaceCounters&
-  getMutableCounters();
-
+PUBLIC_WITH_TESTS_ELSE_PROTECTED:
   void
   setOnDemand(bool isOnDemand);
 
+protected:
+  bool
+  decodeAndDispatchInput(const Block& element);
+
   /** \brief fail the face and raise onFail event if it's UP; otherwise do nothing
    */
   void
   fail(const std::string& reason);
 
+  FaceCounters&
+  getMutableCounters();
+
   DECLARE_SIGNAL_EMIT(onReceiveInterest)
   DECLARE_SIGNAL_EMIT(onReceiveData)
   DECLARE_SIGNAL_EMIT(onSendInterest)
   DECLARE_SIGNAL_EMIT(onSendData)
 
 private:
+  // this method should be used only by the FaceTable
   void
   setId(FaceId faceId);
 
 private:
   FaceId m_id;
   std::string m_description;
-  bool m_isLocal; // for scoping purposes
   FaceCounters m_counters;
-  FaceUri m_remoteUri;
-  FaceUri m_localUri;
+  const FaceUri m_remoteUri;
+  const FaceUri m_localUri;
+  const bool m_isLocal;
   bool m_isOnDemand;
+  const bool m_isMultiAccess;
   bool m_isFailed;
 
   // allow setting FaceId
   friend class FaceTable;
 };
 
+inline FaceId
+Face::getId() const
+{
+  return m_id;
+}
+
+inline void
+Face::setId(FaceId faceId)
+{
+  m_id = faceId;
+}
+
+inline const std::string&
+Face::getDescription() const
+{
+  return m_description;
+}
+
+inline void
+Face::setDescription(const std::string& description)
+{
+  m_description = description;
+}
+
 inline bool
 Face::isLocal() const
 {
   return m_isLocal;
 }
 
+inline bool
+Face::isOnDemand() const
+{
+  return m_isOnDemand;
+}
+
+inline void
+Face::setOnDemand(bool isOnDemand)
+{
+  m_isOnDemand = isOnDemand;
+}
+
+inline bool
+Face::isMultiAccess() const
+{
+  return m_isMultiAccess;
+}
+
 inline const FaceCounters&
 Face::getCounters() const
 {
@@ -240,18 +282,6 @@
   return m_localUri;
 }
 
-inline void
-Face::setOnDemand(bool isOnDemand)
-{
-  m_isOnDemand = isOnDemand;
-}
-
-inline bool
-Face::isOnDemand() const
-{
-  return m_isOnDemand;
-}
-
 
 /** \defgroup FaceLogging Face logging macros
  *
diff --git a/daemon/face/multicast-udp-face.cpp b/daemon/face/multicast-udp-face.cpp
index 9eb38c3..910f1cb 100644
--- a/daemon/face/multicast-udp-face.cpp
+++ b/daemon/face/multicast-udp-face.cpp
@@ -35,13 +35,10 @@
                                    const shared_ptr<MulticastUdpFace::protocol::socket>& sendSocket,
                                    const MulticastUdpFace::protocol::endpoint& localEndpoint,
                                    const MulticastUdpFace::protocol::endpoint& multicastEndpoint)
-  : DatagramFace<protocol, Multicast>(FaceUri(multicastEndpoint),
-                                      FaceUri(localEndpoint),
-                                      recvSocket, false)
+  : DatagramFace(FaceUri(multicastEndpoint), FaceUri(localEndpoint), recvSocket)
   , m_multicastGroup(multicastEndpoint)
   , m_sendSocket(sendSocket)
 {
-  NFD_LOG_FACE_INFO("Creating face");
 }
 
 const MulticastUdpFace::protocol::endpoint&
@@ -80,10 +77,4 @@
   sendBlock(data.wireEncode());
 }
 
-bool
-MulticastUdpFace::isMultiAccess() const
-{
-  return true;
-}
-
 } // namespace nfd
diff --git a/daemon/face/multicast-udp-face.hpp b/daemon/face/multicast-udp-face.hpp
index c08375b..eff4394 100644
--- a/daemon/face/multicast-udp-face.hpp
+++ b/daemon/face/multicast-udp-face.hpp
@@ -55,9 +55,6 @@
   void
   sendData(const Data& data) DECL_OVERRIDE;
 
-  bool
-  isMultiAccess() const DECL_OVERRIDE;
-
 private:
   void
   sendBlock(const Block& block);
diff --git a/daemon/face/protocol-factory.hpp b/daemon/face/protocol-factory.hpp
index 0542017..1c12cc0 100644
--- a/daemon/face/protocol-factory.hpp
+++ b/daemon/face/protocol-factory.hpp
@@ -26,11 +26,12 @@
 #ifndef NFD_DAEMON_FACE_PROTOCOL_FACTORY_HPP
 #define NFD_DAEMON_FACE_PROTOCOL_FACTORY_HPP
 
-#include "face.hpp"
+#include "common.hpp"
 
 namespace nfd {
 
 class Channel;
+class Face;
 
 /**
  * \brief Prototype for the callback called when face is created
@@ -69,9 +70,8 @@
              const FaceCreatedCallback& onCreated,
              const FaceConnectFailedCallback& onConnectFailed) = 0;
 
-  virtual std::list<shared_ptr<const Channel> >
+  virtual std::list<shared_ptr<const Channel>>
   getChannels() const = 0;
-
 };
 
 } // namespace nfd
diff --git a/daemon/face/stream-face.hpp b/daemon/face/stream-face.hpp
index 0383d4c..fb51afd 100644
--- a/daemon/face/stream-face.hpp
+++ b/daemon/face/stream-face.hpp
@@ -117,15 +117,15 @@
 template<class T, class FaceBase>
 inline
 StreamFace<T, FaceBase>::StreamFace(const FaceUri& remoteUri, const FaceUri& localUri,
-                const shared_ptr<typename StreamFace::protocol::socket>& socket,
-                bool isOnDemand)
+                                    const shared_ptr<typename StreamFace::protocol::socket>& socket,
+                                    bool isOnDemand)
   : FaceBase(remoteUri, localUri)
   , m_socket(socket)
   , m_inputBufferSize(0)
 {
   NFD_LOG_FACE_INFO("Creating face");
 
-  FaceBase::setOnDemand(isOnDemand);
+  this->setOnDemand(isOnDemand);
   StreamFaceValidator<T, FaceBase>::validateSocket(*socket);
 
   m_socket->async_receive(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE), 0,
diff --git a/daemon/face/udp-face.cpp b/daemon/face/udp-face.cpp
index 27c78b3..7206984 100644
--- a/daemon/face/udp-face.cpp
+++ b/daemon/face/udp-face.cpp
@@ -38,14 +38,13 @@
 NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(DatagramFace, UdpFace::protocol, "UdpFace");
 
 UdpFace::UdpFace(const shared_ptr<UdpFace::protocol::socket>& socket,
-                 bool isOnDemand,
-                 const time::seconds& idleTimeout)
-  : DatagramFace<protocol>(FaceUri(socket->remote_endpoint()),
-                           FaceUri(socket->local_endpoint()),
-                           socket, isOnDemand)
+                 bool isOnDemand, const time::seconds& idleTimeout)
+  : DatagramFace(FaceUri(socket->remote_endpoint()), FaceUri(socket->local_endpoint()), socket)
   , m_idleTimeout(idleTimeout)
   , m_lastIdleCheck(time::steady_clock::now())
 {
+  this->setOnDemand(isOnDemand);
+
 #ifdef __linux__
   //
   // By default, Linux does path MTU discovery on IPv4 sockets,
@@ -67,7 +66,7 @@
     }
 #endif
 
-  if (isOnDemand && m_idleTimeout > time::seconds::zero()) {
+  if (this->isOnDemand() && m_idleTimeout > time::seconds::zero()) {
     m_closeIfIdleEvent = scheduler::schedule(m_idleTimeout,
                                              bind(&UdpFace::closeIfIdle, this));
   }
diff --git a/daemon/face/udp-face.hpp b/daemon/face/udp-face.hpp
index f6c3183..e73c1e1 100644
--- a/daemon/face/udp-face.hpp
+++ b/daemon/face/udp-face.hpp
@@ -32,15 +32,14 @@
 namespace nfd {
 
 /**
- * \brief Implementation of Face abstraction that uses UDP
- *        as underlying transport mechanism
+ * \brief Implementation of Face abstraction that uses
+ *        unicast UDP as underlying transport mechanism
  */
 class UdpFace : public DatagramFace<boost::asio::ip::udp>
 {
 public:
   UdpFace(const shared_ptr<protocol::socket>& socket,
-          bool isOnDemand,
-          const time::seconds& idleTimeout);
+          bool isOnDemand, const time::seconds& idleTimeout);
 
   ~UdpFace() DECL_OVERRIDE;
 
@@ -55,6 +54,9 @@
   const time::seconds m_idleTimeout;
   time::steady_clock::TimePoint m_lastIdleCheck;
   scheduler::EventId m_closeIfIdleEvent;
+
+  // friend because it needs to invoke protected Face::setOnDemand
+  friend class UdpChannel;
 };
 
 } // namespace nfd