tools: refactor ndn-autoconfig
Hub face creation and prefix registrations are moved into a new
Procedure class. Main function is simplified.
refs #4158
Change-Id: I15b660e3b8a1bde89498a1cb549a87788de46c7a
diff --git a/tools/ndn-autoconfig/guess-from-identity-name.cpp b/tools/ndn-autoconfig/guess-from-identity-name.cpp
index c26ec81..8ef112d 100644
--- a/tools/ndn-autoconfig/guess-from-identity-name.cpp
+++ b/tools/ndn-autoconfig/guess-from-identity-name.cpp
@@ -32,14 +32,13 @@
namespace tools {
namespace autoconfig {
-GuessFromIdentityName::GuessFromIdentityName(Face& face, KeyChain& keyChain,
- const NextStageCallback& nextStageOnFailure)
- : Stage(face, keyChain, nextStageOnFailure)
+GuessFromIdentityName::GuessFromIdentityName(KeyChain& keyChain)
+ : m_keyChain(keyChain)
{
}
void
-GuessFromIdentityName::start()
+GuessFromIdentityName::doStart()
{
std::cerr << "Trying default identity name..." << std::endl;
@@ -53,11 +52,10 @@
try {
std::string hubUri = querySrvRr(serverName.str());
- this->connectToHub(hubUri);
+ this->provideHubFaceUri(hubUri);
}
catch (const DnsSrvError& e) {
- m_nextStageOnFailure(std::string("Failed to find a home router based on the default identity "
- "name (") + e.what() + ")");
+ this->fail(e.what());
}
}
diff --git a/tools/ndn-autoconfig/guess-from-identity-name.hpp b/tools/ndn-autoconfig/guess-from-identity-name.hpp
index 315e856..9da9093 100644
--- a/tools/ndn-autoconfig/guess-from-identity-name.hpp
+++ b/tools/ndn-autoconfig/guess-from-identity-name.hpp
@@ -27,6 +27,7 @@
#define NFD_TOOLS_NDN_AUTOCONFIG_GUESS_FROM_IDENTITY_NAME_HPP
#include "stage.hpp"
+#include <ndn-cxx/security/key-chain.hpp>
namespace ndn {
namespace tools {
@@ -56,14 +57,22 @@
class GuessFromIdentityName : public Stage
{
public:
- /**
- * @brief Create stage to guess home router based on the default identity name
- */
- GuessFromIdentityName(Face& face, KeyChain& keyChain,
- const NextStageCallback& nextStageOnFailure);
+ explicit
+ GuessFromIdentityName(KeyChain& keyChain);
+ const std::string&
+ getName() const override
+ {
+ static const std::string STAGE_NAME("guess from identity name");
+ return STAGE_NAME;
+ }
+
+private:
void
- start() override;
+ doStart() override;
+
+private:
+ KeyChain& m_keyChain;
};
} // namespace autoconfig
diff --git a/tools/ndn-autoconfig/guess-from-search-domains.cpp b/tools/ndn-autoconfig/guess-from-search-domains.cpp
index f53c4fc..2f92cc3 100644
--- a/tools/ndn-autoconfig/guess-from-search-domains.cpp
+++ b/tools/ndn-autoconfig/guess-from-search-domains.cpp
@@ -30,24 +30,15 @@
namespace tools {
namespace autoconfig {
-GuessFromSearchDomains::GuessFromSearchDomains(Face& face, KeyChain& keyChain,
- const NextStageCallback& nextStageOnFailure)
- : Stage(face, keyChain, nextStageOnFailure)
-{
-}
-
void
-GuessFromSearchDomains::start()
+GuessFromSearchDomains::doStart()
{
- std::cerr << "Trying default suffix DNS query..." << std::endl;
-
try {
std::string hubUri = querySrvRrSearch();
- this->connectToHub(hubUri);
+ this->provideHubFaceUri(hubUri);
}
catch (const DnsSrvError& e) {
- m_nextStageOnFailure(std::string("Failed to find NDN router using default suffix DNS query (") +
- e.what() + ")");
+ this->fail(e.what());
}
}
diff --git a/tools/ndn-autoconfig/guess-from-search-domains.hpp b/tools/ndn-autoconfig/guess-from-search-domains.hpp
index a2670ec..9bd6521 100644
--- a/tools/ndn-autoconfig/guess-from-search-domains.hpp
+++ b/tools/ndn-autoconfig/guess-from-search-domains.hpp
@@ -49,14 +49,16 @@
class GuessFromSearchDomains : public Stage
{
public:
- /**
- * @brief Create stage to guess home router based on DNS query with default suffix
- */
- GuessFromSearchDomains(Face& face, KeyChain& keyChain,
- const NextStageCallback& nextStageOnFailure);
+ const std::string&
+ getName() const override
+ {
+ static const std::string STAGE_NAME("guess from search domains");
+ return STAGE_NAME;
+ }
+private:
void
- start() override;
+ doStart() override;
};
} // namespace autoconfig
diff --git a/tools/ndn-autoconfig/main.cpp b/tools/ndn-autoconfig/main.cpp
index db45610..fad4933 100644
--- a/tools/ndn-autoconfig/main.cpp
+++ b/tools/ndn-autoconfig/main.cpp
@@ -1,5 +1,5 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
@@ -23,23 +23,20 @@
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "procedure.hpp"
+#include "core/extended-error-message.hpp"
+#include "core/scheduler.hpp"
#include "core/version.hpp"
-#include "multicast-discovery.hpp"
-#include "guess-from-search-domains.hpp"
-#include "ndn-fch-discovery.hpp"
-#include "guess-from-identity-name.hpp"
-
-#include <ndn-cxx/net/network-monitor.hpp>
-#include <ndn-cxx/util/scheduler.hpp>
-#include <ndn-cxx/util/scheduler-scoped-event-id.hpp>
-
-#include <boost/noncopyable.hpp>
+#include <signal.h>
+#include <string.h>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>
-
-namespace po = boost::program_options;
+#include <ndn-cxx/net/network-monitor.hpp>
+#include <ndn-cxx/util/scheduler.hpp>
+#include <ndn-cxx/util/scheduler-scoped-event-id.hpp>
+#include <ndn-cxx/util/time.hpp>
namespace ndn {
namespace tools {
@@ -47,201 +44,144 @@
// ndn-autoconfig is an NDN tool not an NFD tool, so it uses ndn::tools::autoconfig namespace.
// It lives in NFD repository because nfd-start can automatically start ndn-autoconfig in daemon mode.
-class NdnAutoconfig : boost::noncopyable
+static const time::nanoseconds DAEMON_INITIAL_DELAY = time::milliseconds(100);
+static const time::nanoseconds DAEMON_UNCONDITIONAL_INTERVAL = time::hours(1);
+static const time::nanoseconds NETMON_DAMPEN_PERIOD = time::seconds(5);
+
+namespace po = boost::program_options;
+
+static void
+usage(std::ostream& os,
+ const po::options_description& optionsDescription,
+ const char* programName)
{
-public:
- class Error : public std::runtime_error
- {
- public:
- explicit
- Error(const std::string& what)
- : std::runtime_error(what)
- {
+ os << "Usage:\n"
+ << " " << programName << " [options]\n"
+ << "\n";
+ os << optionsDescription;
+}
+
+static void
+runDaemon(Procedure& proc)
+{
+ boost::asio::signal_set terminateSignals(proc.getIoService());
+ terminateSignals.add(SIGINT);
+ terminateSignals.add(SIGTERM);
+ terminateSignals.async_wait([&] (const boost::system::error_code& error, int signalNo) {
+ if (error) {
+ return;
}
+ const char* signalName = ::strsignal(signalNo);
+ std::cerr << "Exit on signal ";
+ if (signalName == nullptr) {
+ std::cerr << signalNo;
+ }
+ else {
+ std::cerr << signalName;
+ }
+ std::cerr << std::endl;
+ proc.getIoService().stop();
+ });
+
+ util::Scheduler sched(proc.getIoService());
+ util::scheduler::ScopedEventId runEvt(sched);
+ auto scheduleRerun = [&] (time::nanoseconds delay) {
+ runEvt = sched.scheduleEvent(delay, [&] { proc.runOnce(); });
};
- explicit
- NdnAutoconfig(const std::string& ndnFchUrl, 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,
- ndnFchUrl,
- [&] (const std::string& errorMessage) {
- std::cerr << "Stage 3 failed: " << errorMessage << std::endl;
- m_stage4.start();
- })
- , m_stage4(m_face, m_keyChain,
- [&] (const std::string& errorMessage) {
- std::cerr << "Stage 4 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 net::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));
- });
- }
+ proc.onComplete.connect([&] (bool isSuccess) {
+ scheduleRerun(DAEMON_UNCONDITIONAL_INTERVAL);
+ });
- // Delay a little bit
- m_startStagesEvent = m_scheduler.scheduleEvent(time::milliseconds(100),
- bind(&NdnAutoconfig::startStages, this));
- }
+ net::NetworkMonitor netmon(proc.getIoService());
+ netmon.onNetworkStateChanged.connect([&] { scheduleRerun(NETMON_DAMPEN_PERIOD); });
- 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<net::NetworkMonitor> m_networkMonitor;
- util::Scheduler m_scheduler;
- util::scheduler::ScopedEventId m_startStagesEvent;
- bool m_isDaemonMode;
- boost::asio::signal_set m_terminationSignalSet;
-
- MulticastDiscovery m_stage1;
- GuessFromSearchDomains m_stage2;
- NdnFchDiscovery m_stage3;
- GuessFromIdentityName m_stage4;
-};
+ scheduleRerun(DAEMON_INITIAL_DELAY);
+ proc.getIoService().run();
+}
static int
main(int argc, char** argv)
{
- bool isDaemonMode = false;
+ Options options;
+ bool isDaemon = false;
std::string configFile;
- std::string ndnFchUrl;
- 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"
+ po::options_description optionsDescription("Options");
+ optionsDescription.add_options()
+ ("help,h", "print this message and exit")
+ ("version,V", "display version and exit")
+ ("daemon,d", po::bool_switch(&isDaemon)->default_value(isDaemon),
+ "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.")
- ("ndn-fch-url", po::value<std::string>(&ndnFchUrl)->default_value("http://ndn-fch.named-data.net"),
+ ("ndn-fch-url", po::value<std::string>(&options.ndnFchUrl)->default_value(options.ndnFchUrl),
"URL for NDN-FCH (Find Closest Hub) service")
- ("config,c", po::value<std::string>(&configFile), "configuration file. If `enabled = true` "
- "is not specified, no actions will be performed.")
- ("version,V", "show version and exit")
+ ("config,c", po::value<std::string>(&configFile),
+ "configuration file. Exit immediately if `enabled = true` is not specified in config file.")
;
- po::variables_map options;
+ po::variables_map vm;
try {
- po::store(po::parse_command_line(argc, argv, optionDescription), options);
- po::notify(options);
+ po::store(po::parse_command_line(argc, argv, optionsDescription), vm);
+ po::notify(vm);
}
catch (const std::exception& e) {
- std::cerr << "ERROR: " << e.what() << "\n" << std::endl;
- NdnAutoconfig::usage(std::cerr, optionDescription, argv[0]);
- return 1;
+ std::cerr << "ERROR: " << e.what() << "\n" << "\n\n";
+ usage(std::cerr, optionsDescription, argv[0]);
+ return 2;
}
- if (options.count("help")) {
- NdnAutoconfig::usage(std::cout, optionDescription, argv[0]);
+ if (vm.count("help")) {
+ usage(std::cout, optionsDescription, argv[0]);
return 0;
}
- if (options.count("version")) {
+ if (vm.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<bool>(&isEnabled))
- ;
-
- if (!configFile.empty()) {
- isEnabled = false; // Disable by default if config file is specified
+ if (vm.count("config")) {
+ po::options_description configFileOptions;
+ configFileOptions.add_options()
+ ("enabled", po::value<bool>()->default_value(false))
+ ;
try {
- po::store(po::parse_config_file<char>(configFile.c_str(), configFileOptions), options);
- po::notify(options);
+ po::store(po::parse_config_file<char>(configFile.data(), configFileOptions), vm);
+ po::notify(vm);
}
catch (const std::exception& e) {
- std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
- return 1;
+ std::cerr << "ERROR in config: " << e.what() << "\n\n";
+ return 2;
+ }
+ if (!vm["enabled"].as<bool>()) {
+ // not enabled in config
+ return 0;
}
}
- if (!isEnabled) {
- return 0;
- }
-
+ int exitCode = 0;
try {
- NdnAutoconfig autoConfigInstance(ndnFchUrl, isDaemonMode);
- autoConfigInstance.run();
+ Face face;
+ KeyChain keyChain;
+ Procedure proc(face, keyChain);
+ proc.initialize(options);
+
+ if (isDaemon) {
+ runDaemon(proc);
+ }
+ else {
+ proc.onComplete.connect([&exitCode] (bool isSuccess) { exitCode = isSuccess ? 0 : 3; });
+ proc.runOnce();
+ face.processEvents();
+ }
}
- catch (const std::exception& error) {
- std::cerr << "ERROR: " << error.what() << std::endl;
+ catch (const std::exception& e) {
+ std::cerr << ::nfd::getExtendedErrorMessage(e) << std::endl;
return 1;
}
- return 0;
+ return exitCode;
}
} // namespace autoconfig
diff --git a/tools/ndn-autoconfig/multicast-discovery.cpp b/tools/ndn-autoconfig/multicast-discovery.cpp
index 6692bc2..f9b4797 100644
--- a/tools/ndn-autoconfig/multicast-discovery.cpp
+++ b/tools/ndn-autoconfig/multicast-discovery.cpp
@@ -33,46 +33,44 @@
static const Name LOCALHOP_HUB_DISCOVERY_PREFIX = "/localhop/ndn-autoconf/hub";
-MulticastDiscovery::MulticastDiscovery(Face& face, KeyChain& keyChain,
- const NextStageCallback& nextStageOnFailure)
- : Stage(face, keyChain, nextStageOnFailure)
+MulticastDiscovery::MulticastDiscovery(Face& face, nfd::Controller& controller)
+ : m_face(face)
+ , m_controller(controller)
, m_nRequestedRegs(0)
, m_nFinishedRegs(0)
{
}
void
-MulticastDiscovery::start()
+MulticastDiscovery::doStart()
{
- std::cerr << "Trying multicast discovery..." << std::endl;
-
this->collectMulticastFaces();
}
void
MulticastDiscovery::collectMulticastFaces()
{
- ndn::nfd::FaceQueryFilter filter;
- filter.setLinkType(ndn::nfd::LINK_TYPE_MULTI_ACCESS);
- m_controller.fetch<ndn::nfd::FaceQueryDataset>(
+ nfd::FaceQueryFilter filter;
+ filter.setLinkType(nfd::LINK_TYPE_MULTI_ACCESS);
+ m_controller.fetch<nfd::FaceQueryDataset>(
filter,
bind(&MulticastDiscovery::registerHubDiscoveryPrefix, this, _1),
- bind(m_nextStageOnFailure, _2)
+ bind(&MulticastDiscovery::fail, this, _2)
);
}
void
-MulticastDiscovery::registerHubDiscoveryPrefix(const std::vector<ndn::nfd::FaceStatus>& dataset)
+MulticastDiscovery::registerHubDiscoveryPrefix(const std::vector<nfd::FaceStatus>& dataset)
{
std::vector<uint64_t> multicastFaces;
std::transform(dataset.begin(), dataset.end(), std::back_inserter(multicastFaces),
- [] (const ndn::nfd::FaceStatus& faceStatus) { return faceStatus.getFaceId(); });
+ [] (const nfd::FaceStatus& faceStatus) { return faceStatus.getFaceId(); });
if (multicastFaces.empty()) {
- m_nextStageOnFailure("No multicast faces available, skipping multicast discovery stage");
+ this->fail("No multicast faces available, skipping multicast discovery stage");
}
else {
- ControlParameters parameters;
+ nfd::ControlParameters parameters;
parameters
.setName(LOCALHOP_HUB_DISCOVERY_PREFIX)
.setCost(1)
@@ -83,7 +81,7 @@
for (const auto& face : multicastFaces) {
parameters.setFaceId(face);
- m_controller.start<ndn::nfd::RibRegisterCommand>(
+ m_controller.start<nfd::RibRegisterCommand>(
parameters,
bind(&MulticastDiscovery::onRegisterSuccess, this),
bind(&MulticastDiscovery::onRegisterFailure, this, _1));
@@ -102,7 +100,7 @@
}
void
-MulticastDiscovery::onRegisterFailure(const ControlResponse& response)
+MulticastDiscovery::onRegisterFailure(const nfd::ControlResponse& response)
{
std::cerr << "ERROR: " << response.getText() << " (code: " << response.getCode() << ")" << std::endl;
--m_nRequestedRegs;
@@ -112,8 +110,8 @@
MulticastDiscovery::setStrategy();
}
else {
- m_nextStageOnFailure("Failed to register " + LOCALHOP_HUB_DISCOVERY_PREFIX.toUri() +
- " for all multicast faces, skipping multicast discovery stage");
+ this->fail("Failed to register " + LOCALHOP_HUB_DISCOVERY_PREFIX.toUri() +
+ " for all multicast faces, skipping multicast discovery stage");
}
}
}
@@ -121,23 +119,23 @@
void
MulticastDiscovery::setStrategy()
{
- ControlParameters parameters;
+ nfd::ControlParameters parameters;
parameters
.setName(LOCALHOP_HUB_DISCOVERY_PREFIX)
.setStrategy("/localhost/nfd/strategy/multicast");
- m_controller.start<ndn::nfd::StrategyChoiceSetCommand>(
+ m_controller.start<nfd::StrategyChoiceSetCommand>(
parameters,
bind(&MulticastDiscovery::requestHubData, this),
bind(&MulticastDiscovery::onSetStrategyFailure, this, _1));
}
void
-MulticastDiscovery::onSetStrategyFailure(const ControlResponse& response)
+MulticastDiscovery::onSetStrategyFailure(const nfd::ControlResponse& response)
{
- m_nextStageOnFailure("Failed to set multicast strategy for " +
- LOCALHOP_HUB_DISCOVERY_PREFIX.toUri() + " namespace (" + response.getText() + "). "
- "Skipping multicast discovery stage");
+ this->fail("Failed to set multicast strategy for " +
+ LOCALHOP_HUB_DISCOVERY_PREFIX.toUri() + " namespace (" + response.getText() + "). "
+ "Skipping multicast discovery stage");
}
void
@@ -149,8 +147,8 @@
m_face.expressInterest(interest,
bind(&MulticastDiscovery::onSuccess, this, _2),
- bind(m_nextStageOnFailure, "HUB Data not received: nacked"),
- bind(m_nextStageOnFailure, "HUB Data not received: timeout"));
+ bind(&MulticastDiscovery::fail, this, "HUB Data not received: nacked"),
+ bind(&MulticastDiscovery::fail, this, "HUB Data not received: timeout"));
}
void
@@ -162,11 +160,10 @@
// Get Uri
Block::element_const_iterator blockValue = content.find(tlv::nfd::Uri);
if (blockValue == content.elements_end()) {
- m_nextStageOnFailure("Incorrect reply to multicast discovery stage");
+ this->fail("Incorrect reply to multicast discovery stage");
return;
}
- std::string hubUri(reinterpret_cast<const char*>(blockValue->value()), blockValue->value_size());
- this->connectToHub(hubUri);
+ this->provideHubFaceUri(std::string(reinterpret_cast<const char*>(blockValue->value()), blockValue->value_size()));
}
} // namespace autoconfig
diff --git a/tools/ndn-autoconfig/multicast-discovery.hpp b/tools/ndn-autoconfig/multicast-discovery.hpp
index 1a10d89..d714306 100644
--- a/tools/ndn-autoconfig/multicast-discovery.hpp
+++ b/tools/ndn-autoconfig/multicast-discovery.hpp
@@ -27,6 +27,9 @@
#define NFD_TOOLS_NDN_AUTOCONFIG_MULTICAST_DISCOVERY_HPP
#include "stage.hpp"
+#include <ndn-cxx/face.hpp>
+#include <ndn-cxx/mgmt/nfd/controller.hpp>
+#include <ndn-cxx/mgmt/nfd/face-status.hpp>
namespace ndn {
namespace tools {
@@ -53,29 +56,36 @@
/**
* @brief Create multicast discovery stage
*/
- MulticastDiscovery(Face& face, KeyChain& keyChain, const NextStageCallback& nextStageOnFailure);
+ MulticastDiscovery(Face& face, nfd::Controller& controller);
- void
- start() override;
+ const std::string&
+ getName() const override
+ {
+ static const std::string STAGE_NAME("multicast discovery");
+ return STAGE_NAME;
+ }
private:
void
+ doStart() override;
+
+ void
collectMulticastFaces();
void
- registerHubDiscoveryPrefix(const std::vector<ndn::nfd::FaceStatus>& dataset);
+ registerHubDiscoveryPrefix(const std::vector<nfd::FaceStatus>& dataset);
void
onRegisterSuccess();
void
- onRegisterFailure(const ControlResponse& response);
+ onRegisterFailure(const nfd::ControlResponse& response);
void
setStrategy();
void
- onSetStrategyFailure(const ControlResponse& response);
+ onSetStrategyFailure(const nfd::ControlResponse& response);
// Start to look for a hub (NDN hub discovery first stage)
void
@@ -85,6 +95,8 @@
onSuccess(const Data& data);
private:
+ Face& m_face;
+ nfd::Controller& m_controller;
size_t m_nRequestedRegs;
size_t m_nFinishedRegs;
};
diff --git a/tools/ndn-autoconfig/ndn-fch-discovery.cpp b/tools/ndn-autoconfig/ndn-fch-discovery.cpp
index 6f043a3..01c169e 100644
--- a/tools/ndn-autoconfig/ndn-fch-discovery.cpp
+++ b/tools/ndn-autoconfig/ndn-fch-discovery.cpp
@@ -132,19 +132,14 @@
}
};
-NdnFchDiscovery::NdnFchDiscovery(Face& face, KeyChain& keyChain,
- const std::string& url,
- const NextStageCallback& nextStageOnFailure)
- : Stage(face, keyChain, nextStageOnFailure)
- , m_url(url)
+NdnFchDiscovery::NdnFchDiscovery(const std::string& url)
+ : m_url(url)
{
}
void
-NdnFchDiscovery::start()
+NdnFchDiscovery::doStart()
{
- std::cerr << "Trying NDN-FCH service..." << std::endl;
-
try {
using namespace boost::asio::ip;
tcp::iostream requestStream;
@@ -205,10 +200,10 @@
BOOST_THROW_EXCEPTION(HttpException("NDN-FCH did not return hub host"));
}
- this->connectToHub("udp://" + hubHost);
+ this->provideHubFaceUri("udp://" + hubHost);
}
catch (const std::runtime_error& e) {
- m_nextStageOnFailure(std::string("Failed to find NDN router using NDN-FCH service (") + e.what() + ")");
+ this->fail(e.what());
}
}
diff --git a/tools/ndn-autoconfig/ndn-fch-discovery.hpp b/tools/ndn-autoconfig/ndn-fch-discovery.hpp
index 2b8de07..000568d 100644
--- a/tools/ndn-autoconfig/ndn-fch-discovery.hpp
+++ b/tools/ndn-autoconfig/ndn-fch-discovery.hpp
@@ -43,12 +43,19 @@
/**
* @brief Create stage to discover NDN hub using NDN-FCH protocol
*/
- NdnFchDiscovery(Face& face, KeyChain& keyChain,
- const std::string& url,
- const NextStageCallback& nextStageOnFailure);
+ explicit
+ NdnFchDiscovery(const std::string& url);
+ const std::string&
+ getName() const override
+ {
+ static const std::string STAGE_NAME("NDN-FCH");
+ return STAGE_NAME;
+ }
+
+private:
void
- start() override;
+ doStart() override;
private:
std::string m_url;
diff --git a/tools/ndn-autoconfig/procedure.cpp b/tools/ndn-autoconfig/procedure.cpp
new file mode 100644
index 0000000..042ac17
--- /dev/null
+++ b/tools/ndn-autoconfig/procedure.cpp
@@ -0,0 +1,143 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2017, 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 "procedure.hpp"
+#include "guess-from-identity-name.hpp"
+#include "guess-from-search-domains.hpp"
+#include "multicast-discovery.hpp"
+#include "ndn-fch-discovery.hpp"
+
+namespace ndn {
+namespace tools {
+namespace autoconfig {
+
+using nfd::ControlParameters;
+using nfd::ControlResponse;
+
+static const time::nanoseconds FACEURI_CANONIZE_TIMEOUT = time::seconds(4);
+static const std::vector<Name> HUB_PREFIXES{"/ndn", "/localhop/nfd"};
+static const nfd::RouteOrigin HUB_ROUTE_ORIGIN = nfd::ROUTE_ORIGIN_AUTOCONF;
+static const uint64_t HUB_ROUTE_COST = 100;
+
+Procedure::Procedure(Face& face, KeyChain& keyChain)
+ : m_face(face)
+ , m_keyChain(keyChain)
+ , m_controller(face, keyChain)
+{
+}
+
+void
+Procedure::initialize(const Options& options)
+{
+ BOOST_ASSERT(m_stages.empty());
+ this->makeStages(options);
+ BOOST_ASSERT(!m_stages.empty());
+
+ for (size_t i = 0; i < m_stages.size(); ++i) {
+ m_stages[i]->onSuccess.connect(bind(&Procedure::connect, this, _1));
+ if (i + 1 < m_stages.size()) {
+ m_stages[i]->onFailure.connect([=] (const std::string&) { m_stages[i + 1]->start(); });
+ }
+ else {
+ m_stages[i]->onFailure.connect([=] (const std::string&) { this->onComplete(false); });
+ }
+ }
+}
+
+void
+Procedure::makeStages(const Options& options)
+{
+ m_stages.push_back(make_unique<MulticastDiscovery>(m_face, m_controller));
+ m_stages.push_back(make_unique<GuessFromSearchDomains>());
+ m_stages.push_back(make_unique<NdnFchDiscovery>(options.ndnFchUrl));
+ m_stages.push_back(make_unique<GuessFromIdentityName>(m_keyChain));
+}
+
+void
+Procedure::runOnce()
+{
+ BOOST_ASSERT(!m_stages.empty());
+ m_stages.front()->start();
+}
+
+void
+Procedure::connect(const FaceUri& hubFaceUri)
+{
+ hubFaceUri.canonize(
+ [this] (const FaceUri& canonicalUri) {
+ m_controller.start<nfd::FaceCreateCommand>(
+ ControlParameters().setUri(canonicalUri.toString()),
+ [this] (const ControlParameters& params) {
+ std::cerr << "Connected to HUB " << params.getUri() << std::endl;
+ this->registerPrefixes(params.getFaceId());
+ },
+ [this, canonicalUri] (const ControlResponse& resp) {
+ if (resp.getCode() == 409) {
+ ControlParameters params(resp.getBody());
+ std::cerr << "Already connected to HUB " << params.getUri() << std::endl;
+ this->registerPrefixes(params.getFaceId());
+ }
+ else {
+ std::cerr << "Failed to connect to HUB " << canonicalUri << ": "
+ << resp.getText() << " (" << resp.getCode() << ")" << std::endl;
+ this->onComplete(false);
+ }
+ });
+ },
+ [this] (const std::string& reason) {
+ std::cerr << "Failed to canonize HUB FaceUri: " << reason << std::endl;
+ this->onComplete(false);
+ },
+ m_face.getIoService(), FACEURI_CANONIZE_TIMEOUT);
+}
+
+void
+Procedure::registerPrefixes(uint64_t hubFaceId, size_t index)
+{
+ if (index >= HUB_PREFIXES.size()) {
+ this->onComplete(true);
+ return;
+ }
+
+ m_controller.start<nfd::RibRegisterCommand>(
+ ControlParameters()
+ .setName(HUB_PREFIXES[index])
+ .setFaceId(hubFaceId)
+ .setOrigin(HUB_ROUTE_ORIGIN)
+ .setCost(HUB_ROUTE_COST),
+ [=] (const ControlParameters&) {
+ std::cerr << "Registered prefix " << HUB_PREFIXES[index] << std::endl;
+ this->registerPrefixes(hubFaceId, index + 1);
+ },
+ [=] (const ControlResponse& resp) {
+ std::cerr << "Failed to register " << HUB_PREFIXES[index] << ": "
+ << resp.getText() << " (" << resp.getCode() << ")" << std::endl;
+ this->onComplete(false);
+ });
+}
+
+} // namespace autoconfig
+} // namespace tools
+} // namespace ndn
diff --git a/tools/ndn-autoconfig/procedure.hpp b/tools/ndn-autoconfig/procedure.hpp
new file mode 100644
index 0000000..0f65b89
--- /dev/null
+++ b/tools/ndn-autoconfig/procedure.hpp
@@ -0,0 +1,92 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2017, 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_TOOLS_NDN_AUTOCONFIG_PROCEDURE_HPP
+#define NFD_TOOLS_NDN_AUTOCONFIG_PROCEDURE_HPP
+
+#include "stage.hpp"
+#include <ndn-cxx/face.hpp>
+#include <ndn-cxx/mgmt/nfd/controller.hpp>
+#include <ndn-cxx/security/key-chain.hpp>
+
+namespace ndn {
+namespace tools {
+namespace autoconfig {
+
+struct Options
+{
+ std::string ndnFchUrl = "http://ndn-fch.named-data.net"; ///< HTTP base URL of NDN-FCH service
+};
+
+class Procedure : noncopyable
+{
+public:
+ Procedure(Face& face, KeyChain& keyChain);
+
+ void
+ initialize(const Options& options);
+
+ /** \brief run HUB discovery procedure once
+ */
+ void
+ runOnce();
+
+ boost::asio::io_service&
+ getIoService()
+ {
+ return m_face.getIoService();
+ }
+
+private:
+ VIRTUAL_WITH_TESTS void
+ makeStages(const Options& options);
+
+ void
+ connect(const FaceUri& hubFaceUri);
+
+ void
+ registerPrefixes(uint64_t hubFaceId, size_t index = 0);
+
+public:
+ /** \brief signal when procedure completes
+ *
+ * Argument indicates whether the procedure succeeds (true) or fails (false).
+ */
+ util::Signal<Procedure, bool> onComplete;
+
+PROTECTED_WITH_TESTS_ELSE_PRIVATE:
+ std::vector<unique_ptr<Stage>> m_stages;
+
+private:
+ Face& m_face;
+ KeyChain& m_keyChain;
+ nfd::Controller m_controller;
+};
+
+} // namespace autoconfig
+} // namespace tools
+} // namespace ndn
+
+#endif // NFD_TOOLS_NDN_AUTOCONFIG_PROCEDURE_HPP
diff --git a/tools/ndn-autoconfig/stage.cpp b/tools/ndn-autoconfig/stage.cpp
index dbad283..2e1e048 100644
--- a/tools/ndn-autoconfig/stage.cpp
+++ b/tools/ndn-autoconfig/stage.cpp
@@ -29,106 +29,46 @@
namespace tools {
namespace autoconfig {
-Stage::Stage(Face& face, KeyChain& keyChain, const NextStageCallback& nextStageOnFailure)
- : m_face(face)
- , m_keyChain(keyChain)
- , m_controller(face, keyChain)
- , m_nextStageOnFailure(nextStageOnFailure)
-{
-}
-
void
-Stage::connectToHub(const std::string& uri)
+Stage::start()
{
- FaceUri faceUri(uri);
- std::cerr << "About to connect to: " << uri << std::endl;
-
- faceUri.canonize(bind(&Stage::onCanonizeSuccess, this, _1),
- bind(&Stage::onCanonizeFailure, this, _1),
- m_face.getIoService(), time::seconds(4));
-
-}
-
-
-void
-Stage::onCanonizeSuccess(const FaceUri& canonicalUri)
-{
- m_controller.start<ndn::nfd::FaceCreateCommand>(
- ControlParameters().setUri(canonicalUri.toString()),
- bind(&Stage::onHubConnectSuccess, this, _1),
- bind(&Stage::onHubConnectError, this, _1));
-}
-
-void
-Stage::onCanonizeFailure(const std::string& reason)
-{
- BOOST_THROW_EXCEPTION(Error("FaceUri canonization failed: " + reason));
-}
-
-void
-Stage::onHubConnectSuccess(const ControlParameters& resp)
-{
- std::cerr << "Successfully created face: " << resp << std::endl;
-
- registerAutoConfigNames(resp.getFaceId());
-}
-
-void
-Stage::onHubConnectError(const ControlResponse& response)
-{
- // If face exists, continue proceeding with the existing face
- if (response.getCode() == 409) {
- std::cerr << "Face exists. Proceeding with existing face: " << ControlParameters(response.getBody()) << std::endl;
-
- registerAutoConfigNames(ControlParameters(response.getBody()).getFaceId());
+ if (m_isInProgress) {
+ BOOST_THROW_EXCEPTION(Error("Cannot start a stage when it's in progress"));
}
- // Otherwise, report the failure and throw out exception
+ m_isInProgress = true;
+
+ std::cerr << "Starting " << this->getName() << " stage" << std::endl;
+ this->doStart();
+}
+
+void
+Stage::provideHubFaceUri(const std::string& s)
+{
+ FaceUri u;
+ if (u.parse(s)) {
+ this->succeed(u);
+ }
else {
- std::ostringstream os;
- os << "Failed to create face: " << response.getText() << " (code: " << response.getCode() << ")";
- BOOST_THROW_EXCEPTION(Error(os.str()));
+ this->fail("Cannot parse FaceUri: " + s);
}
}
void
-Stage::registerAutoConfigNames(uint64_t faceId)
+Stage::succeed(const FaceUri& hubFaceUri)
{
- static const Name TESTBED_PREFIX = "/ndn";
- registerPrefix(TESTBED_PREFIX, faceId);
-
- static const Name LOCALHOP_NFD_PREFIX = "/localhop/nfd";
- registerPrefix(LOCALHOP_NFD_PREFIX, faceId);
+ std::cerr << "Stage " << this->getName() << " succeeded with " << hubFaceUri << std::endl;
+ this->onSuccess(hubFaceUri);
+ m_isInProgress = false;
}
void
-Stage::registerPrefix(const Name& prefix, uint64_t faceId)
+Stage::fail(const std::string& msg)
{
- // Register a prefix in RIB
- m_controller.start<ndn::nfd::RibRegisterCommand>(
- ControlParameters()
- .setName(prefix)
- .setFaceId(faceId)
- .setOrigin(ndn::nfd::ROUTE_ORIGIN_AUTOCONF)
- .setCost(100)
- .setExpirationPeriod(time::milliseconds::max()),
- bind(&Stage::onPrefixRegistrationSuccess, this, _1),
- bind(&Stage::onPrefixRegistrationError, this, _1));
+ std::cerr << "Stage " << this->getName() << " failed: " << msg << std::endl;
+ this->onFailure(msg);
+ m_isInProgress = false;
}
-void
-Stage::onPrefixRegistrationSuccess(const ControlParameters& commandSuccessResult)
-{
- std::cerr << "Successful in name registration: " << commandSuccessResult << std::endl;
-}
-
-void
-Stage::onPrefixRegistrationError(const ControlResponse& response)
-{
- BOOST_THROW_EXCEPTION(Error("Failed in name registration, " + response.getText() +
- " (code: " + to_string(response.getCode()) + ")"));
-}
-
-
} // namespace autoconfig
} // namespace tools
} // namespace ndn
diff --git a/tools/ndn-autoconfig/stage.hpp b/tools/ndn-autoconfig/stage.hpp
index 2c63280..015153d 100644
--- a/tools/ndn-autoconfig/stage.hpp
+++ b/tools/ndn-autoconfig/stage.hpp
@@ -27,22 +27,14 @@
#define NFD_TOOLS_NDN_AUTOCONFIG_STAGE_HPP
#include "core/common.hpp"
-
-#include <ndn-cxx/face.hpp>
-#include <ndn-cxx/mgmt/nfd/controller.hpp>
-#include <ndn-cxx/mgmt/nfd/face-status.hpp>
#include <ndn-cxx/net/face-uri.hpp>
-#include <ndn-cxx/security/key-chain.hpp>
+#include <ndn-cxx/util/signal.hpp>
namespace ndn {
namespace tools {
namespace autoconfig {
-using ndn::nfd::ControlParameters;
-using ndn::nfd::ControlResponse;
-
-/**
- * @brief Base class for discovery stages
+/** \brief a discovery stage
*/
class Stage : boost::noncopyable
{
@@ -57,63 +49,51 @@
}
};
- /**
- * @brief Callback to be called when the stage fails
- */
- typedef std::function<void(const std::string&)> NextStageCallback;
+ virtual ~Stage() = default;
- /**
- * @brief Start the stage
+ /** \brief get stage name
+ * \return stage name as a phrase, typically starting with lower case
*/
- virtual void
- start() = 0;
+ virtual const std::string&
+ getName() const = 0;
-protected:
- /**
- * @brief Initialize variables and create Controller instance
- * @param face Face to be used for all operations (e.g., will send registration commands)
- * @param keyChain KeyChain object
- * @param nextStageOnFailure Callback to be called after the stage failed
- */
- Stage(Face& face, KeyChain& keyChain, const NextStageCallback& nextStageOnFailure);
-
- /**
- * @brief Attempt to connect to local hub using the \p uri FaceUri
- * @throw Error when failed to establish the tunnel
+ /** \brief start running this stage
+ * \throw Error stage is already running
*/
void
- connectToHub(const std::string& uri);
+ start();
+
+protected:
+ /** \brief parse HUB FaceUri from string and declare success
+ */
+ void
+ provideHubFaceUri(const std::string& s);
+
+ void
+ succeed(const FaceUri& hubFaceUri);
+
+ void
+ fail(const std::string& msg);
private:
- void
- onCanonizeSuccess(const FaceUri& canonicalUri);
+ virtual void
+ doStart() = 0;
- void
- onCanonizeFailure(const std::string& reason);
+public:
+ /** \brief signal when a HUB FaceUri is found
+ *
+ * Argument is HUB FaceUri, may not be canonical.
+ */
+ util::Signal<Stage, FaceUri> onSuccess;
- void
- onHubConnectSuccess(const ControlParameters& resp);
+ /** \brief signal when discovery fails
+ *
+ * Argument is error message.
+ */
+ util::Signal<Stage, std::string> onFailure;
- void
- onHubConnectError(const ControlResponse& response);
-
- void
- registerAutoConfigNames(uint64_t faceId);
-
- void
- registerPrefix(const Name& prefix, uint64_t faceId);
-
- void
- onPrefixRegistrationSuccess(const ControlParameters& commandSuccessResult);
-
- void
- onPrefixRegistrationError(const ControlResponse& response);
-
-protected:
- Face& m_face;
- KeyChain& m_keyChain;
- ndn::nfd::Controller m_controller;
- NextStageCallback m_nextStageOnFailure;
+private:
+ bool m_isInProgress = false;
};
} // namespace autoconfig