conf: Make event intervals configurable

User can specify the intervals for the first Hello Interest,
AdjLsa building, and routing calculation in the conf file.

refs: #2071

Change-Id: Ic8eb29d433069086955178bc42b5f8fc8f4149d3
diff --git a/src/conf-file-processor.cpp b/src/conf-file-processor.cpp
index 45890d1..bf07bee 100644
--- a/src/conf-file-processor.cpp
+++ b/src/conf-file-processor.cpp
@@ -39,6 +39,105 @@
 
 using namespace std;
 
+template <class T>
+class ConfigurationVariable
+{
+public:
+  typedef ndn::function<void(T)> ConfParameterCallback;
+  typedef boost::property_tree::ptree ConfigSection;
+
+  ConfigurationVariable(const std::string& key, const ConfParameterCallback& setter)
+    : m_key(key)
+    , m_setterCallback(setter)
+    , m_minValue(0)
+    , m_maxValue(0)
+    , m_shouldCheckRange(false)
+    , m_isRequired(true)
+  {
+  }
+
+  bool
+  parseFromConfigSection(const ConfigSection& section)
+  {
+    try {
+      T value = section.get<T>(m_key);
+
+      if (!isValidValue(value)) {
+        return false;
+      }
+
+      m_setterCallback(value);
+      return true;
+    }
+    catch (const std::exception& ex) {
+
+      if (m_isRequired) {
+        std::cerr << ex.what() << std::endl;
+        std::cerr << "Missing required configuration variable" << std::endl;
+        return false;
+      }
+      else {
+        m_setterCallback(m_defaultValue);
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  void
+  setMinAndMaxValue(T min, T max)
+  {
+    m_minValue = min;
+    m_maxValue = max;
+    m_shouldCheckRange = true;
+  }
+
+  void
+  setOptional(T defaultValue)
+  {
+    m_isRequired = false;
+    m_defaultValue = defaultValue;
+  }
+
+private:
+  void
+  printOutOfRangeError(T value)
+  {
+    std::cerr << "Invalid value for " << m_key << ": "
+              << value << ". "
+              << "Valid values: "
+              << m_minValue << " - "
+              << m_maxValue << std::endl;
+  }
+
+  bool
+  isValidValue(T value)
+  {
+    if (!m_shouldCheckRange) {
+      return true;
+    }
+    else if (value < m_minValue || value > m_maxValue)
+    {
+      printOutOfRangeError(value);
+      return false;
+    }
+
+    return true;
+  }
+
+private:
+  const std::string m_key;
+  const ConfParameterCallback m_setterCallback;
+  T m_defaultValue;
+
+  T m_minValue;
+  T m_maxValue;
+
+  bool m_shouldCheckRange;
+  bool m_isRequired;
+};
+
 bool
 ConfFileProcessor::processConfFile()
 {
@@ -325,6 +424,30 @@
   catch (const std::exception& ex) {
     std::cerr << ex.what() << std::endl;
   }
+
+  // Event intervals
+  // adj-lsa-build-interval
+  ConfigurationVariable<uint32_t> adjLsaBuildInterval("adj-lsa-build-interval",
+                                                      bind(&ConfParameter::setAdjLsaBuildInterval,
+                                                      &m_nlsr.getConfParameter(), _1));
+  adjLsaBuildInterval.setMinAndMaxValue(ADJ_LSA_BUILD_INTERVAL_MIN, ADJ_LSA_BUILD_INTERVAL_MAX);
+  adjLsaBuildInterval.setOptional(ADJ_LSA_BUILD_INTERVAL_DEFAULT);
+
+  if (!adjLsaBuildInterval.parseFromConfigSection(section)) {
+    return false;
+  }
+
+  // first-hello-interval
+  ConfigurationVariable<uint32_t> firstHelloInterval("first-hello-interval",
+                                                     bind(&ConfParameter::setFirstHelloInterval,
+                                                     &m_nlsr.getConfParameter(), _1));
+  firstHelloInterval.setMinAndMaxValue(FIRST_HELLO_INTERVAL_MIN, FIRST_HELLO_INTERVAL_MAX);
+  firstHelloInterval.setOptional(FIRST_HELLO_INTERVAL_DEFAULT);
+
+  if (!firstHelloInterval.parseFromConfigSection(section)) {
+    return false;
+  }
+
   for (ConfigSection::const_iterator tn =
            section.begin(); tn != section.end(); ++tn) {
 
@@ -425,6 +548,18 @@
     cerr << ex.what() << endl;
     return false;
   }
+
+  // routing-calc-interval
+  ConfigurationVariable<uint32_t> routingCalcInterval("routing-calc-interval",
+                                                      bind(&ConfParameter::setRoutingCalcInterval,
+                                                      &m_nlsr.getConfParameter(), _1));
+  routingCalcInterval.setMinAndMaxValue(ROUTING_CALC_INTERVAL_MIN, ROUTING_CALC_INTERVAL_MAX);
+  routingCalcInterval.setOptional(ROUTING_CALC_INTERVAL_DEFAULT);
+
+  if (!routingCalcInterval.parseFromConfigSection(section)) {
+    return false;
+  }
+
   return true;
 }
 
diff --git a/src/conf-parameter.cpp b/src/conf-parameter.cpp
index f45fea7..f2b8bd2 100644
--- a/src/conf-parameter.cpp
+++ b/src/conf-parameter.cpp
@@ -34,7 +34,7 @@
   _LOG_DEBUG("Site Name: " << m_siteName);
   _LOG_DEBUG("Network: " << m_network);
   _LOG_DEBUG("Router Prefix: " << m_routerPrefix);
-  _LOG_DEBUG("ChronoSync sync Prifex: " << m_chronosyncPrefix);
+  _LOG_DEBUG("ChronoSync sync Prefix: " << m_chronosyncPrefix);
   _LOG_DEBUG("ChronoSync LSA prefix: " << m_lsaPrefix);
   _LOG_DEBUG("Hello Interest retry number: " << m_interestRetryNumber);
   _LOG_DEBUG("Hello Interest resend second: " << m_interestResendTime);
@@ -42,11 +42,16 @@
   _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("Hyperbolic Routing: " << m_hyperbolicState);
   _LOG_DEBUG("Hyp R: " << m_corR);
   _LOG_DEBUG("Hyp theta: " << m_corTheta);
   _LOG_DEBUG("Log Directory: " << m_logDir);
   _LOG_DEBUG("Seq Directory: " << m_seqFileDir);
+
+  // Event Intervals
+  _LOG_DEBUG("Adjacency LSA build interval:  " << m_adjLsaBuildInterval);
+  _LOG_DEBUG("First Hello Interest interval: " << m_firstHelloInterval);
+  _LOG_DEBUG("Routing calculation interval:  " << m_routingCalcInterval);
 }
 
 } // namespace nlsr
diff --git a/src/conf-parameter.hpp b/src/conf-parameter.hpp
index 8f2965b..6f51d70 100644
--- a/src/conf-parameter.hpp
+++ b/src/conf-parameter.hpp
@@ -46,6 +46,24 @@
 };
 
 enum {
+  ADJ_LSA_BUILD_INTERVAL_MIN = 0,
+  ADJ_LSA_BUILD_INTERVAL_DEFAULT = 5,
+  ADJ_LSA_BUILD_INTERVAL_MAX = 5
+};
+
+enum {
+  FIRST_HELLO_INTERVAL_MIN = 0,
+  FIRST_HELLO_INTERVAL_DEFAULT = 10,
+  FIRST_HELLO_INTERVAL_MAX = 10
+};
+
+enum {
+  ROUTING_CALC_INTERVAL_MIN = 0,
+  ROUTING_CALC_INTERVAL_DEFAULT = 15,
+  ROUTING_CALC_INTERVAL_MAX = 15
+};
+
+enum {
   HELLO_RETRIES_MIN = 1,
   HELLO_RETRIES_DEFAULT = 3,
   HELLO_RETRIES_MAX = 15
@@ -80,6 +98,9 @@
 public:
   ConfParameter()
     : m_lsaRefreshTime(LSA_REFRESH_TIME_DEFAULT)
+    , m_adjLsaBuildInterval(ADJ_LSA_BUILD_INTERVAL_DEFAULT)
+    , m_firstHelloInterval(FIRST_HELLO_INTERVAL_DEFAULT)
+    , m_routingCalcInterval(ROUTING_CALC_INTERVAL_DEFAULT)
     , m_lsaInterestLifetime(ndn::time::seconds(static_cast<int>(LSA_INTEREST_LIFETIME_DEFAULT)))
     , m_routerDeadInterval(2*LSA_REFRESH_TIME_DEFAULT)
     , m_logLevel("INFO")
@@ -189,6 +210,42 @@
   }
 
   void
+  setAdjLsaBuildInterval(uint32_t interval)
+  {
+    m_adjLsaBuildInterval = interval;
+  }
+
+  uint32_t
+  getAdjLsaBuildInterval() const
+  {
+    return m_adjLsaBuildInterval;
+  }
+
+  void
+  setFirstHelloInterval(uint32_t interval)
+  {
+    m_firstHelloInterval = interval;
+  }
+
+  uint32_t
+  getFirstHelloInterval() const
+  {
+    return m_firstHelloInterval;
+  }
+
+  void
+  setRoutingCalcInterval(uint32_t interval)
+  {
+    m_routingCalcInterval = interval;
+  }
+
+  uint32_t
+  getRoutingCalcInterval() const
+  {
+    return m_routingCalcInterval;
+  }
+
+  void
   setRouterDeadInterval(int64_t rdt)
   {
     m_routerDeadInterval = rdt;
@@ -339,6 +396,11 @@
   ndn::Name m_lsaPrefix;
 
   int32_t  m_lsaRefreshTime;
+
+  uint32_t m_adjLsaBuildInterval;
+  uint32_t m_firstHelloInterval;
+  uint32_t m_routingCalcInterval;
+
   ndn::time::seconds m_lsaInterestLifetime;
   int64_t  m_routerDeadInterval;
   std::string m_logLevel;
diff --git a/src/hello-protocol.cpp b/src/hello-protocol.cpp
index cefaa29..1af254e 100644
--- a/src/hello-protocol.cpp
+++ b/src/hello-protocol.cpp
@@ -155,7 +155,7 @@
       _LOG_DEBUG("Scheduling scheduledAdjLsaBuild");
       m_nlsr.setIsBuildAdjLsaSheduled(true);
       // event here
-      m_scheduler.scheduleEvent(ndn::time::seconds(5),
+      m_scheduler.scheduleEvent(m_adjLsaBuildInterval,
                                 ndn::bind(&Lsdb::scheduledAdjLsaBuild, &m_nlsr.getLsdb()));
     }
   }
@@ -200,7 +200,7 @@
         _LOG_DEBUG("Scheduling scheduledAdjLsaBuild");
         m_nlsr.setIsBuildAdjLsaSheduled(true);
         // event here
-        m_scheduler.scheduleEvent(ndn::time::seconds(5),
+        m_scheduler.scheduleEvent(m_adjLsaBuildInterval,
                                   ndn::bind(&Lsdb::scheduledAdjLsaBuild, &m_nlsr.getLsdb()));
       }
     }
@@ -285,7 +285,7 @@
         _LOG_DEBUG("Scheduling scheduledAdjLsaBuild");
         m_nlsr.setIsBuildAdjLsaSheduled(true);
         // event here
-        m_scheduler.scheduleEvent(ndn::time::seconds(5),
+        m_scheduler.scheduleEvent(m_adjLsaBuildInterval,
                                   ndn::bind(&Lsdb::scheduledAdjLsaBuild, &m_nlsr.getLsdb()));
       }
     }
diff --git a/src/hello-protocol.hpp b/src/hello-protocol.hpp
index 30385d9..25868bd 100644
--- a/src/hello-protocol.hpp
+++ b/src/hello-protocol.hpp
@@ -33,15 +33,14 @@
 
 class HelloProtocol
 {
-
 public:
   HelloProtocol(Nlsr& nlsr, ndn::Scheduler& scheduler)
     : m_nlsr(nlsr)
     , m_scheduler(scheduler)
+    , m_adjLsaBuildInterval(static_cast<uint32_t>(ADJ_LSA_BUILD_INTERVAL_DEFAULT))
   {
   }
 
-public:
   void
   scheduleInterest(uint32_t seconds);
 
@@ -54,6 +53,18 @@
   void
   processInterest(const ndn::Name& name, const ndn::Interest& interest);
 
+  void
+  setAdjLsaBuildInterval(uint32_t interval)
+  {
+    m_adjLsaBuildInterval = ndn::time::seconds(interval);
+  }
+
+  const ndn::time::seconds&
+  getAdjLsaBuildInterval() const
+  {
+    return m_adjLsaBuildInterval;
+  }
+
 private:
   void
   processInterestTimedOut(const ndn::Interest& interest);
@@ -85,6 +96,8 @@
 
   static const std::string INFO_COMPONENT;
   static const std::string NLSR_COMPONENT;
+
+  ndn::time::seconds m_adjLsaBuildInterval;
 };
 
 } //namespace nlsr
diff --git a/src/nlsr.cpp b/src/nlsr.cpp
index 930dc33..a66e6aa 100644
--- a/src/nlsr.cpp
+++ b/src/nlsr.cpp
@@ -142,7 +142,13 @@
   m_nlsrLsdb.buildAndInstallOwnCoordinateLsa();
 
   registerKeyPrefix();
-  m_helloProtocol.scheduleInterest(10);
+
+  // Set event intervals
+  setFirstHelloInterval(m_confParam.getFirstHelloInterval());
+  m_helloProtocol.setAdjLsaBuildInterval(m_confParam.getAdjLsaBuildInterval());
+  m_routingTable.setRoutingCalcInterval(m_confParam.getRoutingCalcInterval());
+
+  m_helloProtocol.scheduleInterest(m_firstHelloInterval);
 
   // Need to set direct neighbors' costs to 0 for hyperbolic routing
   if (m_confParam.getHyperbolicState() == HYPERBOLIC_STATE_ON) {
diff --git a/src/nlsr.hpp b/src/nlsr.hpp
index 00b7877..866ad7c 100644
--- a/src/nlsr.hpp
+++ b/src/nlsr.hpp
@@ -43,6 +43,7 @@
 #include "route/fib.hpp"
 #include "communication/sync-logic-handler.hpp"
 #include "hello-protocol.hpp"
+#include "test-access-control.hpp"
 
 #include "validator.hpp"
 
@@ -86,6 +87,7 @@
     , m_certificateCache(new ndn::CertificateCacheTtl(ioService))
     , m_validator(m_nlsrFace, DEFAULT_BROADCAST_PREFIX, m_certificateCache)
     , m_faceMonitor(m_nlsrFace)
+    , m_firstHelloInterval(FIRST_HELLO_INTERVAL_DEFAULT)
   {
     m_faceMonitor.onNotification += ndn::bind(&Nlsr::onFaceEventNotification, this, _1);
     m_faceMonitor.start();
@@ -313,6 +315,12 @@
   void
   daemonize();
 
+  uint32_t
+  getFirstHelloInterval() const
+  {
+    return m_firstHelloInterval;
+  }
+
 private:
   void
   registerKeyPrefix();
@@ -332,6 +340,12 @@
   void
   onFaceEventNotification(const ndn::nfd::FaceEventNotification& faceEventNotification);
 
+  void
+  setFirstHelloInterval(uint32_t interval)
+  {
+    m_firstHelloInterval = interval;
+  }
+
 private:
   typedef std::map<ndn::Name, ndn::shared_ptr<ndn::IdentityCertificate> > CertMap;
 
@@ -352,8 +366,11 @@
   Fib m_fib;
   NamePrefixTable m_namePrefixTable;
   SyncLogicHandler m_syncLogicHandler;
+
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   HelloProtocol m_helloProtocol;
 
+private:
   ndn::shared_ptr<ndn::CertificateCacheTtl> m_certificateCache;
   CertMap m_certToPublish;
   Validator m_validator;
@@ -362,6 +379,8 @@
   ndn::Name m_defaultCertName;
 
   ndn::nfd::FaceMonitor m_faceMonitor;
+
+  uint32_t m_firstHelloInterval;
 };
 
 } //namespace nlsr
diff --git a/src/route/routing-table.cpp b/src/route/routing-table.cpp
index 09b9430..371d977 100644
--- a/src/route/routing-table.cpp
+++ b/src/route/routing-table.cpp
@@ -156,7 +156,7 @@
 RoutingTable::scheduleRoutingTableCalculation(Nlsr& pnlsr)
 {
   if (pnlsr.getIsRouteCalculationScheduled() != true) {
-    m_scheduler.scheduleEvent(ndn::time::seconds(15),
+    m_scheduler.scheduleEvent(m_routingCalcInterval,
                               ndn::bind(&RoutingTable::calculate, this, ndn::ref(pnlsr)));
 
     pnlsr.setIsRouteCalculationScheduled(true);
diff --git a/src/route/routing-table.hpp b/src/route/routing-table.hpp
index 6dd3ef2..c85efe9 100644
--- a/src/route/routing-table.hpp
+++ b/src/route/routing-table.hpp
@@ -29,6 +29,7 @@
 #include <boost/cstdint.hpp>
 #include <ndn-cxx/util/scheduler.hpp>
 
+#include "conf-parameter.hpp"
 #include "routing-table-entry.hpp"
 
 namespace nlsr {
@@ -42,8 +43,10 @@
   RoutingTable(ndn::Scheduler& scheduler)
     : m_scheduler(scheduler)
     , m_NO_NEXT_HOP(-12345)
+    , m_routingCalcInterval(static_cast<uint32_t>(ROUTING_CALC_INTERVAL_DEFAULT))
   {
   }
+
   void
   calculate(Nlsr& pnlsr);
 
@@ -65,6 +68,18 @@
     return m_NO_NEXT_HOP;
   }
 
+  void
+  setRoutingCalcInterval(uint32_t interval)
+  {
+    m_routingCalcInterval = ndn::time::seconds(interval);
+  }
+
+  const ndn::time::seconds&
+  getRoutingCalcInterval() const
+  {
+    return m_routingCalcInterval;
+  }
+
 private:
   void
   calculateLsRoutingTable(Nlsr& pnlsr);
@@ -91,6 +106,8 @@
 
   std::list<RoutingTableEntry> m_rTable;
   std::list<RoutingTableEntry> m_dryTable;
+
+  ndn::time::seconds m_routingCalcInterval;
 };
 
 }//namespace nlsr