tools: Refactoring ndn-autoconfig implementation
Change-Id: Ib92942ba40f04aaee83479177b9ba5d32a09af04 Refs: #2421
This commit is contained in:
1 parent
262203b644
commit
2a655f70a1
12 files changed
+1156
-537
No files matched your search
@@ -1,537 +0,0 @@
|
||||
/* -*- 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 <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/security/key-chain.hpp>
|
||||
#include <ndn-cxx/encoding/buffer-stream.hpp>
|
||||
#include <ndn-cxx/util/face-uri.hpp>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/nameser.h>
|
||||
#include <resolv.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <arpa/nameser_compat.h>
|
||||
#endif
|
||||
|
||||
namespace ndn {
|
||||
namespace tools {
|
||||
|
||||
static const Name LOCALHOP_HUB_DISCOVERY_PREFIX = "/localhop/ndn-autoconf/hub";
|
||||
|
||||
void
|
||||
usage(const char* programName)
|
||||
{
|
||||
std::cout << "Usage:\n" << programName << " [-h] [-V]\n"
|
||||
<< " -h - print usage and exit\n"
|
||||
<< " -V - print version number and exit\n"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
class NdnAutoconfig : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
union QueryAnswer
|
||||
{
|
||||
HEADER header;
|
||||
uint8_t buf[NS_PACKETSZ];
|
||||
};
|
||||
|
||||
class Error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
Error(const std::string& what)
|
||||
: std::runtime_error(what)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
explicit
|
||||
NdnAutoconfig()
|
||||
: m_controller(m_face, m_keyChain)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
run()
|
||||
{
|
||||
m_face.processEvents();
|
||||
}
|
||||
|
||||
void
|
||||
fetchSegments(const Data& data, const shared_ptr<OBufferStream>& buffer,
|
||||
void (NdnAutoconfig::*onDone)(const shared_ptr<OBufferStream>&))
|
||||
{
|
||||
buffer->write(reinterpret_cast<const char*>(data.getContent().value()),
|
||||
data.getContent().value_size());
|
||||
|
||||
uint64_t currentSegment = data.getName().get(-1).toSegment();
|
||||
|
||||
const name::Component& finalBlockId = data.getMetaInfo().getFinalBlockId();
|
||||
if (finalBlockId.empty() ||
|
||||
finalBlockId.toSegment() > currentSegment)
|
||||
{
|
||||
m_face.expressInterest(data.getName().getPrefix(-1).appendSegment(currentSegment+1),
|
||||
ndn::bind(&NdnAutoconfig::fetchSegments, this, _2, buffer, onDone),
|
||||
ndn::bind(&NdnAutoconfig::discoverHubStage2, this, "Timeout"));
|
||||
}
|
||||
else
|
||||
{
|
||||
return (this->*onDone)(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
discoverHubStage1()
|
||||
{
|
||||
shared_ptr<OBufferStream> buffer = make_shared<OBufferStream>();
|
||||
|
||||
Interest interest("/localhost/nfd/faces/list");
|
||||
interest.setChildSelector(1);
|
||||
interest.setMustBeFresh(true);
|
||||
|
||||
m_face.expressInterest(interest,
|
||||
ndn::bind(&NdnAutoconfig::fetchSegments, this, _2, buffer,
|
||||
&NdnAutoconfig::discoverHubStage1_registerHubDiscoveryPrefix),
|
||||
ndn::bind(&NdnAutoconfig::discoverHubStage2, this, "Timeout"));
|
||||
}
|
||||
|
||||
void
|
||||
discoverHubStage1_registerHubDiscoveryPrefix(const shared_ptr<OBufferStream>& buffer)
|
||||
{
|
||||
ConstBufferPtr buf = buffer->buf();
|
||||
std::vector<uint64_t> multicastFaces;
|
||||
|
||||
size_t offset = 0;
|
||||
while (offset < buf->size())
|
||||
{
|
||||
Block block;
|
||||
bool ok = Block::fromBuffer(buf, 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()) {
|
||||
discoverHubStage2("No multicast faces available, skipping stage 1");
|
||||
}
|
||||
else {
|
||||
shared_ptr<nfd::Controller> controller = make_shared<nfd::Controller>(ref(m_face));
|
||||
shared_ptr<std::pair<size_t, size_t> > nRegistrations =
|
||||
make_shared<std::pair<size_t, size_t> >(0, 0);
|
||||
|
||||
nfd::ControlParameters parameters;
|
||||
parameters
|
||||
.setName(LOCALHOP_HUB_DISCOVERY_PREFIX)
|
||||
.setCost(1)
|
||||
.setExpirationPeriod(time::seconds(30));
|
||||
|
||||
nRegistrations->first = multicastFaces.size();
|
||||
|
||||
for (std::vector<uint64_t>::iterator i = multicastFaces.begin();
|
||||
i != multicastFaces.end(); ++i) {
|
||||
parameters.setFaceId(*i);
|
||||
|
||||
controller->start<nfd::RibRegisterCommand>(parameters,
|
||||
bind(&NdnAutoconfig::discoverHubStage1_onRegisterSuccess,
|
||||
this, controller, nRegistrations),
|
||||
bind(&NdnAutoconfig::discoverHubStage1_onRegisterFailure,
|
||||
this, _1, _2, controller, nRegistrations));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
discoverHubStage1_onRegisterSuccess(const shared_ptr<nfd::Controller>& controller,
|
||||
const shared_ptr<std::pair<size_t, size_t> >& nRegistrations)
|
||||
{
|
||||
nRegistrations->second++;
|
||||
|
||||
if (nRegistrations->first == nRegistrations->second) {
|
||||
discoverHubStage1_setStrategy(controller);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
discoverHubStage1_onRegisterFailure(uint32_t code, const std::string& error,
|
||||
const shared_ptr<nfd::Controller>& controller,
|
||||
const shared_ptr<std::pair<size_t, size_t> >& nRegistrations)
|
||||
{
|
||||
std::cerr << "ERROR: " << error << " (code: " << code << ")" << std::endl;
|
||||
nRegistrations->first--;
|
||||
|
||||
if (nRegistrations->first == nRegistrations->second) {
|
||||
if (nRegistrations->first > 0) {
|
||||
discoverHubStage1_setStrategy(controller);
|
||||
} else {
|
||||
discoverHubStage2("Failed to register " + LOCALHOP_HUB_DISCOVERY_PREFIX.toUri() +
|
||||
" for all multicast faces");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
discoverHubStage1_setStrategy(const shared_ptr<nfd::Controller>& controller)
|
||||
{
|
||||
nfd::ControlParameters parameters;
|
||||
parameters
|
||||
.setName(LOCALHOP_HUB_DISCOVERY_PREFIX)
|
||||
.setStrategy("/localhost/nfd/strategy/broadcast");
|
||||
|
||||
controller->start<nfd::StrategyChoiceSetCommand>(parameters,
|
||||
bind(&NdnAutoconfig::discoverHubStage1_onSetStrategySuccess,
|
||||
this, controller),
|
||||
bind(&NdnAutoconfig::discoverHubStage1_onSetStrategyFailure,
|
||||
this, _2, controller));
|
||||
}
|
||||
|
||||
void
|
||||
discoverHubStage1_onSetStrategySuccess(const shared_ptr<nfd::Controller>& controller)
|
||||
{
|
||||
discoverHubStage1_requestHubData();
|
||||
}
|
||||
|
||||
void
|
||||
discoverHubStage1_onSetStrategyFailure(const std::string& error,
|
||||
const shared_ptr<nfd::Controller>& controller)
|
||||
{
|
||||
discoverHubStage2("Failed to set broadcast strategy for " +
|
||||
LOCALHOP_HUB_DISCOVERY_PREFIX.toUri() + " namespace (" + error + ")");
|
||||
}
|
||||
|
||||
// Start to look for a hub (NDN hub discovery first stage)
|
||||
void
|
||||
discoverHubStage1_requestHubData()
|
||||
{
|
||||
Interest interest(LOCALHOP_HUB_DISCOVERY_PREFIX);
|
||||
interest.setInterestLifetime(time::milliseconds(4000)); // 4 seconds
|
||||
interest.setMustBeFresh(true);
|
||||
|
||||
std::cerr << "Stage 1: Trying multicast discovery..." << std::endl;
|
||||
m_face.expressInterest(interest,
|
||||
bind(&NdnAutoconfig::onDiscoverHubStage1Success, this, _1, _2),
|
||||
bind(&NdnAutoconfig::discoverHubStage2, this, "Timeout"));
|
||||
}
|
||||
|
||||
// First stage OnData Callback
|
||||
void
|
||||
onDiscoverHubStage1Success(const Interest& interest, 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()) {
|
||||
discoverHubStage2("Incorrect reply to stage1");
|
||||
return;
|
||||
}
|
||||
std::string faceMgmtUri(reinterpret_cast<const char*>(blockValue->value()),
|
||||
blockValue->value_size());
|
||||
connectToHub(faceMgmtUri);
|
||||
}
|
||||
|
||||
// First stage OnTimeout callback - start 2nd stage
|
||||
void
|
||||
discoverHubStage2(const std::string& message)
|
||||
{
|
||||
std::cerr << message << std::endl;
|
||||
std::cerr << "Stage 2: Trying DNS query with default suffix..." << std::endl;
|
||||
|
||||
_res.retry = 2;
|
||||
_res.ndots = 10;
|
||||
|
||||
QueryAnswer queryAnswer;
|
||||
|
||||
int answerSize = res_search("_ndn._udp",
|
||||
ns_c_in,
|
||||
ns_t_srv,
|
||||
queryAnswer.buf,
|
||||
sizeof(queryAnswer));
|
||||
|
||||
// 2nd stage failed - move on to the third stage
|
||||
if (answerSize < 0) {
|
||||
discoverHubStage3("Failed to find NDN router using default suffix DNS query");
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isParsed = parseHostAndConnectToHub(queryAnswer, answerSize);
|
||||
if (isParsed == false) {
|
||||
// Failed to parse DNS response, try stage 3
|
||||
discoverHubStage3("Failed to parse DNS response");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Second stage OnTimeout callback
|
||||
void
|
||||
discoverHubStage3(const std::string& message)
|
||||
{
|
||||
std::cerr << message << std::endl;
|
||||
std::cerr << "Stage 3: Trying to find home router..." << std::endl;
|
||||
|
||||
KeyChain keyChain;
|
||||
Name identity = keyChain.getDefaultIdentity();
|
||||
std::string serverName = "_ndn._udp.";
|
||||
|
||||
for (Name::const_reverse_iterator i = identity.rbegin(); i != identity.rend(); i++) {
|
||||
serverName.append(i->toUri());
|
||||
serverName.append(".");
|
||||
}
|
||||
serverName += "_homehub._autoconf.named-data.net";
|
||||
std::cerr << "Stage3: About to query for a home router: " << serverName << std::endl;
|
||||
|
||||
QueryAnswer queryAnswer;
|
||||
|
||||
int answerSize = res_query(serverName.c_str(),
|
||||
ns_c_in,
|
||||
ns_t_srv,
|
||||
queryAnswer.buf,
|
||||
sizeof(queryAnswer));
|
||||
|
||||
|
||||
// 3rd stage failed - abort
|
||||
if (answerSize < 0) {
|
||||
std::cerr << "Failed to find a home router" << std::endl;
|
||||
std::cerr << "exit" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isParsed = parseHostAndConnectToHub(queryAnswer, answerSize);
|
||||
if (isParsed == false) {
|
||||
// Failed to parse DNS response
|
||||
throw Error("Failed to parse DNS response");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
parseHostAndConnectToHub(QueryAnswer& queryAnswer, int answerSize)
|
||||
{
|
||||
// The references of the next classes are:
|
||||
// http://www.diablotin.com/librairie/networking/dnsbind/ch14_02.htm
|
||||
// https://gist.github.com/mologie/6027597
|
||||
|
||||
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) {
|
||||
std::cerr << "No records found\n" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t* blob = queryAnswer.buf + NS_HFIXEDSZ;
|
||||
|
||||
blob += dn_skipname(blob, queryAnswer.buf + answerSize) + NS_QFIXEDSZ;
|
||||
|
||||
for (int i = 0; i < ntohs(queryAnswer.header.ancount); i++) {
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
|
||||
srv_t* server = reinterpret_cast<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) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string uri = "udp://";
|
||||
uri.append(hostName);
|
||||
uri.append(":");
|
||||
uri.append(boost::lexical_cast<std::string>(convertedPort));
|
||||
|
||||
connectToHub(uri);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
connectToHub(const std::string& uri)
|
||||
{
|
||||
ndn::util::FaceUri faceUri(uri);
|
||||
|
||||
faceUri.canonize(bind(&NdnAutoconfig::onCanonizeSuccess, this, _1),
|
||||
bind(&NdnAutoconfig::onCanonizeFailure, this, _1),
|
||||
m_face.getIoService(), ndn::time::seconds(4));
|
||||
|
||||
}
|
||||
|
||||
void onCanonizeSuccess(const ndn::util::FaceUri& canonicalUri)
|
||||
{
|
||||
std::cerr << "about to connect to: " << canonicalUri.toString() << std::endl;
|
||||
|
||||
m_controller.start<nfd::FaceCreateCommand>(
|
||||
nfd::ControlParameters()
|
||||
.setUri(canonicalUri.toString()),
|
||||
bind(&NdnAutoconfig::onHubConnectSuccess, this, _1),
|
||||
bind(&NdnAutoconfig::onHubConnectError, this, _1, _2));
|
||||
}
|
||||
|
||||
void
|
||||
onCanonizeFailure(const std::string& reason)
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "Canonize faceUri failed: " << reason;
|
||||
throw Error(os.str());
|
||||
}
|
||||
|
||||
void
|
||||
onHubConnectSuccess(const nfd::ControlParameters& resp)
|
||||
{
|
||||
std::cerr << "Successfully created face: " << resp << std::endl;
|
||||
|
||||
// Register a prefix in RIB
|
||||
static const Name TESTBED_PREFIX("/ndn");
|
||||
m_controller.start<nfd::RibRegisterCommand>(
|
||||
nfd::ControlParameters()
|
||||
.setName(TESTBED_PREFIX)
|
||||
.setFaceId(resp.getFaceId())
|
||||
.setOrigin(nfd::ROUTE_ORIGIN_AUTOCONF)
|
||||
.setCost(100)
|
||||
.setExpirationPeriod(time::milliseconds::max()),
|
||||
bind(&NdnAutoconfig::onPrefixRegistrationSuccess, this, _1),
|
||||
bind(&NdnAutoconfig::onPrefixRegistrationError, this, _1, _2));
|
||||
}
|
||||
|
||||
void
|
||||
onHubConnectError(uint32_t code, const std::string& error)
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "Failed to create face: " << error << " (code: " << code << ")";
|
||||
throw Error(os.str());
|
||||
}
|
||||
|
||||
void
|
||||
onPrefixRegistrationSuccess(const nfd::ControlParameters& commandSuccessResult)
|
||||
{
|
||||
std::cerr << "Successful in name registration: " << commandSuccessResult << std::endl;
|
||||
}
|
||||
|
||||
void
|
||||
onPrefixRegistrationError(uint32_t code, const std::string& error)
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "Failed in name registration, " << error << " (code: " << code << ")";
|
||||
throw Error(os.str());
|
||||
}
|
||||
|
||||
private:
|
||||
Face m_face;
|
||||
KeyChain m_keyChain;
|
||||
nfd::Controller m_controller;
|
||||
};
|
||||
|
||||
} // 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::usage(programName);
|
||||
return 0;
|
||||
case 'V':
|
||||
std::cout << NFD_VERSION_BUILD_STRING << std::endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
ndn::tools::NdnAutoconfig autoConfigInstance;
|
||||
|
||||
autoConfigInstance.discoverHubStage1();
|
||||
autoConfigInstance.run();
|
||||
}
|
||||
catch (const std::exception& error) {
|
||||
std::cerr << "ERROR: " << error.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in new issue
Block a user