nrd-config: Adding processing of command line arguments and processing of conf file.

refs #1450

Change-Id: I18fa5c1c12ec2367670659be331a9f95e0a920eb
diff --git a/src/common.hpp b/src/common.hpp
index 650f2de..f520828 100644
--- a/src/common.hpp
+++ b/src/common.hpp
@@ -22,5 +22,24 @@
 #include <boost/lexical_cast.hpp>
 #include <boost/algorithm/string.hpp>
 #include <boost/algorithm/string/regex_find_format.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/info_parser.hpp>
 
+#include "../build/src/config.hpp"
+
+namespace ndn {
+namespace nrd {
+
+class Error : public std::runtime_error
+{
+public:
+  explicit
+  Error(const std::string& what)
+    : std::runtime_error(what)
+  {
+  }
+};
+
+} //namespace nrd
+} //namespace ndn
 #endif // NRD_COMMON_HPP
diff --git a/src/main.cpp b/src/main.cpp
index e360e5d..5d0e5ed 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -4,21 +4,97 @@
  * See COPYING for copyright and distribution information.
  */
 
+#include "common.hpp"
 #include "nrd.hpp"
+#include "nrd-config.hpp"
+#include <getopt.h>
+
+struct ProgramOptions
+{
+  bool showUsage;
+  std::string config;
+};
+
+static void
+printUsage(std::ostream& os, const std::string& programName)
+{
+  os << "Usage: \n"
+    << "  " << programName << " [options]\n"
+    << "\n"
+    << "Run NRD daemon\n"
+    << "\n"
+    << "Options:\n"
+    << "  [--help]   - print this help message\n"
+    << "  [--config /path/to/nrd.conf] - path to configuration file "
+    << "(default: " << DEFAULT_CONFIG_FILE << ")\n"
+    ;
+}
+
+static bool
+parseCommandLine(int argc, char** argv, ProgramOptions& options)
+{
+  options.showUsage = false;
+  options.config = DEFAULT_CONFIG_FILE;
+
+  while (true) {
+    int optionIndex = 0;
+    static ::option longOptions[] = {
+      { "help"   , no_argument      , 0, 0 },
+      { "config" , required_argument, 0, 0 },
+      { 0        , 0                , 0, 0 }
+    };
+    int c = getopt_long_only(argc, argv, "", longOptions, &optionIndex);
+    if (c == -1)
+      break;
+
+    switch (c) {
+      case 0:
+        switch (optionIndex) {
+          case 0: // help
+            options.showUsage = true;
+            break;
+          case 1: // config
+            options.config = ::optarg;
+            break;
+          default:
+            return false;
+        }
+        break;
+    }
+  }
+  return true;
+}
 
 int
 main(int argc, char** argv)
 {
-  try {
-    // TODO: the configFilename should be obtained from command line arguments.
-    std::string configFilename("nrd.conf");
+  //processing command line arguments, if available
+  ProgramOptions options;
+  bool isCommandLineValid = parseCommandLine(argc, argv, options);
+  if (!isCommandLineValid) {
+    printUsage(std::cerr, argv[0]);
+    return 1;
+  }
+  if (options.showUsage) {
+    printUsage(std::cout, argv[0]);
+    return 0;
+  }
 
-    ndn::nrd::Nrd nrd(configFilename);
+  //Now read the config file and pass the security section to validator
+  try {
+    std::string configFilename(options.config);
+
+    ndn::nrd::NrdConfig config;
+    config.load(configFilename);
+    ndn::nrd::ConfigSection securitySection = config.getSecuritySection();
+
+    ndn::nrd::Nrd nrd(securitySection, configFilename);
     nrd.enableLocalControlHeader();
     nrd.listen();
   }
   catch (std::exception& e) {
     std::cerr << "ERROR: " << e.what() << std::endl;
   }
+
   return 0;
 }
diff --git a/src/nrd-config.cpp b/src/nrd-config.cpp
new file mode 100644
index 0000000..c6181f9
--- /dev/null
+++ b/src/nrd-config.cpp
@@ -0,0 +1,116 @@
+#include "nrd-config.hpp"
+
+namespace ndn {
+namespace nrd {
+
+NrdConfig::NrdConfig()
+  : m_isSecuritySectionDefined(false)
+{
+}
+
+void
+NrdConfig::load(const std::string& filename)
+{
+  std::ifstream inputFile;
+  inputFile.open(filename.c_str());
+  if (!inputFile.good() || !inputFile.is_open())
+  {
+    std::string msg = "Failed to read configuration file: ";
+    msg += filename;
+    std::cerr << filename << std::endl;
+    throw Error(msg);
+  }
+  load(inputFile, filename);
+  inputFile.close();
+}
+
+void
+NrdConfig::load(const std::string& input, const std::string& filename)
+{
+  std::istringstream inputStream(input);
+  load(inputStream, filename);
+}
+
+void
+NrdConfig::load(std::istream& input, const std::string& filename)
+{
+  BOOST_ASSERT(!filename.empty());
+
+  ConfigSection ptree;
+  try
+  {
+    boost::property_tree::read_info(input, ptree);
+  }
+  catch (const boost::property_tree::info_parser_error& error)
+  {
+    std::stringstream msg;
+    msg << "Failed to parse configuration file";
+    msg << " " << filename;
+    msg << " " << error.message() << " line " << error.line();
+    throw Error(msg.str());
+  }
+  process(ptree, filename);
+}
+
+void
+NrdConfig::process(const ConfigSection& configSection,
+                   const std::string& filename)
+{
+  BOOST_ASSERT(!filename.empty());
+
+  if (configSection.begin() == configSection.end())
+    {
+      std::string msg = "Error processing configuration file";
+      msg += ": ";
+      msg += filename;
+      msg += " no data";
+      throw Error(msg);
+    }
+
+  for (ConfigSection::const_iterator i = configSection.begin();
+       i != configSection.end(); ++i)
+    {
+      const std::string& sectionName = i->first;
+      const ConfigSection& section = i->second;
+
+      if (boost::iequals(sectionName, "security"))
+        {
+          onSectionSecurity(section, filename);
+        }
+      //Add more sections here as needed
+      //else if (boost::iequals(sectionName, "another-section"))
+        //{
+          //onSectionAnotherSection(section, filename);
+        //}
+      else
+        {
+          std::string msg = "Error processing configuration file";
+          msg += " ";
+          msg += filename;
+          msg += " unrecognized section: " + sectionName;
+          throw Error(msg);
+        }
+    }
+}
+
+void
+NrdConfig::onSectionSecurity(const ConfigSection& section,
+                             const std::string& filename)
+{
+  if (!m_isSecuritySectionDefined) {
+    //setSecturitySection(section);
+    m_securitySection = section;
+    m_filename = filename;
+    m_isSecuritySectionDefined = true;
+  }
+  else {
+    std::string msg = "Error processing configuration file";
+    msg += " ";
+    msg += filename;
+    msg += " security section can appear only once";
+    throw Error(msg);
+  }
+}
+
+} //namespace nrd
+} //namespace ndn
diff --git a/src/nrd-config.hpp b/src/nrd-config.hpp
new file mode 100644
index 0000000..ee119f6
--- /dev/null
+++ b/src/nrd-config.hpp
@@ -0,0 +1,61 @@
+#ifndef NRD_CONFIG_HPP
+#define NRD_CONFIG_HPP
+
+#include "common.hpp"
+
+namespace ndn {
+namespace nrd {
+
+typedef boost::property_tree::ptree ConfigSection;
+
+class NrdConfig
+{
+
+public:
+  NrdConfig();
+
+  virtual
+  ~NrdConfig()
+  {
+  }
+
+  void
+  load(const std::string& filename);
+
+  void
+  load(const std::string& input, const std::string& filename);
+
+  void
+  load(std::istream& input, const std::string& filename);
+
+  const ConfigSection&
+  getSecuritySection() const
+  {
+    return m_securitySection;
+  }
+
+private:
+  void
+  process(const ConfigSection& configSection,
+          const std::string& filename);
+
+  void
+  onSectionSecurity(const ConfigSection& section,
+                    const std::string& filename);
+
+  const void
+  setSecturitySection(const ConfigSection& securitySection)
+  {
+    m_securitySection = securitySection;
+  }
+
+private:
+  bool m_isSecuritySectionDefined;
+  ConfigSection m_securitySection;
+  std::string m_filename;
+};
+
+}//namespace nrd
+}//namespace ndn
+
+#endif // NRD_CONFIG_HPP
diff --git a/src/nrd.cpp b/src/nrd.cpp
index 09db6b2..492f9c2 100644
--- a/src/nrd.cpp
+++ b/src/nrd.cpp
@@ -34,7 +34,8 @@
                      ),
   };
 
-Nrd::Nrd(const std::string& validatorConfig)
+Nrd::Nrd(const ndn::nrd::ConfigSection& securitySection,
+         const std::string& validatorConfig)
   : m_face(new Face())
   , m_nfdController(new nfd::Controller(*m_face))
   , m_validator(m_face)
@@ -45,7 +46,8 @@
   //check whether the components of localhop and localhost prefixes are same
   BOOST_ASSERT(COMMAND_PREFIX.size() == REMOTE_COMMAND_PREFIX.size());
 
-  m_validator.load(validatorConfig);
+  //m_validator.load(validatorConfig);
+  m_validator.load(securitySection, validatorConfig);
 
   std::cerr << "Setting interest filter on: " << COMMAND_PREFIX.toUri() << std::endl;
   m_face->setController(m_nfdController);
@@ -70,7 +72,6 @@
   m_face->shutdown();
 }
 
-
 void
 Nrd::sendResponse(const Name& name,
                   const nfd::ControlResponse& response)
@@ -230,7 +231,6 @@
   sendResponse(request.getName(), response);
 }
 
-
 void
 Nrd::insertEntry(const Interest& request, const PrefixRegOptions& options)
 {
@@ -248,7 +248,6 @@
     bind(&Nrd::onCommandError, this, _1, _2, request, options));
 }
 
-
 void
 Nrd::deleteEntry(const Interest& request, const PrefixRegOptions& options)
 {
@@ -260,7 +259,6 @@
     bind(&Nrd::onCommandError, this, _1, _2, request, options));
 }
 
-
 void
 Nrd::listen()
 {
@@ -268,14 +266,12 @@
   m_face->processEvents();
 }
 
-
 void
 Nrd::onControlHeaderSuccess()
 {
   std::cout << "Local control header enabled" << std::endl;
 }
 
-
 void
 Nrd::onControlHeaderError(uint32_t code, const std::string& reason)
 {
@@ -298,9 +294,10 @@
 Nrd::onNotification(const nfd::FaceEventNotification& notification)
 {
   /// \todo A notification can be missed, in this case check Facelist
-  if (notification.getKind() == 2) { //face destroyed
-      m_managedRib.erase(notification.getFaceId());
-    }
+  std::cerr << "Notification Rcvd: " << notification << std::endl;
+  if (notification.getKind() == ndn::nfd::FACE_EVENT_DESTROYED) { //face destroyed
+    m_managedRib.erase(notification.getFaceId());
+  }
 }
 
 } // namespace nrd
diff --git a/src/nrd.hpp b/src/nrd.hpp
index b441de8..d6007d7 100644
--- a/src/nrd.hpp
+++ b/src/nrd.hpp
@@ -9,15 +9,16 @@
 
 #include "rib.hpp"
 #include "face-monitor.hpp"
+#include "nrd-config.hpp"
 
 namespace ndn {
 namespace nrd {
 
-class Nrd
+class Nrd : noncopyable
 {
 public:
-  explicit
-  Nrd(const std::string& validatorConfig);
+  Nrd(const ndn::nrd::ConfigSection& securitySection,
+      const std::string& validatorConfig);
 
   void
   onRibRequest(const Interest& request);