/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /** * Copyright (c) 2014-2016, 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 "core/version.hpp" #include "multicast-discovery.hpp" #include "guess-from-search-domains.hpp" #include "guess-from-identity-name.hpp" #include #include #include #include #include #include #include namespace po = boost::program_options; namespace ndn { namespace tools { class NdnAutoconfig : boost::noncopyable { public: class Error : public std::runtime_error { public: explicit Error(const std::string& what) : std::runtime_error(what) { } }; explicit NdnAutoconfig(bool isDaemonMode) : m_face(m_io) , m_scheduler(m_io) , m_startStagesEvent(m_scheduler) , m_isDaemonMode(isDaemonMode) , m_terminationSignalSet(m_io) , m_stage1(m_face, m_keyChain, [&] (const std::string& errorMessage) { std::cerr << "Stage 1 failed: " << errorMessage << std::endl; m_stage2.start(); }) , m_stage2(m_face, m_keyChain, [&] (const std::string& errorMessage) { std::cerr << "Stage 2 failed: " << errorMessage << std::endl; m_stage3.start(); }) , m_stage3(m_face, m_keyChain, [&] (const std::string& errorMessage) { std::cerr << "Stage 3 failed: " << errorMessage << std::endl; if (!m_isDaemonMode) BOOST_THROW_EXCEPTION(Error("No more stages, automatic discovery failed")); else std::cerr << "No more stages, automatic discovery failed" << std::endl; }) { if (m_isDaemonMode) { m_networkMonitor.reset(new util::NetworkMonitor(m_io)); m_networkMonitor->onNetworkStateChanged.connect([this] { // delay stages, so if multiple events are triggered in short sequence, // only one auto-detection procedure is triggered m_startStagesEvent = m_scheduler.scheduleEvent(time::seconds(5), bind(&NdnAutoconfig::startStages, this)); }); } // Delay a little bit m_startStagesEvent = m_scheduler.scheduleEvent(time::milliseconds(100), bind(&NdnAutoconfig::startStages, this)); } void run() { if (m_isDaemonMode) { m_terminationSignalSet.add(SIGINT); m_terminationSignalSet.add(SIGTERM); m_terminationSignalSet.async_wait(bind(&NdnAutoconfig::terminate, this, _1, _2)); } m_io.run(); } void terminate(const boost::system::error_code& error, int signalNo) { if (error) return; m_io.stop(); } static void usage(std::ostream& os, const po::options_description& optionDescription, const char* programName) { os << "Usage:\n" << " " << programName << " [options]\n" << "\n"; os << optionDescription; } private: void startStages() { m_stage1.start(); if (m_isDaemonMode) { m_startStagesEvent = m_scheduler.scheduleEvent(time::hours(1), bind(&NdnAutoconfig::startStages, this)); } } private: boost::asio::io_service m_io; Face m_face; KeyChain m_keyChain; unique_ptr m_networkMonitor; util::Scheduler m_scheduler; util::scheduler::ScopedEventId m_startStagesEvent; bool m_isDaemonMode; boost::asio::signal_set m_terminationSignalSet; autoconfig::MulticastDiscovery m_stage1; autoconfig::GuessFromSearchDomains m_stage2; autoconfig::GuessFromIdentityName m_stage3; }; } // namespace tools } // namespace ndn int main(int argc, char** argv) { bool isDaemonMode = false; std::string configFile; po::options_description optionDescription("Options"); optionDescription.add_options() ("help,h", "produce help message") ("daemon,d", po::bool_switch(&isDaemonMode)->default_value(isDaemonMode), "run in daemon mode, detecting network change events and re-running " "auto-discovery procedure. In addition, the auto-discovery procedure " "is unconditionally re-run every hour.\n" "NOTE: if connection to NFD fails, the daemon will be terminated.") ("config,c", po::value(&configFile), "configuration file. If `enabled = true` " "is not specified, no actions will be performed.") ("version,V", "show version and exit") ; po::variables_map options; try { po::store(po::parse_command_line(argc, argv, optionDescription), options); po::notify(options); } catch (const std::exception& e) { std::cerr << "ERROR: " << e.what() << "\n" << std::endl; ndn::tools::NdnAutoconfig::usage(std::cerr, optionDescription, argv[0]); return 1; } if (options.count("help")) { ndn::tools::NdnAutoconfig::usage(std::cout, optionDescription, argv[0]); return 0; } if (options.count("version")) { std::cout << NFD_VERSION_BUILD_STRING << std::endl; return 0; } // Enable (one-shot or daemon mode whenever config file is not specified) bool isEnabled = true; po::options_description configFileOptions; configFileOptions.add_options() ("enabled", po::value(&isEnabled)) ; if (!configFile.empty()) { isEnabled = false; // Disable by default if config file is specified try { po::store(po::parse_config_file(configFile.c_str(), configFileOptions), options); po::notify(options); } catch (const std::exception& e) { std::cerr << "ERROR: " << e.what() << std::endl << std::endl; return 1; } } if (!isEnabled) { return 0; } try { ndn::tools::NdnAutoconfig autoConfigInstance(isDaemonMode); autoConfigInstance.run(); } catch (const std::exception& error) { std::cerr << "ERROR: " << error.what() << std::endl; return 1; } return 0; }