rib: Add periodic invalid face clean up

refs: #1744, #1875

Change-Id: I4e6780ef6abb95b2c4ad7c1e6291897693cb551a
diff --git a/rib/rib-manager.cpp b/rib/rib-manager.cpp
index 59e6230..14dbaf3 100644
--- a/rib/rib-manager.cpp
+++ b/rib/rib-manager.cpp
@@ -71,6 +71,8 @@
 const Name RibManager::LIST_COMMAND_PREFIX("/localhost/nfd/rib/list");
 const size_t RibManager::LIST_COMMAND_NCOMPS = LIST_COMMAND_PREFIX.size();
 
+const time::seconds RibManager::ACTIVE_FACE_FETCH_INTERVAL = time::seconds(300);
+
 RibManager::RibManager(ndn::Face& face)
   : m_face(face)
   , m_nfdController(m_face)
@@ -89,6 +91,11 @@
 {
 }
 
+RibManager::~RibManager()
+{
+  scheduler::cancel(m_activeFaceFetchEvent);
+}
+
 void
 RibManager::startListening(const Name& commandPrefix, const ndn::OnInterest& onRequest)
 {
@@ -121,7 +128,7 @@
   m_faceMonitor.onNotification += bind(&RibManager::onNotification, this, _1);
   m_faceMonitor.start();
 
-  fetchActiveFaces();
+  scheduleActiveFaceFetch(ACTIVE_FACE_FETCH_INTERVAL);
 }
 
 void
@@ -259,20 +266,6 @@
       parameters.setFaceId(request->getIncomingFaceId());
     }
 
-  // Is the face valid?
-  // Issue 1852: There is no need to check (and it can easily fail) for self-registrations
-  if (!isSelfRegistration && activeFaces.find(parameters.getFaceId()) == activeFaces.end())
-    {
-      NFD_LOG_DEBUG("register result: FAIL reason: unknown faceId");
-
-      if (static_cast<bool>(request))
-        {
-          sendResponse(request->getName(), 410, "Face not found");
-        }
-
-      return;
-    }
-
   FaceEntry faceEntry;
   faceEntry.faceId = parameters.getFaceId();
   faceEntry.origin = parameters.getOrigin();
@@ -303,6 +296,7 @@
   NFD_LOG_TRACE("register prefix: " << faceEntry);
 
   m_managedRib.insert(parameters.getName(), faceEntry);
+  m_registeredFaces.insert(faceEntry.faceId);
 
   sendUpdatesToFib(request, parameters);
 }
@@ -349,20 +343,6 @@
       parameters.setFaceId(request->getIncomingFaceId());
     }
 
-  // Is the face valid?
-  // Issue 1852: There is no need to check (and it can easily fail) for self-registrations
-  if (!isSelfRegistration && activeFaces.find(parameters.getFaceId()) == activeFaces.end())
-    {
-      NFD_LOG_DEBUG("register result: FAIL reason: unknown faceId");
-
-      if (static_cast<bool>(request))
-        {
-          sendResponse(request->getName(), 410, "Face not found");
-        }
-
-      return;
-    }
-
   FaceEntry faceEntry;
   faceEntry.faceId = parameters.getFaceId();
   faceEntry.origin = parameters.getOrigin();
@@ -598,6 +578,9 @@
   {
     sendErrorResponse(code, error, request);
   }
+
+  // Since the FIB rejected the update, clean up the invalid face
+  scheduleActiveFaceFetch(time::seconds(1));
 }
 
 void
@@ -653,18 +636,11 @@
 void
 RibManager::onNotification(const FaceEventNotification& notification)
 {
-  /// \todo A notification can be missed, in this case check Facelist
   NFD_LOG_TRACE("onNotification: " << notification);
 
-  if (notification.getKind() == ndn::nfd::FACE_EVENT_CREATED)
-    {
-      NFD_LOG_DEBUG("Received notification for created faceId: " << notification.getFaceId());
-      activeFaces.insert(notification.getFaceId());
-    }
-  else if (notification.getKind() == ndn::nfd::FACE_EVENT_DESTROYED)
+  if (notification.getKind() == ndn::nfd::FACE_EVENT_DESTROYED)
     {
       NFD_LOG_DEBUG("Received notification for destroyed faceId: " << notification.getFaceId());
-      activeFaces.erase(notification.getFaceId());
 
       scheduler::schedule(time::seconds(0),
                           bind(&RibManager::processErasureAfterNotification, this,
@@ -676,6 +652,7 @@
 RibManager::processErasureAfterNotification(uint64_t faceId)
 {
   m_managedRib.erase(faceId);
+  m_registeredFaces.erase(faceId);
 
   sendUpdatesToFibAfterFaceDestroyEvent();
 }
@@ -786,6 +763,15 @@
 }
 
 void
+RibManager::scheduleActiveFaceFetch(const time::seconds& timeToWait)
+{
+  scheduler::cancel(m_activeFaceFetchEvent);
+
+  m_activeFaceFetchEvent = scheduler::schedule(timeToWait,
+                                               bind(&RibManager::fetchActiveFaces, this));
+}
+
+void
 RibManager::fetchActiveFaces()
 {
   NFD_LOG_DEBUG("Fetching active faces");
@@ -818,19 +804,20 @@
     }
   else
     {
-      updateActiveFaces(buffer);
+      removeInvalidFaces(buffer);
     }
 }
 
 void
-RibManager::updateActiveFaces(shared_ptr<ndn::OBufferStream> buffer)
+RibManager::removeInvalidFaces(shared_ptr<ndn::OBufferStream> buffer)
 {
-  NFD_LOG_DEBUG("Updating active faces");
+  NFD_LOG_DEBUG("Checking for invalid face registrations");
 
   ndn::ConstBufferPtr buf = buffer->buf();
 
   Block block;
   size_t offset = 0;
+  FaceIdSet activeFaces;
 
   while (offset < buf->size())
     {
@@ -843,16 +830,30 @@
       offset += block.size();
 
       ndn::nfd::FaceStatus status(block);
-
-      NFD_LOG_DEBUG("Adding faceId: " << status.getFaceId() << " to activeFaces");
       activeFaces.insert(status.getFaceId());
     }
+
+  // Look for face IDs that were registered but not active to find missed
+  // face destroyed events
+  for (FaceIdSet::iterator it = m_registeredFaces.begin(); it != m_registeredFaces.end(); ++it)
+    {
+      if (activeFaces.find(*it) == activeFaces.end())
+        {
+          NFD_LOG_DEBUG("Removing invalid face ID: " << *it);
+          scheduler::schedule(time::seconds(0),
+                              bind(&RibManager::processErasureAfterNotification, this, *it));
+        }
+    }
+
+  // Reschedule the check for future clean up
+  scheduleActiveFaceFetch(ACTIVE_FACE_FETCH_INTERVAL);
 }
 
 void
 RibManager::onFetchFaceStatusTimeout()
 {
   std::cerr << "Face Status Dataset request timed out" << std::endl;
+  scheduleActiveFaceFetch(ACTIVE_FACE_FETCH_INTERVAL);
 }
 
 } // namespace rib