mgmt: re-added expiration time to FaceStatus

refs #3381

Change-Id: I57d3166fc6ed52a54c442a80faffe7a7f4051e1d
diff --git a/daemon/face/face.hpp b/daemon/face/face.hpp
index d783dd0..2b56fec 100644
--- a/daemon/face/face.hpp
+++ b/daemon/face/face.hpp
@@ -159,6 +159,12 @@
    */
   signal::Signal<Transport, FaceState/*old*/, FaceState/*new*/>& afterStateChange;
 
+  /** \return expiration time of the face
+   *  \retval time::steady_clock::TimePoint::max() the face has an indefinite lifetime
+   */
+  time::steady_clock::TimePoint
+  getExpirationTime() const;
+
   /** \brief request the face to be closed
    *
    *  This operation is effective only if face is in UP or DOWN state,
@@ -266,6 +272,12 @@
   return m_transport->getState();
 }
 
+inline time::steady_clock::TimePoint
+Face::getExpirationTime() const
+{
+  return m_transport->getExpirationTime();
+}
+
 inline void
 Face::close()
 {
diff --git a/daemon/face/transport.cpp b/daemon/face/transport.cpp
index 2d2c3dd..26cc0d7 100644
--- a/daemon/face/transport.cpp
+++ b/daemon/face/transport.cpp
@@ -64,6 +64,7 @@
   , m_linkType(ndn::nfd::LINK_TYPE_NONE)
   , m_mtu(MTU_INVALID)
   , m_state(TransportState::UP)
+  , m_expirationTime(time::steady_clock::TimePoint::max())
 {
 }
 
diff --git a/daemon/face/transport.hpp b/daemon/face/transport.hpp
index 56ff730..a12ce7c 100644
--- a/daemon/face/transport.hpp
+++ b/daemon/face/transport.hpp
@@ -253,6 +253,12 @@
    */
   signal::Signal<Transport, TransportState/*old*/, TransportState/*new*/> afterStateChange;
 
+  /** \return expiration time of the transport
+   *  \retval time::steady_clock::TimePoint::max() the transport has indefinite lifetime
+   */
+  time::steady_clock::TimePoint
+  getExpirationTime() const;
+
 protected: // properties to be set by subclass
   void
   setLocalUri(const FaceUri& uri);
@@ -279,6 +285,9 @@
   void
   setState(TransportState newState);
 
+  void
+  setExpirationTime(const time::steady_clock::TimePoint& expirationTime);
+
 protected: // to be overridden by subclass
   /** \brief invoked before persistency is changed
    *  \throw std::invalid_argument new persistency is not supported
@@ -316,6 +325,7 @@
   ndn::nfd::LinkType m_linkType;
   ssize_t m_mtu;
   TransportState m_state;
+  time::steady_clock::TimePoint m_expirationTime;
 };
 
 inline const Face*
@@ -415,6 +425,18 @@
   return m_state;
 }
 
+inline time::steady_clock::TimePoint
+Transport::getExpirationTime() const
+{
+  return m_expirationTime;
+}
+
+inline void
+Transport::setExpirationTime(const time::steady_clock::TimePoint& expirationTime)
+{
+  m_expirationTime = expirationTime;
+}
+
 std::ostream&
 operator<<(std::ostream& os, const FaceLogHelper<Transport>& flh);
 
diff --git a/daemon/face/unicast-udp-transport.cpp b/daemon/face/unicast-udp-transport.cpp
index 3bd4759..b6ad19a 100644
--- a/daemon/face/unicast-udp-transport.cpp
+++ b/daemon/face/unicast-udp-transport.cpp
@@ -89,6 +89,7 @@
   }
   else {
     m_closeIfIdleEvent.cancel();
+    setExpirationTime(time::steady_clock::TimePoint::max());
   }
 }
 
@@ -105,6 +106,7 @@
       scheduleClosureWhenIdle();
     }
   });
+  setExpirationTime(time::steady_clock::now() + m_idleTimeout);
 }
 
 } // namespace face
diff --git a/daemon/mgmt/face-manager.cpp b/daemon/mgmt/face-manager.cpp
index 0cc40d5..0c94fea 100644
--- a/daemon/mgmt/face-manager.cpp
+++ b/daemon/mgmt/face-manager.cpp
@@ -248,10 +248,9 @@
 FaceManager::listFaces(const Name& topPrefix, const Interest& interest,
                        ndn::mgmt::StatusDatasetContext& context)
 {
+  auto now = time::steady_clock::now();
   for (const auto& face : m_faceTable) {
-    ndn::nfd::FaceStatus status;
-    collectFaceProperties(*face, status);
-    collectFaceCounters(*face, status);
+    ndn::nfd::FaceStatus status = collectFaceStatus(*face, now);
     context.append(status.wireEncode());
   }
   context.end();
@@ -294,13 +293,12 @@
     return context.reject(ControlResponse(400, "Malformed filter"));
   }
 
+  auto now = time::steady_clock::now();
   for (const auto& face : m_faceTable) {
     if (!doesMatchFilter(faceFilter, face)) {
       continue;
     }
-    ndn::nfd::FaceStatus status;
-    collectFaceProperties(*face, status);
-    collectFaceCounters(*face, status);
+    ndn::nfd::FaceStatus status = collectFaceStatus(*face, now);
     context.append(status.wireEncode());
   }
 
@@ -349,6 +347,32 @@
   return true;
 }
 
+ndn::nfd::FaceStatus
+FaceManager::collectFaceStatus(const Face& face, const time::steady_clock::TimePoint& now)
+{
+  ndn::nfd::FaceStatus status;
+
+  collectFaceProperties(face, status);
+
+  time::steady_clock::TimePoint expirationTime = face.getExpirationTime();
+  if (expirationTime != time::steady_clock::TimePoint::max()) {
+    status.setExpirationPeriod(std::max(time::milliseconds(0),
+                                        time::duration_cast<time::milliseconds>(expirationTime - now)));
+  }
+
+  const face::FaceCounters& counters = face.getCounters();
+  status.setNInInterests(counters.nInInterests)
+        .setNOutInterests(counters.nOutInterests)
+        .setNInDatas(counters.nInData)
+        .setNOutDatas(counters.nOutData)
+        .setNInNacks(counters.nInNacks)
+        .setNOutNacks(counters.nOutNacks)
+        .setNInBytes(counters.nInBytes)
+        .setNOutBytes(counters.nOutBytes);
+
+  return status;
+}
+
 template<typename FaceTraits>
 void
 FaceManager::collectFaceProperties(const Face& face, FaceTraits& traits)
@@ -362,20 +386,6 @@
 }
 
 void
-FaceManager::collectFaceCounters(const Face& face, ndn::nfd::FaceStatus& status)
-{
-  const face::FaceCounters& counters = face.getCounters();
-  status.setNInInterests(counters.nInInterests)
-        .setNOutInterests(counters.nOutInterests)
-        .setNInDatas(counters.nInData)
-        .setNOutDatas(counters.nOutData)
-        .setNInNacks(counters.nInNacks)
-        .setNOutNacks(counters.nOutNacks)
-        .setNInBytes(counters.nInBytes)
-        .setNOutBytes(counters.nOutBytes);
-}
-
-void
 FaceManager::afterFaceAdded(shared_ptr<Face> face,
                             const ndn::mgmt::PostNotification& post)
 {
diff --git a/daemon/mgmt/face-manager.hpp b/daemon/mgmt/face-manager.hpp
index c2f43bb..fda4fbe 100644
--- a/daemon/mgmt/face-manager.hpp
+++ b/daemon/mgmt/face-manager.hpp
@@ -107,6 +107,11 @@
   bool
   doesMatchFilter(const ndn::nfd::FaceQueryFilter& filter, shared_ptr<Face> face);
 
+  /** \brief get status of face, including properties and counters
+   */
+  static ndn::nfd::FaceStatus
+  collectFaceStatus(const Face& face, const time::steady_clock::TimePoint& now);
+
   /** \brief copy face properties into traits
    *  \tparam FaceTraits either FaceStatus or FaceEventNotification
    */
@@ -114,11 +119,6 @@
   static void
   collectFaceProperties(const Face& face, FaceTraits& traits);
 
-  /** \brief copy face counters into FaceStatus
-   */
-  static void
-  collectFaceCounters(const Face& face, ndn::nfd::FaceStatus& status);
-
 private: // NotificationStream
   void
   afterFaceAdded(shared_ptr<Face> face,
diff --git a/tests/daemon/face/transport.t.cpp b/tests/daemon/face/transport.t.cpp
index 9a59491..75bedf8 100644
--- a/tests/daemon/face/transport.t.cpp
+++ b/tests/daemon/face/transport.t.cpp
@@ -200,6 +200,13 @@
 
 BOOST_AUTO_TEST_SUITE_END() // StateTransition
 
+BOOST_AUTO_TEST_CASE(NoExpirationTime)
+{
+  initialize();
+
+  BOOST_CHECK_EQUAL(transport->getExpirationTime(), time::steady_clock::TimePoint::max());
+}
+
 BOOST_AUTO_TEST_CASE(Send)
 {
   this->initialize();
diff --git a/tests/daemon/face/unicast-udp-transport.t.cpp b/tests/daemon/face/unicast-udp-transport.t.cpp
index 0d66fa3..fb5469d 100644
--- a/tests/daemon/face/unicast-udp-transport.t.cpp
+++ b/tests/daemon/face/unicast-udp-transport.t.cpp
@@ -102,6 +102,7 @@
 BOOST_AUTO_TEST_CASE(IdleClose)
 {
   initialize(ip::address_v4::loopback(), ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
+  BOOST_CHECK_NE(transport->getExpirationTime(), time::steady_clock::TimePoint::max());
 
   int nStateChanges = 0;
   this->transport->afterStateChange.connect(
@@ -195,6 +196,15 @@
   BOOST_CHECK_EQUAL(transport->getState(), TransportState::UP);
 }
 
+BOOST_AUTO_TEST_CASE(ChangePersistencyNoExpirationTime)
+{
+  initialize(ip::address_v4::loopback(), ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
+  BOOST_CHECK_NE(transport->getExpirationTime(), time::steady_clock::TimePoint::max());
+
+  transport->setPersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
+  BOOST_CHECK_EQUAL(transport->getExpirationTime(), time::steady_clock::TimePoint::max());
+}
+
 BOOST_AUTO_TEST_SUITE_END() // TestUnicastUdpTransport
 BOOST_AUTO_TEST_SUITE_END() // Face