rib: Refactor initialization of NRD instance
This commit also makes Face used inside NRD be adaptive to nfd.conf.
More specifically, it will use the same unix socket path as specified in
face_system.unix section. If this section is not present, it will use
the same tcp port as specified in face_system.tcp section. If tcp
section is also absent, nrd will abort execution.
Change-Id: I48f75ddf972f259055cd61824e3c228ca1d6a639
Refs: #2496
diff --git a/daemon/main.cpp b/daemon/main.cpp
index aa2d822..eaa4e26 100644
--- a/daemon/main.cpp
+++ b/daemon/main.cpp
@@ -41,7 +41,7 @@
NFD_LOG_INIT("NFD");
-class NfdRunner
+class NfdRunner : noncopyable
{
public:
explicit
diff --git a/rib/main.cpp b/rib/main.cpp
index bfea4f7..62b2ffc 100644
--- a/rib/main.cpp
+++ b/rib/main.cpp
@@ -1,12 +1,12 @@
/* -*- 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
+ * Copyright (c) 2014-2015, 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.
@@ -23,86 +23,35 @@
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <getopt.h>
+#include "nrd.hpp"
#include "version.hpp"
-#include "common.hpp"
-#include "rib-manager.hpp"
-#include "core/config-file.hpp"
-#include "core/global-io.hpp"
#include "core/logger.hpp"
+#include "core/global-io.hpp"
+
+#include <string.h>
+
+#include <boost/filesystem.hpp>
+#include <boost/program_options/options_description.hpp>
+#include <boost/program_options/variables_map.hpp>
+#include <boost/program_options/parsers.hpp>
namespace nfd {
namespace rib {
NFD_LOG_INIT("NRD");
-struct ProgramOptions
-{
- bool showUsage;
- bool showVersion;
- bool showModules;
- std::string config;
-};
-
-class Nrd : noncopyable
+class NrdRunner : noncopyable
{
public:
- class IgnoreNfdAndLogSections
+ explicit
+ NrdRunner(const std::string& configFile)
+ : m_nrd(configFile, m_keyChain)
+ , m_terminationSignalSet(getGlobalIoService())
{
- public:
- void
- operator()(const std::string& filename,
- const std::string& sectionName,
- const ConfigSection& section,
- bool isDryRun)
- {
- // Ignore "log" and sections belonging to NFD,
- // but raise an error if we're missing a handler for an "rib_" section.
-
- if (sectionName.find("rib_") != 0 || sectionName == "log")
- {
- // do nothing
- }
- else
- {
- // missing NRD section
- ConfigFile::throwErrorOnUnknownSection(filename, sectionName, section, isDryRun);
- }
- }
- };
-
- Nrd()
- : m_face(getGlobalIoService())
- {
- }
-
- void
- initialize(const std::string& configFile)
- {
- initializeLogging(configFile);
-
- m_ribManager = make_shared<RibManager>(ndn::ref(m_face));
-
- ConfigFile config((IgnoreNfdAndLogSections()));
- m_ribManager->setConfigFile(config);
-
- // 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(&ConfigFile::ignoreUnknownSection);
- LoggerFactory::getInstance().setConfigFile(config);
-
- config.parse(configFile, true);
- config.parse(configFile, false);
+ m_terminationSignalSet.add(SIGINT);
+ m_terminationSignalSet.add(SIGTERM);
+ m_terminationSignalSet.async_wait(bind(&NrdRunner::terminate, this, _1, _2));
}
static void
@@ -125,125 +74,93 @@
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.showVersion = false;
- options.showModules = false;
- options.config = DEFAULT_CONFIG_FILE;
-
- while (true) {
- int optionIndex = 0;
- static ::option longOptions[] = {
- { "help" , no_argument , 0, 0 },
- { "modules", no_argument , 0, 0 },
- { "config" , required_argument, 0, 0 },
- { "version", no_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: // modules
- options.showModules = true;
- break;
- case 2: // config
- options.config = ::optarg;
- break;
- case 3: // version
- options.showVersion = true;
- break;
- default:
- return false;
- }
- break;
- }
+ for (const auto& module : LoggerFactory::getInstance().getModules()) {
+ os << module << "\n";
}
- return true;
}
-
void
- terminate(const boost::system::error_code& error,
- int signalNo,
- boost::asio::signal_set& signalSet)
+ run()
+ {
+ getGlobalIoService().run();
+ }
+
+ void
+ initialize()
+ {
+ m_nrd.initialize();
+ }
+
+ void
+ terminate(const boost::system::error_code& error, int signalNo)
{
if (error)
return;
- if (signalNo == SIGINT ||
- signalNo == SIGTERM)
- {
- getGlobalIoService().stop();
- NFD_LOG_INFO("Caught signal '" << strsignal(signalNo) << "', exiting...");
- }
- else
- {
- /// \todo May be try to reload config file
- signalSet.async_wait(bind(&Nrd::terminate, this, _1, _2,
- ref(signalSet)));
- }
+ NFD_LOG_INFO("Caught signal '" << ::strsignal(signalNo) << "', exiting...");
+ getGlobalIoService().stop();
}
private:
- shared_ptr<RibManager> m_ribManager;
- ndn::Face m_face;
+ ndn::KeyChain m_keyChain;
+ Nrd m_nrd; // must be after m_io and m_keyChain
+ boost::asio::signal_set m_terminationSignalSet;
};
-} // namespace rib
} // namespace nfd
+} // namespace rib
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]);
+ namespace po = boost::program_options;
+
+ po::options_description description;
+
+ std::string configFile = DEFAULT_CONFIG_FILE;
+ description.add_options()
+ ("help,h", "print this help message")
+ ("version,V", "print version and exit")
+ ("modules,m", "list available logging modules")
+ ("config,c", po::value<std::string>(&configFile), "path to configuration file")
+ ;
+
+ po::variables_map vm;
+ try {
+ po::store(po::command_line_parser(argc, argv).options(description).run(), vm);
+ po::notify(vm);
+ }
+ catch (const std::exception& e) {
+ std::cerr << "ERROR: " << e.what() << std::endl;
+ NrdRunner::printUsage(std::cerr, argv[0]);
return 1;
}
- if (options.showUsage) {
- Nrd::printUsage(std::cout, argv[0]);
+
+ if (vm.count("help") > 0) {
+ NrdRunner::printUsage(std::cout, argv[0]);
return 0;
}
- if (options.showModules) {
- Nrd::printModules(std::cout);
- return 0;
- }
-
- if (options.showVersion) {
+ if (vm.count("version") > 0) {
std::cout << NFD_VERSION_BUILD_STRING << std::endl;
return 0;
}
- Nrd nrdInstance;
+ if (vm.count("modules") > 0) {
+ NrdRunner::printModules(std::cout);
+ return 0;
+ }
+
+ NrdRunner runner(configFile);
try {
- nrdInstance.initialize(options.config);
+ runner.initialize();
}
- catch (boost::filesystem::filesystem_error& e) {
+ catch (const 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");
@@ -258,21 +175,12 @@
return 2;
}
- boost::asio::signal_set signalSet(nfd::getGlobalIoService());
- signalSet.add(SIGINT);
- signalSet.add(SIGTERM);
- signalSet.add(SIGHUP);
- signalSet.add(SIGUSR1);
- signalSet.add(SIGUSR2);
- signalSet.async_wait(bind(&Nrd::terminate, &nrdInstance, _1, _2,
- ndn::ref(signalSet)));
-
try {
- nfd::getGlobalIoService().run();
+ runner.run();
}
- catch (std::exception& e) {
+ catch (const std::exception& e) {
NFD_LOG_FATAL(e.what());
- return 3;
+ return 4;
}
return 0;
diff --git a/rib/nrd.cpp b/rib/nrd.cpp
new file mode 100644
index 0000000..be1f527
--- /dev/null
+++ b/rib/nrd.cpp
@@ -0,0 +1,144 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015, 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 "nrd.hpp"
+
+#include "rib-manager.hpp"
+#include "core/config-file.hpp"
+#include "core/logger-factory.hpp"
+#include "core/global-io.hpp"
+
+#include <boost/property_tree/info_parser.hpp>
+
+#include <ndn-cxx/transport/unix-transport.hpp>
+#include <ndn-cxx/transport/tcp-transport.hpp>
+
+namespace nfd {
+namespace rib {
+
+static const std::string INTERNAL_CONFIG = "internal://nfd.conf";
+
+Nrd::Nrd(const std::string& configFile, ndn::KeyChain& keyChain)
+ : m_configFile(configFile)
+ , m_keyChain(keyChain)
+{
+}
+
+Nrd::Nrd(const ConfigSection& config, ndn::KeyChain& keyChain)
+ : m_configSection(config)
+ , m_keyChain(keyChain)
+{
+}
+
+void
+Nrd::initialize()
+{
+ m_face.reset(new ndn::Face(getLocalNfdTransport(), getGlobalIoService(), m_keyChain));
+
+ initializeLogging();
+
+ m_ribManager.reset(new RibManager(*m_face));
+
+ ConfigFile config([] (const std::string& filename, const std::string& sectionName,
+ const ConfigSection& section, bool isDryRun) {
+ // Ignore "log" and sections belonging to NFD,
+ // but raise an error if we're missing a handler for a "rib" section.
+ if (sectionName != "rib" || sectionName == "log") {
+ // do nothing
+ }
+ else {
+ // missing NRD section
+ ConfigFile::throwErrorOnUnknownSection(filename, sectionName, section, isDryRun);
+ }
+ });
+ m_ribManager->setConfigFile(config);
+
+ // parse config file
+ if (!m_configFile.empty()) {
+ config.parse(m_configFile, true);
+ config.parse(m_configFile, false);
+ }
+ else {
+ config.parse(m_configSection, true, INTERNAL_CONFIG);
+ config.parse(m_configSection, false, INTERNAL_CONFIG);
+ }
+
+ m_ribManager->registerWithNfd();
+ m_ribManager->enableLocalControlHeader();
+}
+
+void
+Nrd::initializeLogging()
+{
+ ConfigFile config(&ConfigFile::ignoreUnknownSection);
+ LoggerFactory::getInstance().setConfigFile(config);
+
+ if (!m_configFile.empty()) {
+ config.parse(m_configFile, true);
+ config.parse(m_configFile, false);
+ }
+ else {
+ config.parse(m_configSection, true, INTERNAL_CONFIG);
+ config.parse(m_configSection, false, INTERNAL_CONFIG);
+ }
+}
+
+shared_ptr<ndn::Transport>
+Nrd::getLocalNfdTransport()
+{
+ ConfigSection config;
+
+ if (!m_configFile.empty()) {
+ // Any format errors should have been caught already
+ // If error is thrown at this point, it is development error
+ boost::property_tree::read_info(m_configFile, config);
+ }
+ else
+ config = m_configSection;
+
+ if (config.get_child_optional("face_system.unix")) {
+ // unix socket enabled
+
+ auto&& socketPath = config.get<std::string>("face_system.unix.path", "/var/run/nfd.sock");
+ // default socketPath should be the same as in FaceManager::processSectionUnix
+
+ return make_shared<ndn::UnixTransport>(socketPath);
+ }
+ else if (config.get_child_optional("face_system.tcp") &&
+ config.get<std::string>("face_system.tcp.listen", "yes") == "yes") {
+ // tcp is enabled
+
+ auto&& port = config.get<std::string>("face_system.tcp.port", "6363");
+ // default port should be the same as in FaceManager::processSectionTcp
+
+ return make_shared<ndn::TcpTransport>("localhost", port);
+ }
+ else {
+ throw Error("No transport is available to communicate with NFD");
+ }
+}
+
+} // namespace rib
+} // namespace nfd
diff --git a/rib/nrd.hpp b/rib/nrd.hpp
new file mode 100644
index 0000000..fda116b
--- /dev/null
+++ b/rib/nrd.hpp
@@ -0,0 +1,101 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015, 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/>.
+ */
+
+#ifndef NFD_RIB_NRD_HPP
+#define NFD_RIB_NRD_HPP
+
+#include "common.hpp"
+#include "core/config-file.hpp"
+#include "rib-manager.hpp"
+
+#include <ndn-cxx/face.hpp>
+#include <ndn-cxx/security/key-chain.hpp>
+#include <ndn-cxx/transport/transport.hpp>
+
+namespace nfd {
+namespace rib {
+
+/**
+ * \brief Class representing NRD (NFD RIB Manager) instance
+ * This class can be used to initialize all components of NRD
+ */
+class Nrd : noncopyable
+{
+public:
+ class Error : public std::runtime_error
+ {
+ public:
+ explicit
+ Error(const std::string& what)
+ : std::runtime_error(what)
+ {
+ }
+ };
+
+ /**
+ * \brief Create NRD instance using absolute or relative path to \p configFile
+ */
+ Nrd(const std::string& configFile, ndn::KeyChain& keyChain);
+
+ /**
+ * \brief Create NRD instance using a parsed ConfigSection \p config
+ * This version of the constructor is more appropriate for integrated environments,
+ * such as NS-3 or android.
+ * \note When using this version of the constructor, error messages will include
+ * "internal://nfd.conf" when referring to configuration errors.
+ */
+ Nrd(const ConfigSection& config, ndn::KeyChain& keyChain);
+
+ /**
+ * \brief Perform initialization of NFD instance
+ * After initialization, NFD instance can be started by invoking run on globalIoService
+ */
+ void
+ initialize();
+
+private:
+ void
+ initializeLogging();
+
+ /**
+ * \brief Look into the config file and construct appropriate transport to communicate with NFD
+ * If NRD instance was initialized with config file, INFO format is assumed
+ */
+ shared_ptr<ndn::Transport>
+ getLocalNfdTransport();
+
+private:
+ std::string m_configFile;
+ ConfigSection m_configSection;
+
+ ndn::KeyChain& m_keyChain;
+ unique_ptr<ndn::Face> m_face;
+ unique_ptr<RibManager> m_ribManager;
+};
+
+} // namespace rib
+} // namespace nfd
+
+#endif // NFD_RIB_NRD_HPP