/* -*- 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 . */ #include #include #include "version.hpp" #include "core/logger.hpp" #include "core/global-io.hpp" #include "core/privilege-helper.hpp" #include "fw/forwarder.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 { NFD_LOG_INIT("NFD"); struct ProgramOptions { bool showUsage; bool showVersion; bool showModules; std::string config; }; class Nfd : noncopyable { public: explicit Nfd(const std::string& configFile) : m_configFile(configFile) , m_originalStreamBuf(0) { } ~Nfd() { if (static_cast(m_originalStreamBuf)) { std::clog.rdbuf(m_originalStreamBuf); } } void initialize() { initializeLogging(); m_forwarder = make_shared(); initializeManagement(); 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(); m_fibManager = make_shared(ref(m_forwarder->getFib()), bind(&Forwarder::getFace, m_forwarder.get(), _1), m_internalFace); m_faceManager = make_shared(ref(m_forwarder->getFaceTable()), m_internalFace); m_strategyChoiceManager = make_shared(ref(m_forwarder->getStrategyChoice()), m_internalFace); m_statusServer = make_shared(m_internalFace, ref(*m_forwarder)); 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->addFace(m_internalFace); m_faceManager->setConfigFile(config); // parse config file config.parse(m_configFile, true); config.parse(m_configFile, false); // add FIB entry for NFD Management Protocol shared_ptr entry = m_forwarder->getFib().insert("/localhost/nfd").first; entry->addNextHop(m_internalFace, 0); } static void printUsage(std::ostream& os, const std::string& programName) { os << "Usage: \n" << " " << programName << " [options]\n" << "\n" << "Run NFD forwarding daemon\n" << "\n" << "Options:\n" << " [--help] - print this help message\n" << " [--version] - print version and exit\n" << " [--modules] - list available logging modules\n" << " [--config /path/to/nfd.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 modules(LoggerFactory::getInstance().getModules()); for (list::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; } } 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) { getGlobalIoService().stop(); NFD_LOG_INFO("Caught signal '" << strsignal(signalNo) << "', exiting..."); } else { signalSet.async_wait(bind(&Nfd::terminate, this, _1, _2, ref(signalSet))); } } void reload(const boost::system::error_code& error, int signalNo, boost::asio::signal_set& signalSet) { if (error) return; NFD_LOG_INFO("Caught signal '" << strsignal(signalNo)); //////////////////////// // 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))); } private: std::string m_configFile; shared_ptr m_forwarder; shared_ptr m_internalFace; shared_ptr m_fibManager; shared_ptr m_faceManager; shared_ptr m_strategyChoiceManager; shared_ptr m_statusServer; shared_ptr m_logFile; std::basic_streambuf* m_originalStreamBuf; }; } // namespace nfd int main(int argc, char** argv) { using namespace nfd; ProgramOptions options; bool isCommandLineValid = Nfd::parseCommandLine(argc, argv, options); if (!isCommandLineValid) { Nfd::printUsage(std::cerr, argv[0]); return 1; } if (options.showUsage) { Nfd::printUsage(std::cout, argv[0]); return 0; } if (options.showVersion) { std::cout << NFD_VERSION_BUILD_STRING << std::endl; return 0; } if (options.showModules) { Nfd::printModules(std::cout); return 0; } Nfd nfdInstance(options.config); try { nfdInstance.initialize(); } 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; } catch (const PrivilegeHelper::Error& e) { // PrivilegeHelper::Errors do not inherit from std::exception // and represent seteuid/gid failures NFD_LOG_FATAL(e.what()); 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(); } catch (const std::exception& e) { NFD_LOG_FATAL(e.what()); return 4; } catch (const PrivilegeHelper::Error& e) { NFD_LOG_FATAL(e.what()); return 5; } return 0; }