face: Moving idle UdpFace closing logic to UdpFace class

Change-Id: Ia7310fa18681f17d93c8214ce744da909fea7022
Refs: #1686
diff --git a/daemon/mgmt/face-flags.hpp b/daemon/face/face-flags.hpp
similarity index 100%
rename from daemon/mgmt/face-flags.hpp
rename to daemon/face/face-flags.hpp
diff --git a/daemon/face/face.cpp b/daemon/face/face.cpp
index 9d2368b..ea08f5b 100644
--- a/daemon/face/face.cpp
+++ b/daemon/face/face.cpp
@@ -24,6 +24,7 @@
  **/
 
 #include "face.hpp"
+#include "face-flags.hpp"
 #include "core/logger.hpp"
 
 namespace nfd {
@@ -128,4 +129,23 @@
   this->onFail(reason);
 }
 
+ndn::nfd::FaceStatus
+Face::getFaceStatus() const
+{
+  const FaceCounters& counters = getCounters();
+
+  ndn::nfd::FaceStatus status;
+  status.setFaceId(getId())
+    .setRemoteUri(getRemoteUri().toString())
+    .setLocalUri(getLocalUri().toString())
+    .setFlags(getFaceFlags(*this))
+    .setNInInterests(counters.getNInInterests())
+    .setNInDatas(counters.getNInDatas())
+    .setNOutInterests(counters.getNOutInterests())
+    .setNOutDatas(counters.getNOutDatas());
+
+  return status;
+}
+
+
 } //namespace nfd
diff --git a/daemon/face/face.hpp b/daemon/face/face.hpp
index 987853e..2660045 100644
--- a/daemon/face/face.hpp
+++ b/daemon/face/face.hpp
@@ -31,6 +31,8 @@
 #include "core/face-uri.hpp"
 #include "face-counter.hpp"
 
+#include <ndn-cxx/management/nfd-face-status.hpp>
+
 namespace nfd {
 
 /** \class FaceId
@@ -149,6 +151,11 @@
   const FaceUri&
   getLocalUri() const;
 
+  /** \return FaceStatus data structure filled with the current Face status
+   */
+  virtual ndn::nfd::FaceStatus
+  getFaceStatus() const;
+
 protected:
   // this is a non-virtual method
   bool
diff --git a/daemon/face/udp-channel.cpp b/daemon/face/udp-channel.cpp
index 684879a..b01d699 100644
--- a/daemon/face/udp-channel.cpp
+++ b/daemon/face/udp-channel.cpp
@@ -61,15 +61,6 @@
   }
 
   this->setUri(FaceUri(localEndpoint));
-
-  //setting the timeout to close the idle faces
-  m_closeIdleFaceEvent = scheduler::schedule(m_idleFaceTimeout,
-                                bind(&UdpChannel::closeIdleFaces, this));
-}
-
-UdpChannel::~UdpChannel()
-{
-  scheduler::cancel(m_closeIdleFaceEvent);
 }
 
 void
@@ -185,7 +176,7 @@
   ChannelFaceMap::iterator faceMapPos = m_channelFaces.find(remoteEndpoint);
   if (faceMapPos == m_channelFaces.end())
     {
-      face = make_shared<UdpFace>(socket, isOnDemand);
+      face = make_shared<UdpFace>(socket, isOnDemand, m_idleFaceTimeout);
       face->onFail += bind(&UdpChannel::afterFaceFailed, this, remoteEndpoint);
 
       m_channelFaces[remoteEndpoint] = face;
@@ -263,26 +254,4 @@
   m_channelFaces.erase(endpoint);
 }
 
-void
-UdpChannel::closeIdleFaces()
-{
-  ChannelFaceMap::iterator next =  m_channelFaces.begin();
-
-  while (next != m_channelFaces.end()) {
-    ChannelFaceMap::iterator it = next;
-    next++;
-    if (it->second->isOnDemand() &&
-        !it->second->hasBeenUsedRecently()) {
-      //face has been idle since the last time closeIdleFaces
-      //has been called. Going to close it
-      NFD_LOG_DEBUG("Found idle face id: " << it->second->getId());
-      it->second->close();
-    } else {
-      it->second->resetRecentUsage();
-    }
-  }
-  m_closeIdleFaceEvent = scheduler::schedule(m_idleFaceTimeout,
-                                             bind(&UdpChannel::closeIdleFaces, this));
-}
-
 } // namespace nfd
diff --git a/daemon/face/udp-channel.hpp b/daemon/face/udp-channel.hpp
index 4db6e43..fed232a 100644
--- a/daemon/face/udp-channel.hpp
+++ b/daemon/face/udp-channel.hpp
@@ -27,7 +27,6 @@
 
 #include "channel.hpp"
 #include "core/global-io.hpp"
-#include "core/scheduler.hpp"
 #include "udp-face.hpp"
 
 namespace nfd {
@@ -65,9 +64,6 @@
   UdpChannel(const udp::Endpoint& localEndpoint,
              const time::seconds& timeout);
 
-  virtual
-  ~UdpChannel();
-
   /**
    * \brief Enable listening on the local endpoint, accept connections,
    *        and create faces when remote host makes a connection
@@ -137,9 +133,6 @@
                            const ConnectFailedCallback& onConnectFailed,
                            const shared_ptr<boost::asio::ip::udp::resolver>& resolver);
 
-  void
-  closeIdleFaces();
-
 private:
   udp::Endpoint m_localEndpoint;
 
@@ -178,9 +171,6 @@
    *        faces will be removed
    */
   time::seconds m_idleFaceTimeout;
-
-  EventId m_closeIdleFaceEvent;
-
 };
 
 } // namespace nfd
diff --git a/daemon/face/udp-face.cpp b/daemon/face/udp-face.cpp
index d2d7823..d4fe8cf 100644
--- a/daemon/face/udp-face.cpp
+++ b/daemon/face/udp-face.cpp
@@ -33,10 +33,14 @@
 
 NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(DatagramFace, UdpFace::protocol, "UdpFace");
 
-UdpFace::UdpFace(const shared_ptr<UdpFace::protocol::socket>& socket, bool isOnDemand)
+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)
+  , m_idleTimeout(idleTimeout)
+  , m_lastIdleCheck(time::steady_clock::now())
 {
 #ifdef __linux__
   //
@@ -60,6 +64,16 @@
                    << "] Failed to disable path MTU discovery");
     }
 #endif
+
+  if (isOnDemand && m_idleTimeout > time::seconds::zero()) {
+    m_closeIfIdleEvent = scheduler::schedule(m_idleTimeout,
+                                             bind(&UdpFace::closeIfIdle, this));
+  }
+}
+
+UdpFace::~UdpFace()
+{
+  scheduler::cancel(m_closeIfIdleEvent);
 }
 
 void
@@ -84,4 +98,49 @@
   receiveDatagram(buffer, nBytesReceived, error);
 }
 
+ndn::nfd::FaceStatus
+UdpFace::getFaceStatus() const
+{
+  ndn::nfd::FaceStatus status = Face::getFaceStatus();
+  if (isOnDemand()) {
+    time::milliseconds left = time::duration_cast<time::milliseconds>(
+      time::steady_clock::now() - m_lastIdleCheck);
+
+    if (hasBeenUsedRecently()) {
+      status.setExpirationPeriod(left + m_idleTimeout);
+    }
+    else {
+      status.setExpirationPeriod(left);
+    }
+  }
+  return status;
+}
+
+void
+UdpFace::closeIfIdle()
+{
+  // Face can be switched from on-demand to non-on-demand mode
+  // (non-on-demand -> on-demand transition is not allowed)
+  if (isOnDemand()) {
+    if (!hasBeenUsedRecently()) {
+      // face has been idle since the last time closeIfIdle
+      // has been called. Going to close it
+      NFD_LOG_DEBUG("Found idle face id: " << getId());
+
+      NFD_LOG_INFO("[id:" << this->getId()
+                   << ",endpoint:" << m_socket->local_endpoint()
+                   << "] Idle for more than " << m_idleTimeout << ", closing");
+      close();
+    }
+    else {
+      resetRecentUsage();
+
+      m_lastIdleCheck = time::steady_clock::now();
+      m_closeIfIdleEvent = scheduler::schedule(m_idleTimeout,
+                                               bind(&UdpFace::closeIfIdle, this));
+    }
+  }
+  // else do nothing and do not reschedule the event
+}
+
 } // namespace nfd
diff --git a/daemon/face/udp-face.hpp b/daemon/face/udp-face.hpp
index ec11682..2751517 100644
--- a/daemon/face/udp-face.hpp
+++ b/daemon/face/udp-face.hpp
@@ -26,6 +26,7 @@
 #define NFD_DAEMON_FACE_UDP_FACE_HPP
 
 #include "datagram-face.hpp"
+#include "core/scheduler.hpp"
 
 namespace nfd {
 
@@ -37,7 +38,11 @@
 {
 public:
   UdpFace(const shared_ptr<protocol::socket>& socket,
-          bool isOnDemand);
+          bool isOnDemand,
+          const time::seconds& idleTimeout);
+
+  virtual
+  ~UdpFace();
 
   /**
    * \brief Manages the first datagram received by the UdpChannel socket set on listening
@@ -46,6 +51,18 @@
   handleFirstReceive(const uint8_t* buffer,
                      std::size_t nBytesReceived,
                      const boost::system::error_code& error);
+
+  virtual ndn::nfd::FaceStatus
+  getFaceStatus() const;
+
+private:
+  void
+  closeIfIdle();
+
+private:
+  EventId m_closeIfIdleEvent;
+  time::seconds m_idleTimeout;
+  time::steady_clock::TimePoint m_lastIdleCheck;
 };
 
 } // namespace nfd
diff --git a/daemon/mgmt/channel-status-publisher.cpp b/daemon/mgmt/channel-status-publisher.cpp
index 42e4f3a..c212f72 100644
--- a/daemon/mgmt/channel-status-publisher.cpp
+++ b/daemon/mgmt/channel-status-publisher.cpp
@@ -25,7 +25,6 @@
 
 #include "channel-status-publisher.hpp"
 
-#include "face-flags.hpp"
 #include "core/logger.hpp"
 #include "face/protocol-factory.hpp"
 #include "face/channel.hpp"
diff --git a/daemon/mgmt/face-manager.cpp b/daemon/mgmt/face-manager.cpp
index 0c299f2..b6cca36 100644
--- a/daemon/mgmt/face-manager.cpp
+++ b/daemon/mgmt/face-manager.cpp
@@ -25,11 +25,11 @@
 
 #include "face-manager.hpp"
 
-#include "face-flags.hpp"
 #include "core/logger.hpp"
 #include "core/face-uri.hpp"
 #include "core/network-interface.hpp"
 #include "fw/face-table.hpp"
+#include "face/face-flags.hpp"
 #include "face/tcp-factory.hpp"
 #include "face/udp-factory.hpp"
 #include "core/config-file.hpp"
diff --git a/daemon/mgmt/face-status-publisher.cpp b/daemon/mgmt/face-status-publisher.cpp
index 28e7155..62531d2 100644
--- a/daemon/mgmt/face-status-publisher.cpp
+++ b/daemon/mgmt/face-status-publisher.cpp
@@ -23,7 +23,6 @@
  **/
 
 #include "face-status-publisher.hpp"
-#include "face-flags.hpp"
 #include "core/logger.hpp"
 #include "fw/face-table.hpp"
 
@@ -57,18 +56,7 @@
   for (FaceTable::const_reverse_iterator i = m_faceTable.rbegin();
        i != m_faceTable.rend(); ++i) {
     const shared_ptr<Face>& face = *i;
-    const FaceCounters& counters = face->getCounters();
-
-    ndn::nfd::FaceStatus status;
-    status.setFaceId(face->getId())
-          .setRemoteUri(face->getRemoteUri().toString())
-          .setLocalUri(face->getLocalUri().toString())
-          .setFlags(getFaceFlags(*face))
-          .setNInInterests(counters.getNInInterests())
-          .setNInDatas(counters.getNInDatas())
-          .setNOutInterests(counters.getNOutInterests())
-          .setNOutDatas(counters.getNOutDatas());
-
+    ndn::nfd::FaceStatus status = face->getFaceStatus();
     totalLength += status.wireEncode(outBuffer);
   }
   return totalLength;
diff --git a/daemon/mgmt/strategy-choice-publisher.cpp b/daemon/mgmt/strategy-choice-publisher.cpp
index 933cc29..add1b73 100644
--- a/daemon/mgmt/strategy-choice-publisher.cpp
+++ b/daemon/mgmt/strategy-choice-publisher.cpp
@@ -24,7 +24,6 @@
  **/
 
 #include "strategy-choice-publisher.hpp"
-#include "face-flags.hpp"
 #include "core/logger.hpp"
 #include "table/strategy-choice.hpp"
 
diff --git a/tests/daemon/mgmt/face-flags.cpp b/tests/daemon/face/face-flags.cpp
similarity index 95%
rename from tests/daemon/mgmt/face-flags.cpp
rename to tests/daemon/face/face-flags.cpp
index 0aa6c09..764d2b6 100644
--- a/tests/daemon/mgmt/face-flags.cpp
+++ b/tests/daemon/face/face-flags.cpp
@@ -22,7 +22,7 @@
  * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  **/
 
-#include "mgmt/face-flags.hpp"
+#include "face/face-flags.hpp"
 
 #include "tests/test-common.hpp"
 #include "tests/daemon/face/dummy-face.hpp"
@@ -30,7 +30,7 @@
 namespace nfd {
 namespace tests {
 
-BOOST_FIXTURE_TEST_SUITE(MgmtFaceFlags, BaseFixture)
+BOOST_FIXTURE_TEST_SUITE(FaceFaceFlags, BaseFixture)
 
 template<typename DummyFaceBase>
 class DummyOnDemandFace : public DummyFaceBase
diff --git a/tests/daemon/mgmt/face-status-publisher-common.hpp b/tests/daemon/mgmt/face-status-publisher-common.hpp
index 088323f..0cfe6a2 100644
--- a/tests/daemon/mgmt/face-status-publisher-common.hpp
+++ b/tests/daemon/mgmt/face-status-publisher-common.hpp
@@ -28,7 +28,7 @@
 #include "mgmt/face-status-publisher.hpp"
 #include "mgmt/app-face.hpp"
 #include "mgmt/internal-face.hpp"
-#include "mgmt/face-flags.hpp"
+#include "face/face-flags.hpp"
 #include "fw/forwarder.hpp"
 
 #include "tests/test-common.hpp"
diff --git a/tests/daemon/mgmt/strategy-choice-publisher.cpp b/tests/daemon/mgmt/strategy-choice-publisher.cpp
index ac86cd1..b3190d4 100644
--- a/tests/daemon/mgmt/strategy-choice-publisher.cpp
+++ b/tests/daemon/mgmt/strategy-choice-publisher.cpp
@@ -29,7 +29,6 @@
 #include "mgmt/strategy-choice-publisher.hpp"
 #include "mgmt/app-face.hpp"
 #include "mgmt/internal-face.hpp"
-#include "mgmt/face-flags.hpp"
 #include "fw/forwarder.hpp"
 #include "../fw/dummy-strategy.hpp"