tools: Refactoring ndn-autoconfig implementation
Change-Id: Ib92942ba40f04aaee83479177b9ba5d32a09af04
Refs: #2421
diff --git a/tools/ndn-autoconfig/base-dns.cpp b/tools/ndn-autoconfig/base-dns.cpp
new file mode 100644
index 0000000..23e8782
--- /dev/null
+++ b/tools/ndn-autoconfig/base-dns.cpp
@@ -0,0 +1,161 @@
+/* -*- 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 "base-dns.hpp"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <resolv.h>
+#include <arpa/nameser.h>
+
+#ifdef __APPLE__
+#include <arpa/nameser_compat.h>
+#endif
+
+namespace ndn {
+namespace tools {
+namespace autoconfig {
+
+union BaseDns::QueryAnswer
+{
+ HEADER header;
+ uint8_t buf[NS_PACKETSZ];
+};
+
+BaseDns::BaseDns(Face& face, KeyChain& keyChain, const NextStageCallback& nextStageOnFailure)
+ : Base(face, keyChain, nextStageOnFailure)
+{
+}
+
+std::string
+BaseDns::querySrvRr(const std::string& fqdn)
+{
+ std::string srvDomain = "_ndn._udp." + fqdn;
+ std::cerr << "Sending DNS query for SRV record for " << srvDomain << std::endl;
+
+ QueryAnswer queryAnswer;
+ int answerSize = res_query(srvDomain.c_str(),
+ ns_c_in,
+ ns_t_srv,
+ queryAnswer.buf,
+ sizeof(queryAnswer));
+ if (answerSize == 0) {
+ throw Error("No DNS SRV records found for " + srvDomain);
+ }
+ return parseSrvRr(queryAnswer, answerSize);
+}
+
+/**
+ * @brief Send DNS SRV request using search domain list
+ */
+std::string
+BaseDns::querySrvRrSearch()
+{
+ std::cerr << "Sending DNS query for SRV record for _ndn._udp" << std::endl;
+
+ QueryAnswer queryAnswer;
+
+ _res.retry = 2;
+ _res.ndots = 10;
+
+ int answerSize = res_search("_ndn._udp",
+ ns_c_in,
+ ns_t_srv,
+ queryAnswer.buf,
+ sizeof(queryAnswer));
+
+ if (answerSize == 0) {
+ throw Error("No DNS SRV records found for _ndn._udp");
+ }
+
+ return parseSrvRr(queryAnswer, answerSize);
+}
+
+std::string
+BaseDns::parseSrvRr(const QueryAnswer& queryAnswer, int answerSize)
+{
+ // The references of the next classes are:
+ // http://www.diablotin.com/librairie/networking/dnsbind/ch14_02.htm
+
+ struct rechdr
+ {
+ uint16_t type;
+ uint16_t iclass;
+ uint32_t ttl;
+ uint16_t length;
+ };
+
+ struct srv_t
+ {
+ uint16_t priority;
+ uint16_t weight;
+ uint16_t port;
+ uint8_t* target;
+ };
+
+ if (ntohs(queryAnswer.header.ancount) == 0) {
+ throw Error("SRV record cannot be parsed");
+ }
+
+ const uint8_t* blob = queryAnswer.buf + NS_HFIXEDSZ;
+
+ blob += dn_skipname(blob, queryAnswer.buf + answerSize) + NS_QFIXEDSZ;
+
+ char srvName[NS_MAXDNAME];
+ int serverNameSize = dn_expand(queryAnswer.buf, // message pointer
+ queryAnswer.buf + answerSize, // end of message
+ blob, // compressed server name
+ srvName, // expanded server name
+ NS_MAXDNAME);
+ if (serverNameSize <= 0) {
+ throw Error("SRV record cannot be parsed (error decoding domain name)");
+ }
+
+ const srv_t* server = reinterpret_cast<const srv_t*>(&blob[sizeof(rechdr)]);
+ uint16_t convertedPort = be16toh(server->port);
+
+ blob += serverNameSize + NS_HFIXEDSZ + NS_QFIXEDSZ;
+
+ char hostName[NS_MAXDNAME];
+ int hostNameSize = dn_expand(queryAnswer.buf, // message pointer
+ queryAnswer.buf + answerSize, // end of message
+ blob, // compressed host name
+ hostName, // expanded host name
+ NS_MAXDNAME);
+ if (hostNameSize <= 0) {
+ throw Error("SRV record cannot be parsed (error decoding host name)");
+ }
+
+ std::string uri = "udp://";
+ uri.append(hostName);
+ uri.append(":");
+ uri.append(std::to_string(convertedPort));
+
+ return uri;
+}
+
+} // namespace autoconfig
+} // namespace tools
+} // namespace ndn
diff --git a/tools/ndn-autoconfig/base-dns.hpp b/tools/ndn-autoconfig/base-dns.hpp
new file mode 100644
index 0000000..1b881ba
--- /dev/null
+++ b/tools/ndn-autoconfig/base-dns.hpp
@@ -0,0 +1,85 @@
+/* -*- 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_TOOLS_NDN_AUTOCONFIG_BASE_DNS_HPP
+#define NFD_TOOLS_NDN_AUTOCONFIG_BASE_DNS_HPP
+
+#include "base.hpp"
+
+namespace ndn {
+namespace tools {
+namespace autoconfig {
+
+/**
+ * @brief Base class for stages that use DNS-based guessing
+ */
+class BaseDns : public Base
+{
+protected:
+ class Error : public std::runtime_error
+ {
+ public:
+ explicit
+ Error(const std::string& what)
+ : std::runtime_error(what)
+ {
+ }
+ };
+
+ BaseDns(Face& face, KeyChain& keyChain, const NextStageCallback& nextStageOnFailure);
+
+ /**
+ * @brief Send DNS SRV request for a @p fqdn fully qualified domain name
+ * @return FaceUri of the hub from the requested SRV record
+ * @throw Error if query returns nothing or SRV record cannot be parsed
+ */
+ std::string
+ querySrvRr(const std::string& fqdn);
+
+ /**
+ * @brief Send DNS SRV request using search domain list
+ * @return FaceUri of the hub from the requested SRV record
+ * @throw Error if query returns nothing or SRV record cannot be parsed
+ */
+ std::string
+ querySrvRrSearch();
+
+private:
+ union QueryAnswer;
+
+ /**
+ * @brief Parse SRV record
+ * @return FaceUri of the hub from the SRV record
+ * @throw Error if SRV record cannot be parsed
+ */
+ std::string
+ parseSrvRr(const QueryAnswer& queryAnswer, int answerSize);
+};
+
+} // namespace autoconfig
+} // namespace tools
+} // namespace ndn
+
+#endif // NFD_TOOLS_NDN_AUTOCONFIG_BASE_DNS_HPP
diff --git a/tools/ndn-autoconfig/base.cpp b/tools/ndn-autoconfig/base.cpp
new file mode 100644
index 0000000..ed051e1
--- /dev/null
+++ b/tools/ndn-autoconfig/base.cpp
@@ -0,0 +1,119 @@
+/* -*- 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 "base.hpp"
+
+namespace ndn {
+namespace tools {
+namespace autoconfig {
+
+Base::Base(Face& face, KeyChain& keyChain, const NextStageCallback& nextStageOnFailure)
+ : m_face(face)
+ , m_keyChain(keyChain)
+ , m_controller(face, keyChain)
+ , m_nextStageOnFailure(nextStageOnFailure)
+{
+}
+
+void
+Base::connectToHub(const std::string& uri)
+{
+ util::FaceUri faceUri(uri);
+
+ faceUri.canonize(bind(&Base::onCanonizeSuccess, this, _1),
+ bind(&Base::onCanonizeFailure, this, _1),
+ m_face.getIoService(), time::seconds(4));
+
+}
+
+
+void
+Base::onCanonizeSuccess(const util::FaceUri& canonicalUri)
+{
+ std::cerr << "About to connect to: " << canonicalUri.toString() << std::endl;
+
+ m_controller.start<nfd::FaceCreateCommand>(nfd::ControlParameters()
+ .setUri(canonicalUri.toString()),
+ bind(&Base::onHubConnectSuccess, this, _1),
+ bind(&Base::onHubConnectError, this, _1, _2));
+}
+
+void
+Base::onCanonizeFailure(const std::string& reason)
+{
+ std::ostringstream os;
+ os << "FaceUri canonization failed: " << reason;
+ throw Error(os.str());
+}
+
+void
+Base::onHubConnectSuccess(const nfd::ControlParameters& resp)
+{
+ std::cerr << "Successfully created face: " << resp << std::endl;
+
+ static const Name TESTBED_PREFIX = "/ndn";
+ registerPrefix(TESTBED_PREFIX, resp.getFaceId());
+}
+
+void
+Base::onHubConnectError(uint32_t code, const std::string& error)
+{
+ std::ostringstream os;
+ os << "Failed to create face: " << error << " (code: " << code << ")";
+ throw Error(os.str());
+}
+
+void
+Base::registerPrefix(const Name& prefix, uint64_t faceId)
+{
+ // Register a prefix in RIB
+ m_controller.start<nfd::RibRegisterCommand>(nfd::ControlParameters()
+ .setName(prefix)
+ .setFaceId(faceId)
+ .setOrigin(nfd::ROUTE_ORIGIN_AUTOCONF)
+ .setCost(100)
+ .setExpirationPeriod(time::milliseconds::max()),
+ bind(&Base::onPrefixRegistrationSuccess, this, _1),
+ bind(&Base::onPrefixRegistrationError, this, _1, _2));
+}
+
+void
+Base::onPrefixRegistrationSuccess(const nfd::ControlParameters& commandSuccessResult)
+{
+ std::cerr << "Successful in name registration: " << commandSuccessResult << std::endl;
+}
+
+void
+Base::onPrefixRegistrationError(uint32_t code, const std::string& error)
+{
+ std::ostringstream os;
+ os << "Failed in name registration, " << error << " (code: " << code << ")";
+ throw Error(os.str());
+}
+
+
+} // namespace autoconfig
+} // namespace tools
+} // namespace ndn
diff --git a/tools/ndn-autoconfig/base.hpp b/tools/ndn-autoconfig/base.hpp
new file mode 100644
index 0000000..bf195c6
--- /dev/null
+++ b/tools/ndn-autoconfig/base.hpp
@@ -0,0 +1,120 @@
+/* -*- 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_TOOLS_NDN_AUTOCONFIG_BASE_HPP
+#define NFD_TOOLS_NDN_AUTOCONFIG_BASE_HPP
+
+#include "common.hpp"
+
+#include <boost/noncopyable.hpp>
+
+#include <ndn-cxx/face.hpp>
+#include <ndn-cxx/security/key-chain.hpp>
+#include <ndn-cxx/management/nfd-controller.hpp>
+#include <ndn-cxx/management/nfd-face-status.hpp>
+#include <ndn-cxx/encoding/buffer-stream.hpp>
+#include <ndn-cxx/util/face-uri.hpp>
+
+namespace ndn {
+namespace tools {
+namespace autoconfig {
+
+/**
+ * @brief Base class for discovery stages
+ */
+class Base : boost::noncopyable
+{
+public:
+ class Error : public std::runtime_error
+ {
+ public:
+ explicit
+ Error(const std::string& what)
+ : std::runtime_error(what)
+ {
+ }
+ };
+
+ /**
+ * @brief Callback to be called when the stage fails
+ */
+ typedef std::function<void(const std::string&)> NextStageCallback;
+
+ /**
+ * @brief Start the stage
+ */
+ virtual void
+ start() = 0;
+
+protected:
+ /**
+ * @brief Initialize variables and create nfd::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
+ */
+ Base(Face& face, KeyChain& keyChain, const NextStageCallback& nextStageOnFailure);
+
+ /**
+ * @brief Attempt to connect to local hub using the \p uri FaceUri
+ * @throw Base::Error when failed to establish the tunnel
+ */
+ void
+ connectToHub(const std::string& uri);
+
+private:
+ void
+ onCanonizeSuccess(const util::FaceUri& canonicalUri);
+
+ void
+ onCanonizeFailure(const std::string& reason);
+
+ void
+ onHubConnectSuccess(const nfd::ControlParameters& resp);
+
+ void
+ onHubConnectError(uint32_t code, const std::string& error);
+
+ void
+ registerPrefix(const Name& prefix, uint64_t faceId);
+
+ void
+ onPrefixRegistrationSuccess(const nfd::ControlParameters& commandSuccessResult);
+
+ void
+ onPrefixRegistrationError(uint32_t code, const std::string& error);
+
+protected:
+ Face& m_face;
+ KeyChain& m_keyChain;
+ nfd::Controller m_controller;
+ NextStageCallback m_nextStageOnFailure;
+};
+
+} // namespace autoconfig
+} // namespace tools
+} // namespace ndn
+
+#endif // NFD_TOOLS_NDN_AUTOCONFIG_BASE_HPP
diff --git a/tools/ndn-autoconfig/guess-from-identity-name.cpp b/tools/ndn-autoconfig/guess-from-identity-name.cpp
new file mode 100644
index 0000000..5a6df3e
--- /dev/null
+++ b/tools/ndn-autoconfig/guess-from-identity-name.cpp
@@ -0,0 +1,63 @@
+/* -*- 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 "guess-from-identity-name.hpp"
+
+namespace ndn {
+namespace tools {
+namespace autoconfig {
+
+GuessFromIdentityName::GuessFromIdentityName(Face& face, KeyChain& keyChain,
+ const NextStageCallback& nextStageOnFailure)
+ : BaseDns(face, keyChain, nextStageOnFailure)
+{
+}
+
+void
+GuessFromIdentityName::start()
+{
+ std::cerr << "Trying to find home router based on the default identity name..." << std::endl;
+
+ Name identity = m_keyChain.getDefaultIdentity();
+
+ std::ostringstream serverName;
+ for (auto i = identity.rbegin(); i != identity.rend(); ++i) {
+ serverName << i->toUri() << ".";
+ }
+ serverName << "_homehub._autoconf.named-data.net";
+
+ try {
+ std::string hubUri = BaseDns::querySrvRr(serverName.str());
+ this->connectToHub(hubUri);
+ }
+ catch (const BaseDns::Error& e) {
+ m_nextStageOnFailure(std::string("Failed to find a home router based on the default identity "
+ "name (") + e.what() + ")");
+ }
+}
+
+} // namespace autoconfig
+} // namespace tools
+} // namespace ndn
diff --git a/tools/ndn-autoconfig/guess-from-identity-name.hpp b/tools/ndn-autoconfig/guess-from-identity-name.hpp
new file mode 100644
index 0000000..3e0008f
--- /dev/null
+++ b/tools/ndn-autoconfig/guess-from-identity-name.hpp
@@ -0,0 +1,74 @@
+/* -*- 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_TOOLS_NDN_AUTOCONFIG_GUESS_FROM_IDENTITY_NAME_HPP
+#define NFD_TOOLS_NDN_AUTOCONFIG_GUESS_FROM_IDENTITY_NAME_HPP
+
+#include "base-dns.hpp"
+
+namespace ndn {
+namespace tools {
+namespace autoconfig {
+
+/**
+ * @brief Guessing home router based on the default identity name
+ *
+ * This stage assumes that user has configured default certificate using
+ * http://ndncert.named-data.net/
+ *
+ * - Request
+ *
+ * The end host loads the default user identity (eg. /ndn/edu/ucla/cs/afanasev), and
+ * converts it to DNS format.
+ *
+ * The end host sends a DNS query for an SRV record of name _ndn._udp. + user identity in
+ * DNS format + _homehub._auto-conf.named-data.net. For example:
+ *
+ * _ndn._udp.afanasev.cs.ucla.edu.ndn._homehub._autoconf.named-data.net
+ *
+ * - Response
+ *
+ * The DNS server should answer with an SRV record that contains the hostname and UDP port
+ * number of the home NDN router of this user's site.
+ */
+class GuessFromIdentityName : public BaseDns
+{
+public:
+ /**
+ * @brief Create stage to guess home router based on the default identity name
+ * @sa Base::Base
+ */
+ GuessFromIdentityName(Face& face, KeyChain& keyChain,
+ const NextStageCallback& nextStageOnFailure);
+
+ virtual void
+ start() DECL_OVERRIDE;
+};
+
+} // namespace autoconfig
+} // namespace tools
+} // namespace ndn
+
+#endif // NFD_TOOLS_NDN_AUTOCONFIG_GUESSING_FROM_IDENTITY_NAME_HPP
diff --git a/tools/ndn-autoconfig/guess-from-search-domains.cpp b/tools/ndn-autoconfig/guess-from-search-domains.cpp
new file mode 100644
index 0000000..2f452e7
--- /dev/null
+++ b/tools/ndn-autoconfig/guess-from-search-domains.cpp
@@ -0,0 +1,53 @@
+/* -*- 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 "guess-from-search-domains.hpp"
+
+namespace ndn {
+namespace tools {
+namespace autoconfig {
+
+GuessFromSearchDomains::GuessFromSearchDomains(Face& face, KeyChain& keyChain,
+ const NextStageCallback& nextStageOnFailure)
+ : BaseDns(face, keyChain, nextStageOnFailure)
+{
+}
+
+void
+GuessFromSearchDomains::start()
+{
+ try {
+ std::string hubUri = BaseDns::querySrvRrSearch();
+ this->connectToHub(hubUri);
+ }
+ catch (const BaseDns::Error& e) {
+ m_nextStageOnFailure(std::string("Failed to find NDN router using default suffix DNS query (") +
+ e.what() + ")");
+ }
+}
+
+} // namespace autoconfig
+} // namespace tools
+} // namespace ndn
diff --git a/tools/ndn-autoconfig/guess-from-search-domains.hpp b/tools/ndn-autoconfig/guess-from-search-domains.hpp
new file mode 100644
index 0000000..e2eaa5a
--- /dev/null
+++ b/tools/ndn-autoconfig/guess-from-search-domains.hpp
@@ -0,0 +1,67 @@
+/* -*- 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_TOOLS_NDN_AUTOCONFIG_GUESS_FROM_SEARCH_DOMAINS_HPP
+#define NFD_TOOLS_NDN_AUTOCONFIG_GUESS_FROM_SEARCH_DOMAINS_HPP
+
+#include "base-dns.hpp"
+
+namespace ndn {
+namespace tools {
+namespace autoconfig {
+
+/**
+ * @brief Guessing home router based on DNS query with default suffix
+ *
+ * - Request
+ *
+ * The end host sends a DNS query that is equivalent to this command:
+ *
+ * dig +search +short +cmd +tries=2 +ndots=10 _ndn._udp srv
+ *
+ * - Response
+ *
+ * The DNS server should answer with an SRV record that contains the hostname and UDP port
+ * number of the NDN router.
+ */
+class GuessFromSearchDomains : public BaseDns
+{
+public:
+ /**
+ * @brief Create stage to guess home router based on DNS query with default suffix
+ * @sa Base::Base
+ */
+ GuessFromSearchDomains(Face& face, KeyChain& keyChain,
+ const NextStageCallback& nextStageOnFailure);
+
+ virtual void
+ start() DECL_OVERRIDE;
+};
+
+} // namespace autoconfig
+} // namespace tools
+} // namespace ndn
+
+#endif // NFD_TOOLS_NDN_AUTOCONFIG_GUESSING_FROM_SEARCH_DOMAINS_HPP
diff --git a/tools/ndn-autoconfig/main.cpp b/tools/ndn-autoconfig/main.cpp
new file mode 100644
index 0000000..d604c9d
--- /dev/null
+++ b/tools/ndn-autoconfig/main.cpp
@@ -0,0 +1,126 @@
+/* -*- 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 "version.hpp"
+
+#include "multicast-discovery.hpp"
+#include "guess-from-search-domains.hpp"
+#include "guess-from-identity-name.hpp"
+
+#include <boost/noncopyable.hpp>
+
+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)
+ {
+ }
+ };
+
+ NdnAutoconfig()
+ : 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;
+ throw Error("No more stages, automatic discovery failed");
+ })
+ {
+ m_stage1.start();
+ }
+
+ void
+ run()
+ {
+ m_face.processEvents();
+ }
+
+ static void
+ usage(const char* programName)
+ {
+ std::cout << "Usage:\n"
+ << " " << programName << " [options]\n"
+ << "\n"
+ << "Options:\n"
+ << " [-h] - print usage and exit\n"
+ << " [-V] - print version number and exit\n"
+ << std::endl;
+ }
+
+private:
+ Face m_face;
+ KeyChain m_keyChain;
+
+ autoconfig::MulticastDiscovery m_stage1;
+ autoconfig::GuessFromSearchDomains m_stage2;
+ autoconfig::GuessFromIdentityName m_stage3;
+};
+
+} // namespace tools
+} // namespace ndn
+
+int
+main(int argc, char** argv)
+{
+ int opt;
+ const char* programName = argv[0];
+
+ while ((opt = getopt(argc, argv, "hV")) != -1) {
+ switch (opt) {
+ case 'h':
+ ndn::tools::NdnAutoconfig::usage(programName);
+ return 0;
+ case 'V':
+ std::cout << NFD_VERSION_BUILD_STRING << std::endl;
+ return 0;
+ }
+ }
+
+ try {
+ ndn::tools::NdnAutoconfig autoConfigInstance;
+ autoConfigInstance.run();
+ }
+ catch (const std::exception& error) {
+ std::cerr << "ERROR: " << error.what() << std::endl;
+ return 1;
+ }
+ return 0;
+}
diff --git a/tools/ndn-autoconfig/multicast-discovery.cpp b/tools/ndn-autoconfig/multicast-discovery.cpp
new file mode 100644
index 0000000..59db21f
--- /dev/null
+++ b/tools/ndn-autoconfig/multicast-discovery.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 "multicast-discovery.hpp"
+
+#include <ndn-cxx/util/segment-fetcher.hpp>
+
+namespace ndn {
+namespace tools {
+namespace autoconfig {
+
+static const Name LOCALHOP_HUB_DISCOVERY_PREFIX = "/localhop/ndn-autoconf/hub";
+
+MulticastDiscovery::MulticastDiscovery(Face& face, KeyChain& keyChain,
+ const NextStageCallback& nextStageOnFailure)
+ : Base(face, keyChain, nextStageOnFailure)
+ , nRequestedRegs(0)
+ , nFinishedRegs(0)
+{
+}
+
+void
+MulticastDiscovery::start()
+{
+ std::cerr << "Trying multicast discovery..." << std::endl;
+
+ util::SegmentFetcher::fetch(m_face, Interest("/localhost/nfd/faces/list"),
+ ndn::util::DontVerifySegment(),
+ [this] (const ConstBufferPtr& data) {
+ registerHubDiscoveryPrefix(data);
+ },
+ [this] (uint32_t code, const std::string& msg) {
+ m_nextStageOnFailure(msg);
+ });
+}
+
+void
+MulticastDiscovery::registerHubDiscoveryPrefix(const ConstBufferPtr& buffer)
+{
+ std::vector<uint64_t> multicastFaces;
+
+ size_t offset = 0;
+ while (offset < buffer->size()) {
+ Block block;
+ bool ok = Block::fromBuffer(buffer, offset, block);
+ if (!ok)
+ {
+ std::cerr << "ERROR: cannot decode FaceStatus TLV" << std::endl;
+ break;
+ }
+
+ offset += block.size();
+
+ nfd::FaceStatus faceStatus(block);
+
+ ndn::util::FaceUri uri(faceStatus.getRemoteUri());
+ if (uri.getScheme() == "udp4") {
+ namespace ip = boost::asio::ip;
+ boost::system::error_code ec;
+ ip::address address = ip::address::from_string(uri.getHost(), ec);
+
+ if (!ec && address.is_multicast()) {
+ multicastFaces.push_back(faceStatus.getFaceId());
+ }
+ else
+ continue;
+ }
+ }
+
+ if (multicastFaces.empty()) {
+ m_nextStageOnFailure("No multicast faces available, skipping multicast discovery stage");
+ }
+ else {
+ nfd::ControlParameters parameters;
+ parameters
+ .setName(LOCALHOP_HUB_DISCOVERY_PREFIX)
+ .setCost(1)
+ .setExpirationPeriod(time::seconds(30));
+
+ nRequestedRegs = multicastFaces.size();
+ nFinishedRegs = 0;
+
+ for (const auto& face : multicastFaces) {
+ parameters.setFaceId(face);
+ m_controller.start<nfd::RibRegisterCommand>(parameters,
+ bind(&MulticastDiscovery::onRegisterSuccess,
+ this),
+ bind(&MulticastDiscovery::onRegisterFailure,
+ this, _1, _2));
+ }
+ }
+}
+
+void
+MulticastDiscovery::onRegisterSuccess()
+{
+ ++nFinishedRegs;
+
+ if (nRequestedRegs == nFinishedRegs) {
+ MulticastDiscovery::setStrategy();
+ }
+}
+
+void
+MulticastDiscovery::onRegisterFailure(uint32_t code, const std::string& error)
+{
+ std::cerr << "ERROR: " << error << " (code: " << code << ")" << std::endl;
+ --nRequestedRegs;
+
+ if (nRequestedRegs == nFinishedRegs) {
+ if (nRequestedRegs > 0) {
+ MulticastDiscovery::setStrategy();
+ } else {
+ m_nextStageOnFailure("Failed to register " + LOCALHOP_HUB_DISCOVERY_PREFIX.toUri() +
+ " for all multicast faces, skipping multicast discovery stage");
+ }
+ }
+}
+
+void
+MulticastDiscovery::setStrategy()
+{
+ nfd::ControlParameters parameters;
+ parameters
+ .setName(LOCALHOP_HUB_DISCOVERY_PREFIX)
+ .setStrategy("/localhost/nfd/strategy/broadcast");
+
+ m_controller.start<nfd::StrategyChoiceSetCommand>(parameters,
+ bind(&MulticastDiscovery::requestHubData, this),
+ bind(&MulticastDiscovery::onSetStrategyFailure,
+ this, _2));
+}
+
+void
+MulticastDiscovery::onSetStrategyFailure(const std::string& error)
+{
+ m_nextStageOnFailure("Failed to set broadcast strategy for " +
+ LOCALHOP_HUB_DISCOVERY_PREFIX.toUri() + " namespace (" + error + "). "
+ "Skipping multicast discovery stage");
+}
+
+void
+MulticastDiscovery::requestHubData()
+{
+ Interest interest(LOCALHOP_HUB_DISCOVERY_PREFIX);
+ interest.setInterestLifetime(time::milliseconds(4000)); // 4 seconds
+ interest.setMustBeFresh(true);
+
+ m_face.expressInterest(interest,
+ bind(&MulticastDiscovery::onSuccess, this, _2),
+ bind(m_nextStageOnFailure, "Timeout"));
+}
+
+void
+MulticastDiscovery::onSuccess(Data& data)
+{
+ const Block& content = data.getContent();
+ content.parse();
+
+ // 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");
+ return;
+ }
+ std::string hubUri(reinterpret_cast<const char*>(blockValue->value()), blockValue->value_size());
+ this->connectToHub(hubUri);
+}
+
+} // namespace autoconfig
+} // namespace tools
+} // namespace ndn
diff --git a/tools/ndn-autoconfig/multicast-discovery.hpp b/tools/ndn-autoconfig/multicast-discovery.hpp
new file mode 100644
index 0000000..72717fc
--- /dev/null
+++ b/tools/ndn-autoconfig/multicast-discovery.hpp
@@ -0,0 +1,94 @@
+/* -*- 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_TOOLS_NDN_AUTOCONFIG_MULTICAST_DISCOVERY_HPP
+#define NFD_TOOLS_NDN_AUTOCONFIG_MULTICAST_DISCOVERY_HPP
+
+#include "base.hpp"
+
+namespace ndn {
+namespace tools {
+namespace autoconfig {
+
+/**
+ * @brief Multicast discovery stage
+ *
+ * - Request
+ *
+ * The end host sends an Interest over a multicast face.
+ *
+ * Interest Name is /localhop/ndn-autoconf/hub.
+ *
+ * - Response
+ *
+ * A producer app on the HUB answer this Interest with a Data packet that contains a
+ * TLV-encoded Uri block. The value of this block is the URI for the HUB, preferably a
+ * UDP tunnel.
+ */
+class MulticastDiscovery : public Base
+{
+public:
+ /**
+ * @brief Create multicast discovery stage
+ * @sa Base::Base
+ */
+ MulticastDiscovery(Face& face, KeyChain& keyChain, const NextStageCallback& nextStageOnFailure);
+
+ virtual void
+ start() DECL_OVERRIDE;
+
+private:
+ void
+ registerHubDiscoveryPrefix(const ConstBufferPtr& buffer);
+
+ void
+ onRegisterSuccess();
+
+ void
+ onRegisterFailure(uint32_t code, const std::string& error);
+
+ void
+ setStrategy();
+
+ void
+ onSetStrategyFailure(const std::string& error);
+
+ // Start to look for a hub (NDN hub discovery first stage)
+ void
+ requestHubData();
+
+ void
+ onSuccess(Data& data);
+
+private:
+ size_t nRequestedRegs;
+ size_t nFinishedRegs;
+};
+
+} // namespace autoconfig
+} // namespace tools
+} // namespace ndn
+
+#endif // NFD_TOOLS_NDN_AUTOCONFIG_MULTICAST_DISCOVERY_HPP