rib: provide self-learning helpers

refs #4683

Change-Id: Ib1e586a505d07a5e1f7a4b6d78306ea08b4dcda8
diff --git a/rib/rib-manager.cpp b/rib/rib-manager.cpp
index a1707ef..009b9ad 100644
--- a/rib/rib-manager.cpp
+++ b/rib/rib-manager.cpp
@@ -46,9 +46,11 @@
 static const Name LOCALHOP_TOP_PREFIX = "/localhop/nfd";
 static const time::seconds ACTIVE_FACE_FETCH_INTERVAL = time::seconds(300);
 
-RibManager::RibManager(Rib& rib, ndn::Face& face, ndn::nfd::Controller& nfdController, Dispatcher& dispatcher)
+RibManager::RibManager(Rib& rib, ndn::Face& face, ndn::KeyChain& keyChain,
+                       ndn::nfd::Controller& nfdController, Dispatcher& dispatcher)
   : ManagerBase(dispatcher, MGMT_MODULE_NAME)
   , m_rib(rib)
+  , m_keyChain(keyChain)
   , m_nfdController(nfdController)
   , m_dispatcher(dispatcher)
   , m_faceMonitor(face)
@@ -118,18 +120,15 @@
                           const std::function<void(RibUpdateResult)>& done)
 {
   if (expires) {
-    if (*expires <= 0_ns) {
-      done(RibUpdateResult::EXPIRED);
-      return;
-    }
     route.expires = time::steady_clock::now() + *expires;
   }
   else if (route.expires) {
     expires = *route.expires - time::steady_clock::now();
-    if (*expires <= 0_ns) {
-      done(RibUpdateResult::EXPIRED);
-      return;
-    }
+  }
+
+  if (expires && *expires <= 0_s) {
+    m_rib.onRouteExpiration(name, route);
+    return done(RibUpdateResult::EXPIRED);
   }
 
   NFD_LOG_INFO("Adding route " << name << " nexthop=" << route.faceId <<
@@ -318,6 +317,116 @@
   };
 }
 
+std::ostream&
+operator<<(std::ostream& os, RibManager::SlAnnounceResult res)
+{
+  switch (res) {
+    case RibManager::SlAnnounceResult::OK:
+      return os << "OK";
+    case RibManager::SlAnnounceResult::ERROR:
+      return os << "ERROR";
+    case RibManager::SlAnnounceResult::VALIDATION_FAILURE:
+      return os << "VALIDATION_FAILURE";
+    case RibManager::SlAnnounceResult::EXPIRED:
+      return os << "EXPIRED";
+    case RibManager::SlAnnounceResult::NOT_FOUND:
+      return os << "NOT_FOUND";
+  }
+  BOOST_ASSERT_MSG(false, "bad SlAnnounceResult");
+  return os;
+}
+
+RibManager::SlAnnounceResult
+RibManager::getSlAnnounceResultFromRibUpdateResult(RibUpdateResult r)
+{
+  switch (r) {
+  case RibUpdateResult::OK:
+    return SlAnnounceResult::OK;
+  case RibUpdateResult::ERROR:
+    return SlAnnounceResult::ERROR;
+  case RibUpdateResult::EXPIRED:
+    return SlAnnounceResult::EXPIRED;
+  default:
+    BOOST_ASSERT(false);
+    return SlAnnounceResult::ERROR;
+  }
+}
+
+void
+RibManager::slAnnounce(const ndn::PrefixAnnouncement& pa, uint64_t faceId,
+                       time::milliseconds maxLifetime, const SlAnnounceCallback& cb)
+{
+  BOOST_ASSERT(pa.getData());
+
+  if (!m_isLocalhopEnabled) {
+    NFD_LOG_INFO("slAnnounce " << pa.getAnnouncedName() << ' ' << faceId <<
+                 ": localhop_security unconfigured");
+    cb(SlAnnounceResult::VALIDATION_FAILURE);
+    return;
+  }
+
+  m_localhopValidator.validate(*pa.getData(),
+    [=] (const Data&) {
+      Route route(pa, faceId);
+      route.expires = std::min(route.annExpires, time::steady_clock::now() + maxLifetime);
+      beginAddRoute(pa.getAnnouncedName(), route, nullopt,
+        [=] (RibUpdateResult ribRes) {
+          auto res = getSlAnnounceResultFromRibUpdateResult(ribRes);
+          NFD_LOG_INFO("slAnnounce " << pa.getAnnouncedName() << ' ' << faceId << ": " << res);
+          cb(res);
+        });
+    },
+    [=] (const Data&, ndn::security::v2::ValidationError err) {
+      NFD_LOG_INFO("slAnnounce " << pa.getAnnouncedName() << ' ' << faceId <<
+                   " validation error: " << err);
+      cb(SlAnnounceResult::VALIDATION_FAILURE);
+    }
+  );
+}
+
+void
+RibManager::slRenew(const Name& name, uint64_t faceId, time::milliseconds maxLifetime,
+                    const SlAnnounceCallback& cb)
+{
+  Route routeQuery;
+  routeQuery.faceId = faceId;
+  routeQuery.origin = ndn::nfd::ROUTE_ORIGIN_PREFIXANN;
+  Route* oldRoute = m_rib.find(name, routeQuery);
+  if (oldRoute == nullptr || !oldRoute->announcement) {
+    NFD_LOG_DEBUG("slRenew " << name << ' ' << faceId << ": not found");
+    return cb(SlAnnounceResult::NOT_FOUND);
+  }
+
+  Route route = *oldRoute;
+  route.expires = std::min(route.annExpires, time::steady_clock::now() + maxLifetime);
+  beginAddRoute(name, route, nullopt,
+    [=] (RibUpdateResult ribRes) {
+      auto res = getSlAnnounceResultFromRibUpdateResult(ribRes);
+      NFD_LOG_INFO("slRenew " << name << ' ' << faceId << ": " << res);
+      cb(res);
+    });
+}
+
+void
+RibManager::slFindAnn(const Name& name, const SlFindAnnCallback& cb) const
+{
+  shared_ptr<RibEntry> entry;
+  auto exactMatch = m_rib.find(name);
+  if (exactMatch != m_rib.end()) {
+    entry = exactMatch->second;
+  }
+  else {
+    entry = m_rib.findParent(name);
+  }
+  if (entry == nullptr) {
+    return cb(nullopt);
+  }
+
+  auto pa = entry->getPrefixAnnouncement();
+  pa.toData(m_keyChain);
+  cb(pa);
+}
+
 void
 RibManager::fetchActiveFaces()
 {