mgmt: send FACE_EVENT_UP and FACE_EVENT_DOWN notifications

refs #3794

Change-Id: I98cc9db2652454d8fd09975b619433046e9bc7ca
diff --git a/daemon/mgmt/face-manager.cpp b/daemon/mgmt/face-manager.cpp
index 0ce16c5..8a9bb1c 100644
--- a/daemon/mgmt/face-manager.cpp
+++ b/daemon/mgmt/face-manager.cpp
@@ -33,8 +33,6 @@
 
 #include <ndn-cxx/lp/tags.hpp>
 #include <ndn-cxx/mgmt/nfd/channel-status.hpp>
-#include <ndn-cxx/mgmt/nfd/face-status.hpp>
-#include <ndn-cxx/mgmt/nfd/face-event-notification.hpp>
 
 #ifdef HAVE_UNIX_SOCKETS
 #include "face/unix-stream-factory.hpp"
@@ -77,8 +75,13 @@
   registerStatusDatasetHandler("query", bind(&FaceManager::queryFaces, this, _1, _2, _3));
 
   m_postNotification = registerNotificationStream("events");
-  m_faceAddConn = m_faceTable.afterAdd.connect(bind(&FaceManager::notifyAddFace, this, _1));
-  m_faceRemoveConn = m_faceTable.beforeRemove.connect(bind(&FaceManager::notifyRemoveFace, this, _1));
+  m_faceAddConn = m_faceTable.afterAdd.connect([this] (const Face& face) {
+    connectFaceStateChangeSignal(face);
+    notifyFaceEvent(face, ndn::nfd::FACE_EVENT_CREATED);
+  });
+  m_faceRemoveConn = m_faceTable.beforeRemove.connect([this] (const Face& face) {
+    notifyFaceEvent(face, ndn::nfd::FACE_EVENT_DESTROYED);
+  });
 }
 
 void
@@ -493,13 +496,6 @@
         .setNInBytes(counters.nInBytes)
         .setNOutBytes(counters.nOutBytes);
 
-  // Set Flag bits
-  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
-  if (linkService != nullptr) {
-    auto linkServiceOptions = linkService->getOptions();
-    status.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, linkServiceOptions.allowLocalFields);
-  }
-
   return status;
 }
 
@@ -513,26 +509,43 @@
         .setFaceScope(face.getScope())
         .setFacePersistency(face.getPersistency())
         .setLinkType(face.getLinkType());
+
+  // Set Flag bits
+  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
+  if (linkService != nullptr) {
+    auto linkServiceOptions = linkService->getOptions();
+    traits.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, linkServiceOptions.allowLocalFields);
+  }
 }
 
 void
-FaceManager::notifyAddFace(const Face& face)
+FaceManager::notifyFaceEvent(const Face& face, ndn::nfd::FaceEventKind kind)
 {
   ndn::nfd::FaceEventNotification notification;
-  notification.setKind(ndn::nfd::FACE_EVENT_CREATED);
+  notification.setKind(kind);
   collectFaceProperties(face, notification);
 
   m_postNotification(notification.wireEncode());
 }
 
 void
-FaceManager::notifyRemoveFace(const Face& face)
+FaceManager::connectFaceStateChangeSignal(const Face& face)
 {
-  ndn::nfd::FaceEventNotification notification;
-  notification.setKind(ndn::nfd::FACE_EVENT_DESTROYED);
-  collectFaceProperties(face, notification);
+  FaceId faceId = face.getId();
+  m_faceStateChangeConn[faceId] = face.afterStateChange.connect(
+    [this, faceId] (face::FaceState oldState, face::FaceState newState) {
+      const Face& face = *m_faceTable.get(faceId);
 
-  m_postNotification(notification.wireEncode());
+      if (newState == face::FaceState::UP) {
+        notifyFaceEvent(face, ndn::nfd::FACE_EVENT_UP);
+      }
+      else if (newState == face::FaceState::DOWN) {
+        notifyFaceEvent(face, ndn::nfd::FACE_EVENT_DOWN);
+      }
+      else if (newState == face::FaceState::CLOSED) {
+        m_faceStateChangeConn.erase(faceId);
+      }
+    });
 }
 
 void
diff --git a/daemon/mgmt/face-manager.hpp b/daemon/mgmt/face-manager.hpp
index 3a20dbd..c4a2c48 100644
--- a/daemon/mgmt/face-manager.hpp
+++ b/daemon/mgmt/face-manager.hpp
@@ -29,6 +29,7 @@
 #include "nfd-manager-base.hpp"
 #include <ndn-cxx/mgmt/nfd/face-status.hpp>
 #include <ndn-cxx/mgmt/nfd/face-query-filter.hpp>
+#include <ndn-cxx/mgmt/nfd/face-event-notification.hpp>
 #include "face/face.hpp"
 
 namespace nfd {
@@ -138,10 +139,10 @@
 
 private: // NotificationStream
   void
-  notifyAddFace(const Face& face);
+  notifyFaceEvent(const Face& face, ndn::nfd::FaceEventKind kind);
 
   void
-  notifyRemoveFace(const Face& face);
+  connectFaceStateChangeSignal(const Face& face);
 
 private: // configuration
   void
@@ -168,6 +169,7 @@
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   std::map<std::string /*protocol*/, shared_ptr<ProtocolFactory>> m_factories;
   FaceTable& m_faceTable;
+  std::map<FaceId, signal::ScopedConnection> m_faceStateChangeConn;
 
 private:
   ndn::mgmt::PostNotification m_postNotification;