daemon: Refactor initialization of NFD instance
Change-Id: Ie4181a0b65e249c7067a11e941dcea77f010e4b1
Refs: #2496
diff --git a/daemon/main.cpp b/daemon/main.cpp
index e275668..aa2d822 100644
--- a/daemon/main.cpp
+++ b/daemon/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,153 +23,39 @@
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <getopt.h>
-#include <boost/filesystem.hpp>
+#include "nfd.hpp"
#include "version.hpp"
-#include "core/logger.hpp"
#include "core/global-io.hpp"
+#include "core/logger.hpp"
#include "core/privilege-helper.hpp"
-#include "fw/forwarder.hpp"
-#include "face/null-face.hpp"
-#include "mgmt/internal-face.hpp"
-#include "mgmt/fib-manager.hpp"
-#include "mgmt/face-manager.hpp"
-#include "mgmt/strategy-choice-manager.hpp"
-#include "mgmt/status-server.hpp"
-#include "core/config-file.hpp"
-#include "mgmt/general-config-section.hpp"
-#include "mgmt/tables-config-section.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 {
NFD_LOG_INIT("NFD");
-struct ProgramOptions
-{
- bool showUsage;
- bool showVersion;
- bool showModules;
- std::string config;
-};
-
-class Nfd : noncopyable
+class NfdRunner
{
public:
explicit
- Nfd(const std::string& configFile)
- : m_configFile(configFile)
- , m_originalStreamBuf(0)
+ NfdRunner(const std::string& configFile)
+ : m_nfd(configFile, m_keyChain)
+ , m_terminationSignalSet(getGlobalIoService())
+ , m_reloadSignalSet(getGlobalIoService())
{
- }
+ m_terminationSignalSet.add(SIGINT);
+ m_terminationSignalSet.add(SIGTERM);
+ m_terminationSignalSet.async_wait(bind(&NfdRunner::terminate, this, _1, _2));
- ~Nfd()
- {
- if (static_cast<bool>(m_originalStreamBuf)) {
- std::clog.rdbuf(m_originalStreamBuf);
- }
- }
-
- void
- initialize()
- {
- initializeLogging();
-
- m_forwarder = make_shared<Forwarder>();
-
- initializeManagement();
-
- m_forwarder->getFaceTable().addReserved(make_shared<NullFace>(), FACEID_NULL);
- m_forwarder->getFaceTable().addReserved(
- make_shared<NullFace>(FaceUri("contentstore://")), FACEID_CONTENT_STORE);
-
- PrivilegeHelper::drop();
- }
-
-
- void
- initializeLogging()
- {
- ConfigFile config(&ConfigFile::ignoreUnknownSection);
- LoggerFactory::getInstance().setConfigFile(config);
-
- config.parse(m_configFile, true);
- config.parse(m_configFile, false);
- }
-
- class IgnoreRibAndLogSections
- {
- public:
- void
- operator()(const std::string& filename,
- const std::string& sectionName,
- const ConfigSection& section,
- bool isDryRun)
-
- {
- // Ignore "log" and sections beginning with "rib_" (intended for rib manager),
- // but raise an error if we're missing a handler for an NFD section.
-
- if (sectionName.find("rib") == 0 || sectionName == "log")
- {
- // do nothing
- }
- else
- {
- // missing NFD section
- ConfigFile::throwErrorOnUnknownSection(filename, sectionName, section, isDryRun);
- }
- }
- };
-
- void
- initializeManagement()
- {
- m_internalFace = make_shared<InternalFace>();
-
- m_fibManager = make_shared<FibManager>(ref(m_forwarder->getFib()),
- bind(&Forwarder::getFace, m_forwarder.get(), _1),
- m_internalFace,
- ndn::ref(m_keyChain));
-
- m_faceManager = make_shared<FaceManager>(ref(m_forwarder->getFaceTable()),
- m_internalFace,
- ndn::ref(m_keyChain));
-
- m_strategyChoiceManager =
- make_shared<StrategyChoiceManager>(ref(m_forwarder->getStrategyChoice()),
- m_internalFace,
- ndn::ref(m_keyChain));
-
- m_statusServer = make_shared<StatusServer>(m_internalFace,
- ref(*m_forwarder),
- ndn::ref(m_keyChain));
-
- ConfigFile config((IgnoreRibAndLogSections()));
- general::setConfigFile(config);
-
- TablesConfigSection tablesConfig(m_forwarder->getCs(),
- m_forwarder->getPit(),
- m_forwarder->getFib(),
- m_forwarder->getStrategyChoice(),
- m_forwarder->getMeasurements());
- tablesConfig.setConfigFile(config);
-
- m_internalFace->getValidator().setConfigFile(config);
-
- m_forwarder->getFaceTable().addReserved(m_internalFace, FACEID_INTERNAL_FACE);
-
- m_faceManager->setConfigFile(config);
-
- // parse config file
- config.parse(m_configFile, true);
- config.parse(m_configFile, false);
-
- tablesConfig.ensureTablesAreConfigured();
-
- // add FIB entry for NFD Management Protocol
- shared_ptr<fib::Entry> entry = m_forwarder->getFib().insert("/localhost/nfd").first;
- entry->addNextHop(m_internalFace, 0);
+ m_reloadSignalSet.add(SIGHUP);
+ m_reloadSignalSet.async_wait(bind(&NfdRunner::reload, this, _1, _2));
}
static void
@@ -192,137 +78,46 @@
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)
+ 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
- {
- signalSet.async_wait(bind(&Nfd::terminate, this, _1, _2, ref(signalSet)));
- }
+ NFD_LOG_INFO("Caught signal '" << ::strsignal(signalNo) << "', exiting...");
+ getGlobalIoService().stop();
}
void
- reload(const boost::system::error_code& error,
- int signalNo,
- boost::asio::signal_set& signalSet)
+ initialize()
+ {
+ m_nfd.initialize();
+ }
+
+ void
+ reload(const boost::system::error_code& error, int signalNo)
{
if (error)
return;
- NFD_LOG_INFO("Caught signal '" << strsignal(signalNo));
+ NFD_LOG_INFO("Caught signal '" << ::strsignal(signalNo) << "', reloading...");
+ m_nfd.reloadConfigFile();
- ////////////////////////
- // Reload config file //
- ////////////////////////
-
- // Logging
- initializeLogging();
- /// \todo Reopen log file
-
- // Other stuff
- ConfigFile config((IgnoreRibAndLogSections()));
-
- general::setConfigFile(config);
-
- TablesConfigSection tablesConfig(m_forwarder->getCs(),
- m_forwarder->getPit(),
- m_forwarder->getFib(),
- m_forwarder->getStrategyChoice(),
- m_forwarder->getMeasurements());
-
- tablesConfig.setConfigFile(config);
-
- m_internalFace->getValidator().setConfigFile(config);
- m_faceManager->setConfigFile(config);
-
- config.parse(m_configFile, false);
-
- ////////////////////////
-
- signalSet.async_wait(bind(&Nfd::reload, this, _1, _2, ref(signalSet)));
+ m_reloadSignalSet.async_wait(bind(&NfdRunner::reload, this, _1, _2));
}
private:
- std::string m_configFile;
-
- shared_ptr<Forwarder> m_forwarder;
-
- shared_ptr<InternalFace> m_internalFace;
- shared_ptr<FibManager> m_fibManager;
- shared_ptr<FaceManager> m_faceManager;
- shared_ptr<StrategyChoiceManager> m_strategyChoiceManager;
- shared_ptr<StatusServer> m_statusServer;
-
- shared_ptr<std::ofstream> m_logFile;
- std::basic_streambuf<char>* m_originalStreamBuf;
- ndn::KeyChain m_keyChain;
+ ndn::KeyChain m_keyChain;
+ Nfd m_nfd;
+ boost::asio::signal_set m_terminationSignalSet;
+ boost::asio::signal_set m_reloadSignalSet;
};
} // namespace nfd
@@ -332,34 +127,50 @@
{
using namespace nfd;
- ProgramOptions options;
- bool isCommandLineValid = Nfd::parseCommandLine(argc, argv, options);
- if (!isCommandLineValid) {
- Nfd::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;
+ NfdRunner::printUsage(std::cerr, argv[0]);
return 1;
}
- if (options.showUsage) {
- Nfd::printUsage(std::cout, argv[0]);
+ if (vm.count("help") > 0) {
+ NfdRunner::printUsage(std::cout, argv[0]);
return 0;
}
- if (options.showVersion) {
+ if (vm.count("version") > 0) {
std::cout << NFD_VERSION_BUILD_STRING << std::endl;
return 0;
}
- if (options.showModules) {
- Nfd::printModules(std::cout);
+ if (vm.count("modules") > 0) {
+ NfdRunner::printModules(std::cout);
return 0;
}
- Nfd nfdInstance(options.config);
+ NfdRunner runner(configFile);
try {
- nfdInstance.initialize();
+ 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");
@@ -381,17 +192,6 @@
return 3;
}
- boost::asio::signal_set terminationSignalSet(getGlobalIoService());
- terminationSignalSet.add(SIGINT);
- terminationSignalSet.add(SIGTERM);
- terminationSignalSet.async_wait(bind(&Nfd::terminate, &nfdInstance, _1, _2,
- ref(terminationSignalSet)));
-
- boost::asio::signal_set reloadSignalSet(getGlobalIoService());
- reloadSignalSet.add(SIGHUP);
- reloadSignalSet.async_wait(bind(&Nfd::reload, &nfdInstance, _1, _2,
- ref(reloadSignalSet)));
-
try {
getGlobalIoService().run();
}
diff --git a/daemon/nfd.cpp b/daemon/nfd.cpp
new file mode 100644
index 0000000..d7a60d7
--- /dev/null
+++ b/daemon/nfd.cpp
@@ -0,0 +1,194 @@
+/* -*- 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 "nfd.hpp"
+
+#include "core/logger-factory.hpp"
+#include "core/privilege-helper.hpp"
+#include "fw/forwarder.hpp"
+#include "face/null-face.hpp"
+#include "mgmt/internal-face.hpp"
+#include "mgmt/fib-manager.hpp"
+#include "mgmt/face-manager.hpp"
+#include "mgmt/strategy-choice-manager.hpp"
+#include "mgmt/status-server.hpp"
+#include "core/config-file.hpp"
+#include "mgmt/general-config-section.hpp"
+#include "mgmt/tables-config-section.hpp"
+
+namespace nfd {
+
+static const std::string INTERNAL_CONFIG = "internal://nfd.conf";
+
+Nfd::Nfd(const std::string& configFile, ndn::KeyChain& keyChain)
+ : m_configFile(configFile)
+ , m_keyChain(keyChain)
+{
+}
+
+Nfd::Nfd(const ConfigSection& config, ndn::KeyChain& keyChain)
+ : m_configSection(config)
+ , m_keyChain(keyChain)
+{
+}
+
+void
+Nfd::initialize()
+{
+ initializeLogging();
+
+ m_forwarder = make_shared<Forwarder>();
+
+ initializeManagement();
+
+ m_forwarder->getFaceTable().addReserved(make_shared<NullFace>(), FACEID_NULL);
+ m_forwarder->getFaceTable().addReserved(make_shared<NullFace>(FaceUri("contentstore://")),
+ FACEID_CONTENT_STORE);
+
+#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
+ PrivilegeHelper::drop();
+#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
+}
+
+void
+Nfd::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);
+ }
+}
+
+
+static inline void
+ignoreRibAndLogSections(const std::string& filename, const std::string& sectionName,
+ const ConfigSection& section, bool isDryRun)
+{
+ // Ignore "log" and "rib" sections, but raise an error if we're missing a
+ // handler for an NFD section.
+ if (sectionName == "rib" || sectionName == "log") {
+ // do nothing
+ }
+ else {
+ // missing NFD section
+ ConfigFile::throwErrorOnUnknownSection(filename, sectionName, section, isDryRun);
+ }
+}
+
+void
+Nfd::initializeManagement()
+{
+ m_internalFace = make_shared<InternalFace>();
+
+ m_fibManager = make_shared<FibManager>(ref(m_forwarder->getFib()),
+ bind(&Forwarder::getFace, m_forwarder.get(), _1),
+ m_internalFace,
+ ndn::ref(m_keyChain));
+
+ m_faceManager = make_shared<FaceManager>(ref(m_forwarder->getFaceTable()),
+ m_internalFace,
+ ndn::ref(m_keyChain));
+
+ m_strategyChoiceManager =
+ make_shared<StrategyChoiceManager>(ref(m_forwarder->getStrategyChoice()),
+ m_internalFace,
+ ndn::ref(m_keyChain));
+
+ m_statusServer = make_shared<StatusServer>(m_internalFace,
+ ref(*m_forwarder),
+ ndn::ref(m_keyChain));
+
+ ConfigFile config(&ignoreRibAndLogSections);
+ general::setConfigFile(config);
+
+ TablesConfigSection tablesConfig(m_forwarder->getCs(),
+ m_forwarder->getPit(),
+ m_forwarder->getFib(),
+ m_forwarder->getStrategyChoice(),
+ m_forwarder->getMeasurements());
+ tablesConfig.setConfigFile(config);
+
+ m_internalFace->getValidator().setConfigFile(config);
+
+ m_forwarder->getFaceTable().addReserved(m_internalFace, FACEID_INTERNAL_FACE);
+
+ m_faceManager->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);
+ }
+
+ tablesConfig.ensureTablesAreConfigured();
+
+ // add FIB entry for NFD Management Protocol
+ shared_ptr<fib::Entry> entry = m_forwarder->getFib().insert("/localhost/nfd").first;
+ entry->addNextHop(m_internalFace, 0);
+}
+
+void
+Nfd::reloadConfigFile()
+{
+ // Logging
+ initializeLogging();
+ /// \todo Reopen log file
+
+ // Other stuff
+ ConfigFile config(&ignoreRibAndLogSections);
+
+ general::setConfigFile(config);
+
+ TablesConfigSection tablesConfig(m_forwarder->getCs(),
+ m_forwarder->getPit(),
+ m_forwarder->getFib(),
+ m_forwarder->getStrategyChoice(),
+ m_forwarder->getMeasurements());
+
+ tablesConfig.setConfigFile(config);
+
+ m_internalFace->getValidator().setConfigFile(config);
+ m_faceManager->setConfigFile(config);
+
+ if (!m_configFile.empty()) {
+ config.parse(m_configFile, false);
+ }
+ else {
+ config.parse(m_configSection, false, INTERNAL_CONFIG);
+ }
+}
+
+} // namespace nfd
diff --git a/daemon/nfd.hpp b/daemon/nfd.hpp
new file mode 100644
index 0000000..f9cac45
--- /dev/null
+++ b/daemon/nfd.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_DAEMON_NFD_HPP
+#define NFD_DAEMON_NFD_HPP
+
+#include "common.hpp"
+#include "core/config-file.hpp"
+
+#include <ndn-cxx/security/key-chain.hpp>
+
+namespace nfd {
+
+class Forwarder;
+class InternalFace;
+class FibManager;
+class FaceManager;
+class StrategyChoiceManager;
+class StatusServer;
+
+/**
+ * \brief Class representing NFD instance
+ * This class can be used to initialize all components of NFD
+ */
+class Nfd : noncopyable
+{
+public:
+ /**
+ * \brief Create NFD instance using absolute or relative path to \p configFile
+ */
+ Nfd(const std::string& configFile, ndn::KeyChain& keyChain);
+
+ /**
+ * \brief Create NFD 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.
+ */
+ Nfd(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();
+
+ /**
+ * \brief Reload configuration file and apply update (if any)
+ */
+ void
+ reloadConfigFile();
+
+private:
+ void
+ initializeLogging();
+
+ void
+ initializeManagement();
+
+private:
+ std::string m_configFile;
+ ConfigSection m_configSection;
+
+ shared_ptr<Forwarder> m_forwarder;
+
+ shared_ptr<InternalFace> m_internalFace;
+ shared_ptr<FibManager> m_fibManager;
+ shared_ptr<FaceManager> m_faceManager;
+ shared_ptr<StrategyChoiceManager> m_strategyChoiceManager;
+ shared_ptr<StatusServer> m_statusServer;
+
+ ndn::KeyChain& m_keyChain;
+};
+
+} // namespace nfd
+
+#endif // NFD_DAEMON_NFD_HPP