rib: Integrating NRD code into NFD codebase

Change-Id: I3e548f974255f62a4680cfc6c12be3bb7a3db4d2
Refs: #1486
diff --git a/rib/main.cpp b/rib/main.cpp
new file mode 100644
index 0000000..7eddfdd
--- /dev/null
+++ b/rib/main.cpp
@@ -0,0 +1,257 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014  Regents of the University of California,
+ *                     Arizona Board of Regents,
+ *                     Colorado State University,
+ *                     University Pierre & Marie Curie, Sorbonne University,
+ *                     Washington University in St. Louis,
+ *                     Beijing Institute of Technology,
+ *                     The University of Memphis
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include <getopt.h>
+
+#include "common.hpp"
+#include "rib-manager.hpp"
+#include "core/config-file.hpp"
+#include "core/logger.hpp"
+
+namespace nfd {
+namespace rib {
+
+NFD_LOG_INIT("nrd.Main");
+
+struct ProgramOptions
+{
+  bool showUsage;
+  bool showModules;
+  std::string config;
+};
+
+class Nrd : noncopyable
+{
+public:
+  void
+  initialize(const std::string& configFile)
+  {
+    initializeLogging(configFile);
+
+    m_ribManager = make_shared<RibManager>();
+
+    ConfigFile config;
+    m_ribManager->setConfigFile(config);
+    config.addSectionHandler("log", bind(std::plus<int>(), 0, 0)); // no-op
+
+    // parse config file
+    config.parse(configFile, true);
+    config.parse(configFile, false);
+
+    m_ribManager->registerWithNfd();
+    m_ribManager->enableLocalControlHeader();
+  }
+
+  void
+  initializeLogging(const std::string& configFile)
+  {
+    ConfigFile config;
+    LoggerFactory::getInstance().setConfigFile(config);
+
+    for (size_t i = 0; i < N_SUPPORTED_CONFIG_SECTIONS; ++i)
+      {
+        if (SUPPORTED_CONFIG_SECTIONS[i] != "log")
+          {
+            config.addSectionHandler(SUPPORTED_CONFIG_SECTIONS[i],
+                                     bind(std::plus<int>(), 0, 0)); // no-op.
+          }
+      }
+
+    config.parse(configFile, true);
+    config.parse(configFile, false);
+  }
+
+  boost::asio::io_service&
+  getIoService()
+  {
+    return m_ribManager->getIoService();
+  }
+
+  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 void
+  printModules(std::ostream& os)
+  {
+    using namespace std;
+
+    os << "Available logging modules: \n";
+
+    list<string> modules(LoggerFactory::getInstance().getModules());
+    for (list<string>::const_iterator i = modules.begin(); i != modules.end(); ++i)
+      {
+        os << *i << "\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;
+  }
+
+
+  void
+  terminate(const boost::system::error_code& error,
+            int signalNo,
+            boost::asio::signal_set& signalSet)
+  {
+    if (error)
+      return;
+
+    if (signalNo == SIGINT ||
+        signalNo == SIGTERM)
+      {
+        getIoService().stop();
+        std::cout << "Caught signal '" << strsignal(signalNo) << "', exiting..." << std::endl;
+      }
+    else
+      {
+        /// \todo May be try to reload config file (at least security section)
+        signalSet.async_wait(bind(&Nrd::terminate, this, _1, _2,
+                                  boost::ref(signalSet)));
+      }
+  }
+
+private:
+  shared_ptr<RibManager> m_ribManager;
+
+  static const std::string SUPPORTED_CONFIG_SECTIONS[];
+  static const size_t      N_SUPPORTED_CONFIG_SECTIONS;
+};
+
+const std::string Nrd::SUPPORTED_CONFIG_SECTIONS[] =
+  {
+    "log",
+    "security",
+  };
+
+const size_t Nrd::N_SUPPORTED_CONFIG_SECTIONS =
+  sizeof(SUPPORTED_CONFIG_SECTIONS) / sizeof(std::string);
+
+} // namespace rib
+} // namespace nfd
+
+int
+main(int argc, char** argv)
+{
+  using namespace nfd::rib;
+
+  ProgramOptions options;
+  bool isCommandLineValid = Nrd::parseCommandLine(argc, argv, options);
+  if (!isCommandLineValid) {
+    Nrd::printUsage(std::cerr, argv[0]);
+    return 1;
+  }
+  if (options.showUsage) {
+    Nrd::printUsage(std::cout, argv[0]);
+    return 0;
+  }
+
+  if (options.showModules) {
+    Nrd::printModules(std::cout);
+    return 0;
+  }
+
+  Nrd nrdInstance;
+
+  try {
+    nrdInstance.initialize(options.config);
+  }
+  catch (boost::filesystem::filesystem_error& e) {
+    if (e.code() == boost::system::errc::permission_denied) {
+      NFD_LOG_FATAL("Permissions denied for " << e.path1() << ". " <<
+                    argv[0] << " should be run as superuser");
+    }
+    else {
+      NFD_LOG_FATAL(e.what());
+    }
+    return 1;
+  }
+  catch (const std::exception& e) {
+    NFD_LOG_FATAL(e.what());
+    return 2;
+  }
+
+  boost::asio::signal_set signalSet(nrdInstance.getIoService());
+  signalSet.add(SIGINT);
+  signalSet.add(SIGTERM);
+  signalSet.add(SIGHUP);
+  signalSet.add(SIGUSR1);
+  signalSet.add(SIGUSR2);
+  signalSet.async_wait(bind(&Nrd::terminate, &nrdInstance, _1, _2,
+                            boost::ref(signalSet)));
+
+  try {
+    nrdInstance.getIoService().run();
+  }
+  catch (std::exception& e) {
+    NFD_LOG_FATAL(e.what());
+    return 3;
+  }
+
+  return 0;
+}