config+lsdb: Retry retrieve each LSA for `lsa-refresh-time`

This commit also includes extension of the config file
(`lsa-interest-lifetime` parameter in general section)

Change-Id: Ifd01af8cc98d41f7bdc953799a280e4b4269a358
Refs: #1873, #1874
diff --git a/src/communication/sync-logic-handler.cpp b/src/communication/sync-logic-handler.cpp
index dea3782..2570d2d 100644
--- a/src/communication/sync-logic-handler.cpp
+++ b/src/communication/sync-logic-handler.cpp
@@ -97,9 +97,7 @@
         interestName.append(routerName);
         interestName.append("name");
         interestName.appendNumber(sm.getNameLsaSeq());
-        pnlsr.getLsdb().expressInterest(interestName,
-                                        pnlsr.getConfParameter().getInterestResendTime(),
-                                        0);
+        pnlsr.getLsdb().expressInterest(interestName, 0);
       }
       if (pnlsr.getLsdb().isAdjLsaNew(rName.append("adjacency"), sm.getAdjLsaSeq())) {
         _LOG_DEBUG("Updated Adj LSA. Need to fetch it");
@@ -107,9 +105,7 @@
         interestName.append(routerName);
         interestName.append("adjacency");
         interestName.appendNumber(sm.getAdjLsaSeq());
-        pnlsr.getLsdb().expressInterest(interestName,
-                                        pnlsr.getConfParameter().getInterestResendTime(),
-                                        0);
+        pnlsr.getLsdb().expressInterest(interestName, 0);
       }
       if (pnlsr.getLsdb().isCoordinateLsaNew(rName.append("coordinate"),
                                              sm.getCorLsaSeq())) {
@@ -118,9 +114,7 @@
         interestName.append(routerName);
         interestName.append("coordinate");
         interestName.appendNumber(sm.getCorLsaSeq());
-        pnlsr.getLsdb().expressInterest(interestName,
-                                        pnlsr.getConfParameter().getInterestResendTime(),
-                                        0);
+        pnlsr.getLsdb().expressInterest(interestName, 0);
       }
     }
     catch (std::exception& e) {
diff --git a/src/conf-file-processor.cpp b/src/conf-file-processor.cpp
index 0328ecd..5f3c147 100644
--- a/src/conf-file-processor.cpp
+++ b/src/conf-file-processor.cpp
@@ -172,6 +172,23 @@
   }
 
   try {
+    int lifetime = section.get<int>("lsa-interest-lifetime");
+    if (lifetime >= LSA_INTEREST_LIFETIME_MIN && lifetime <= LSA_INTEREST_LIFETIME_MAX) {
+      m_nlsr.getConfParameter().setLsaInterestLifetime(ndn::time::seconds(lifetime));
+    }
+    else {
+      std::cerr << "Wrong value for lsa-interest-timeout. "
+                << "Allowed value:" << LSA_INTEREST_LIFETIME_MIN << "-"
+                << LSA_INTEREST_LIFETIME_MAX << std::endl;
+      return false;
+    }
+  }
+  catch (const std::exception& ex) {
+    std::cerr << ex.what() << std::endl;
+    // return false;
+  }
+
+  try {
     std::string logLevel = section.get<string>("log-level");
     if ( boost::iequals(logLevel, "info") || boost::iequals(logLevel, "debug")) {
       m_nlsr.getConfParameter().setLogLevel(logLevel);
diff --git a/src/conf-parameter.cpp b/src/conf-parameter.cpp
index 0984b99..f45fea7 100644
--- a/src/conf-parameter.cpp
+++ b/src/conf-parameter.cpp
@@ -36,10 +36,11 @@
   _LOG_DEBUG("Router Prefix: " << m_routerPrefix);
   _LOG_DEBUG("ChronoSync sync Prifex: " << m_chronosyncPrefix);
   _LOG_DEBUG("ChronoSync LSA prefix: " << m_lsaPrefix);
-  _LOG_DEBUG("Interest Retry number: " << m_interestRetryNumber);
-  _LOG_DEBUG("Interest Resend second: " << m_interestResendTime);
-  _LOG_DEBUG("Info Interest Interval: " << m_infoInterestInterval);
+  _LOG_DEBUG("Hello Interest retry number: " << m_interestRetryNumber);
+  _LOG_DEBUG("Hello Interest resend second: " << m_interestResendTime);
+  _LOG_DEBUG("Info Interest interval: " << m_infoInterestInterval);
   _LOG_DEBUG("LSA refresh time: " << m_lsaRefreshTime);
+  _LOG_DEBUG("LSA Interest lifetime: " << getLsaInterestLifetime());
   _LOG_DEBUG("Max Faces Per Prefix: " << m_maxFacesPerPrefix);
   _LOG_DEBUG("Hyperbolic ROuting: " << m_hyperbolicState);
   _LOG_DEBUG("Hyp R: " << m_corR);
diff --git a/src/conf-parameter.hpp b/src/conf-parameter.hpp
index cb97943..b8b5b72 100644
--- a/src/conf-parameter.hpp
+++ b/src/conf-parameter.hpp
@@ -27,6 +27,7 @@
 #include <boost/cstdint.hpp>
 #include <ndn-cxx/common.hpp>
 #include <ndn-cxx/face.hpp>
+#include <ndn-cxx/util/time.hpp>
 
 #include "logger.hpp"
 
@@ -39,6 +40,12 @@
 };
 
 enum {
+  LSA_INTEREST_LIFETIME_MIN = 1,
+  LSA_INTEREST_LIFETIME_DEFAULT = 4,
+  LSA_INTEREST_LIFETIME_MAX = 60
+};
+
+enum {
   HELLO_RETRIES_MIN = 1,
   HELLO_RETRIES_DEFAULT = 3,
   HELLO_RETRIES_MAX = 15
@@ -73,6 +80,7 @@
 public:
   ConfParameter()
     : m_lsaRefreshTime(LSA_REFRESH_TIME_DEFAULT)
+    , m_lsaInterestLifetime(ndn::time::seconds(static_cast<int>(LSA_INTEREST_LIFETIME_DEFAULT)))
     , m_routerDeadInterval(2*LSA_REFRESH_TIME_DEFAULT)
     , m_logLevel("INFO")
     , m_interestRetryNumber(HELLO_RETRIES_DEFAULT)
@@ -82,7 +90,8 @@
     , m_corR(0)
     , m_corTheta(0)
     , m_maxFacesPerPrefix(MAX_FACES_PER_PREFIX_MIN)
-  {}
+  {
+  }
 
   void
   setNetwork(const ndn::Name& networkName)
@@ -91,14 +100,14 @@
     m_chronosyncPrefix = m_network;
     m_chronosyncPrefix.append("NLSR");
     m_chronosyncPrefix.append("sync");
-    
+
     m_lsaPrefix = m_network;
     m_lsaPrefix.append("NLSR");
     m_lsaPrefix.append("LSA");
   }
 
   const ndn::Name&
-  getNetwork()
+  getNetwork() const
   {
     return m_network;
   }
@@ -110,7 +119,7 @@
   }
 
   const ndn::Name&
-  getRouterName()
+  getRouterName() const
   {
     return m_routerName;
   }
@@ -122,7 +131,7 @@
   }
 
   const ndn::Name&
-  getSiteName()
+  getSiteName() const
   {
     return m_siteName;
   }
@@ -136,20 +145,20 @@
   }
 
   const ndn::Name&
-  getRouterPrefix()
+  getRouterPrefix() const
   {
     return m_routerPrefix;
   }
 
 
   const ndn::Name&
-  getChronosyncPrefix()
+  getChronosyncPrefix() const
   {
     return m_chronosyncPrefix;
   }
 
   const ndn::Name&
-  getLsaPrefix()
+  getLsaPrefix() const
   {
     return m_lsaPrefix;
   }
@@ -162,31 +171,43 @@
   }
 
   int32_t
-  getLsaRefreshTime()
+  getLsaRefreshTime() const
   {
     return m_lsaRefreshTime;
   }
 
   void
+  setLsaInterestLifetime(const ndn::time::seconds& lifetime)
+  {
+    m_lsaInterestLifetime = lifetime;
+  }
+
+  const ndn::time::seconds&
+  getLsaInterestLifetime() const
+  {
+    return m_lsaInterestLifetime;
+  }
+
+  void
   setRouterDeadInterval(int64_t rdt)
   {
     m_routerDeadInterval = rdt;
   }
 
   int64_t
-  getRouterDeadInterval()
+  getRouterDeadInterval() const
   {
     return m_routerDeadInterval;
   }
-  
-  void 
+
+  void
   setLogLevel(const std::string& logLevel)
   {
     m_logLevel = logLevel;
   }
-  
-  const std::string& 
-  getLogLevel()
+
+  const std::string&
+  getLogLevel() const
   {
     return m_logLevel;
   }
@@ -198,7 +219,7 @@
   }
 
   uint32_t
-  getInterestRetryNumber()
+  getInterestRetryNumber() const
   {
     return m_interestRetryNumber;
   }
@@ -210,13 +231,13 @@
   }
 
   int32_t
-  getInterestResendTime()
+  getInterestResendTime() const
   {
     return m_interestResendTime;
   }
 
   int32_t
-  getInfoInterestInterval()
+  getInfoInterestInterval() const
   {
     return m_infoInterestInterval;
   }
@@ -234,7 +255,7 @@
   }
 
   int32_t
-  getHyperbolicState()
+  getHyperbolicState() const
   {
     return m_hyperbolicState;
   }
@@ -250,7 +271,7 @@
   }
 
   double
-  getCorR()
+  getCorR() const
   {
     return m_corR;
   }
@@ -262,11 +283,11 @@
   }
 
   double
-  getCorTheta()
+  getCorTheta() const
   {
     return m_corTheta;
   }
-  
+
   void
   setMaxFacesPerPrefix(int32_t mfpp)
   {
@@ -274,7 +295,7 @@
   }
 
   int32_t
-  getMaxFacesPerPrefix()
+  getMaxFacesPerPrefix() const
   {
     return m_maxFacesPerPrefix;
   }
@@ -286,7 +307,7 @@
   }
 
   const std::string&
-  getLogDir()
+  getLogDir() const
   {
     return m_logDir;
   }
@@ -298,7 +319,7 @@
   }
 
   const std::string&
-  getSeqFileDir()
+  getSeqFileDir() const
   {
     return m_seqFileDir;
   }
@@ -318,21 +339,22 @@
   ndn::Name m_lsaPrefix;
 
   int32_t  m_lsaRefreshTime;
+  ndn::time::seconds m_lsaInterestLifetime;
   int64_t  m_routerDeadInterval;
   std::string m_logLevel;
 
   uint32_t m_interestRetryNumber;
   int32_t  m_interestResendTime;
-  
-  
+
+
   int32_t  m_infoInterestInterval;
-  
+
   int32_t m_hyperbolicState;
   double m_corR;
   double m_corTheta;
 
   int32_t m_maxFacesPerPrefix;
-  
+
   std::string m_logDir;
   std::string m_seqFileDir;
 
diff --git a/src/lsdb.cpp b/src/lsdb.cpp
index 55e8044..dc7882d 100644
--- a/src/lsdb.cpp
+++ b/src/lsdb.cpp
@@ -612,9 +612,9 @@
 }
 
 void
-Lsdb::setLsaRefreshTime(int lrt)
+Lsdb::setLsaRefreshTime(const seconds& lsaRefreshTime)
 {
-  m_lsaRefreshTime = ndn::time::seconds(lrt);
+  m_lsaRefreshTime = lsaRefreshTime;
 }
 
 void
@@ -749,20 +749,23 @@
 
 
 void
-Lsdb::expressInterest(const ndn::Name& interestName, uint32_t interestLifeTime,
-                      uint32_t timeoutCount)
+Lsdb::expressInterest(const ndn::Name& interestName, uint32_t timeoutCount,
+                      steady_clock::TimePoint deadline/* = steady_clock::TimePoint::min()*/)
 {
+  if (deadline == steady_clock::TimePoint::min()) {
+    deadline = steady_clock::now() + m_lsaRefreshTime;
+  }
+
   ndn::Interest interest(interestName);
   uint64_t interestedLsSeqNo = interestName[-1].toNumber();
-  _LOG_DEBUG("Expressing Interest for LSA(name): " << interestName <<
-              " Seq number: " << interestedLsSeqNo );
-  interest.setInterestLifetime(ndn::time::seconds(interestLifeTime));
-  interest.setMustBeFresh(true);
+  _LOG_DEBUG("Expressing Interest for LSA(name): " << interestName
+             << " Seq number: " << interestedLsSeqNo);
+  interest.setInterestLifetime(m_nlsr.getConfParameter().getLsaInterestLifetime());
   m_nlsr.getNlsrFace().expressInterest(interest,
                                        ndn::bind(&Lsdb::onContent,
-                                                 this, _1, _2),
+                                                 this, _2, deadline),
                                        ndn::bind(&Lsdb::processInterestTimedOut,
-                                                 this, _1, timeoutCount));
+                                                 this, _1, timeoutCount, deadline));
 }
 
 void
@@ -811,7 +814,7 @@
 {
   ndn::shared_ptr<ndn::Data> data = ndn::make_shared<ndn::Data>();
   data->setName(ndn::Name(interest.getName()).appendVersion());
-  data->setFreshnessPeriod(ndn::time::seconds(10));
+  data->setFreshnessPeriod(m_lsaRefreshTime);
   data->setContent(reinterpret_cast<const uint8_t*>(content.c_str()), content.size());
   m_nlsr.getKeyChain().sign(*data, m_nlsr.getDefaultCertName());
   ndn::SignatureSha256WithRsa signature(data->getSignature());
@@ -864,7 +867,8 @@
 }
 
 void
-Lsdb::onContent(const ndn::Interest& interest, const ndn::Data& data)
+Lsdb::onContent(const ndn::Data& data,
+                const steady_clock::TimePoint& deadline)
 {
   _LOG_DEBUG("Received data for LSA(name): " << data.getName());
   if (data.getSignature().hasKeyLocator()) {
@@ -874,11 +878,28 @@
   }
   m_nlsr.getValidator().validate(data,
                                  ndn::bind(&Lsdb::onContentValidated, this, _1),
-                                 ndn::bind(&Lsdb::onContentValidationFailed, this, _1, _2));
+                                 ndn::bind(&Lsdb::onContentValidationFailed, this, _1, _2,
+                                           deadline));
 
 }
 
 void
+Lsdb::retryContentValidation(const ndn::shared_ptr<const ndn::Data>& data,
+                             const steady_clock::TimePoint& deadline)
+{
+  _LOG_DEBUG("Retrying validation of LSA(name): " << data->getName());
+  if (data->getSignature().hasKeyLocator()) {
+    if (data->getSignature().getKeyLocator().getType() == ndn::KeyLocator::KeyLocator_Name) {
+      _LOG_DEBUG("Data signed with: " << data->getSignature().getKeyLocator().getName());
+    }
+  }
+  m_nlsr.getValidator().validate(*data,
+                                 ndn::bind(&Lsdb::onContentValidated, this, _1),
+                                 ndn::bind(&Lsdb::onContentValidationFailed, this, _1, _2,
+                                           deadline));
+}
+
+void
 Lsdb::onContentValidated(const ndn::shared_ptr<const ndn::Data>& data)
 {
   const ndn::Name& dataName = data->getName();
@@ -916,9 +937,23 @@
 }
 
 void
-Lsdb::onContentValidationFailed(const ndn::shared_ptr<const ndn::Data>& data, const std::string& msg)
+Lsdb::onContentValidationFailed(const ndn::shared_ptr<const ndn::Data>& data,
+                                const std::string& msg,
+                                const steady_clock::TimePoint& deadline)
 {
   _LOG_DEBUG("Validation Error: " << msg);
+
+  // Delay re-validation by LSA Interest Lifetime.  When error callback will have an error
+  // code, re-validation should be done only when some keys from certification chain failed
+  // to be fetched.  After that change, delaying will no longer be necessary.
+
+  // Stop retrying if delayed re-validation will be scheduled pass the deadline
+  if (steady_clock::now() + m_nlsr.getConfParameter().getLsaInterestLifetime() < deadline) {
+    _LOG_DEBUG("Scheduling revalidation");
+    m_nlsr.getScheduler().scheduleEvent(m_nlsr.getConfParameter().getLsaInterestLifetime(),
+                                        ndn::bind(&Lsdb::retryContentValidation,
+                                                  this, data, deadline));
+  }
 }
 
 void
@@ -967,16 +1002,14 @@
 }
 
 void
-Lsdb::processInterestTimedOut(const ndn::Interest& interest, uint32_t timeoutCount)
+Lsdb::processInterestTimedOut(const ndn::Interest& interest, uint32_t retransmitNo,
+                              const ndn::time::steady_clock::TimePoint& deadline)
 {
-  const ndn::Name& interestName(interest.getName());
+  const ndn::Name& interestName = interest.getName();
   _LOG_DEBUG("Interest timed out for  LSA(name): " << interestName);
-  if ((timeoutCount + 1) <= m_nlsr.getConfParameter().getInterestRetryNumber()) {
-    _LOG_DEBUG("Interest timeoutCount: " << (timeoutCount + 1));
-    _LOG_DEBUG("Need to express interest again for LSA(name): " << interestName);
-    expressInterest(interestName,
-                    m_nlsr.getConfParameter().getInterestResendTime(),
-                    timeoutCount + 1);
+
+  if (ndn::time::steady_clock::now() < deadline) {
+    expressInterest(interestName, retransmitNo + 1, deadline);
   }
 }
 
diff --git a/src/lsdb.hpp b/src/lsdb.hpp
index 6bfc849..ef45cea 100644
--- a/src/lsdb.hpp
+++ b/src/lsdb.hpp
@@ -31,6 +31,9 @@
 #include "lsa.hpp"
 
 namespace nlsr {
+
+using namespace ndn::time;
+
 class Nlsr;
 
 class Lsdb
@@ -109,7 +112,7 @@
   writeAdjLsdbLog();
 
   void
-  setLsaRefreshTime(int lrt);
+  setLsaRefreshTime(const seconds& lsaRefreshTime);
 
   void
   setThisRouterPrefix(std::string trp);
@@ -136,29 +139,29 @@
 
   ndn::EventId
   scheduleNameLsaExpiration(const ndn::Name& key, int seqNo,
-                            const ndn::time::seconds& expTime);
+                            const seconds& expTime);
 
   void
   exprireOrRefreshNameLsa(const ndn::Name& lsaKey, uint64_t seqNo);
 
   ndn::EventId
   scheduleAdjLsaExpiration(const ndn::Name& key, int seqNo,
-                           const ndn::time::seconds& expTime);
+                           const seconds& expTime);
 
   void
   exprireOrRefreshAdjLsa(const ndn::Name& lsaKey, uint64_t seqNo);
 
   ndn::EventId
   scheduleCoordinateLsaExpiration(const ndn::Name& key, int seqNo,
-                                  const ndn::time::seconds& expTime);
+                                  const seconds& expTime);
 
   void
   exprireOrRefreshCoordinateLsa(const ndn::Name& lsaKey,
                                 uint64_t seqNo);
 public:
   void
-  expressInterest(const ndn::Name& interestName, uint32_t interestLifeTime,
-                  uint32_t timeoutCount);
+  expressInterest(const ndn::Name& interestName, uint32_t timeoutCount,
+                  steady_clock::TimePoint deadline = steady_clock::TimePoint::min());
 
   void
   processInterest(const ndn::Name& name, const ndn::Interest& interest);
@@ -183,13 +186,27 @@
                                   uint32_t interestedlsSeqNo);
 
   void
-  onContent(const ndn::Interest& interest, const ndn::Data& data);
+  onContent(const ndn::Data& data, const steady_clock::TimePoint& deadline);
+
+  /**
+   * @brief Retry validation after it fails
+   *
+   * Data packet validation can fail either because the packet does not have
+   * valid signature (fatal) or because some of the certificate chain Data packets
+   * failed to be fetched (non-fatal).  Currently, the library does not provide
+   * clear indication (besides plain-text message in error callback) of what is
+   * the reason for failure and we will try to re-validate for as long as it the deadline.
+   */
+  void
+  retryContentValidation(const ndn::shared_ptr<const ndn::Data>& data,
+                         const steady_clock::TimePoint& deadline);
 
   void
   onContentValidated(const ndn::shared_ptr<const ndn::Data>& data);
 
   void
-  onContentValidationFailed(const ndn::shared_ptr<const ndn::Data>& data, const std::string& msg);
+  onContentValidationFailed(const ndn::shared_ptr<const ndn::Data>& data, const std::string& msg,
+                            const steady_clock::TimePoint& deadline);
 
   void
   processContentNameLsa(const ndn::Name& lsaKey,
@@ -204,9 +221,10 @@
                               uint32_t lsSeqNo, std::string& dataContent);
 
   void
-  processInterestTimedOut(const ndn::Interest& interest, uint32_t timeoutCount);
+  processInterestTimedOut(const ndn::Interest& interest, uint32_t retransmitNo,
+                          const steady_clock::TimePoint& deadline);
 
-  ndn::time::system_clock::TimePoint
+  system_clock::TimePoint
   getLsaExpirationTimePoint();
 
 private:
@@ -218,7 +236,7 @@
   std::list<AdjLsa> m_adjLsdb;
   std::list<CoordinateLsa> m_corLsdb;
 
-  ndn::time::seconds m_lsaRefreshTime;
+  seconds m_lsaRefreshTime;
   std::string m_thisRouterPrefix;
 
 };
diff --git a/src/nlsr.cpp b/src/nlsr.cpp
index 3ee4ccd..893809a 100644
--- a/src/nlsr.cpp
+++ b/src/nlsr.cpp
@@ -122,7 +122,7 @@
 {
   _LOG_DEBUG("Initializing Nlsr");
   m_confParam.buildRouterPrefix();
-  m_nlsrLsdb.setLsaRefreshTime(m_confParam.getLsaRefreshTime());
+  m_nlsrLsdb.setLsaRefreshTime(ndn::time::seconds(m_confParam.getLsaRefreshTime()));
   m_nlsrLsdb.setThisRouterPrefix(m_confParam.getRouterPrefix().toUri());
   m_fib.setEntryRefreshTime(2 * m_confParam.getLsaRefreshTime());
   m_sequencingManager.setSeqFileName(m_confParam.getSeqFileDir());