blob: 8df097f5cec40ea85c7f8442c9ec66000a0869bc [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2013-2014 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
* ndn-cxx library is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* ndn-cxx library 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 Lesser General Public License for more details.
*
* You should have received copies of the GNU General Public License and GNU Lesser
* General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
* <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*/
#include "dns.hpp"
#include "scheduler.hpp"
namespace ndn {
namespace dns {
typedef boost::asio::ip::udp::endpoint EndPoint;
typedef boost::asio::ip::basic_resolver<boost::asio::ip::udp> BoostResolver;
class Resolver : noncopyable
{
public:
Resolver(const SuccessCallback& onSuccess,
const ErrorCallback& onError,
const ndn::dns::AddressSelector& addressSelector,
boost::asio::io_service& ioService)
: m_resolver(ioService)
, m_addressSelector(addressSelector)
, m_onSuccess(onSuccess)
, m_onError(onError)
, m_scheduler(ioService)
{
}
void
asyncResolve(const std::string& host,
const time::nanoseconds& timeout,
const shared_ptr<Resolver>& self)
{
BoostResolver::query query(host, NULL_PORT
#if not defined(__FreeBSD__)
, BoostResolver::query::all_matching
#endif
);
m_resolver.async_resolve(query, bind(&Resolver::onResolveSuccess, this, _1, _2, self));
m_resolveTimeout = m_scheduler.scheduleEvent(timeout,
bind(&Resolver::onResolveError, this,
"Timeout", self));
}
BoostResolver::iterator
syncResolve(BoostResolver::query query)
{
return m_resolver.resolve(query);
}
void
onResolveSuccess(const boost::system::error_code& error,
BoostResolver::iterator remoteEndpoint,
const shared_ptr<Resolver>& self)
{
m_scheduler.cancelEvent(m_resolveTimeout);
if (error)
{
if (error == boost::system::errc::operation_canceled)
{
return;
}
return m_onError("Remote endpoint hostname or port cannot be resolved: " +
error.category().message(error.value()));
}
BoostResolver::iterator end;
for (; remoteEndpoint != end; ++remoteEndpoint)
{
IpAddress address(EndPoint(*remoteEndpoint).address());
if (m_addressSelector(address))
{
return m_onSuccess(address);
}
}
m_onError("No endpoint matching the specified address selector found");
}
void
onResolveError(const std::string& errorInfo, const shared_ptr<Resolver>& self)
{
m_resolver.cancel();
m_onError(errorInfo);
}
public:
static const std::string NULL_PORT;
private:
BoostResolver m_resolver;
EventId m_resolveTimeout;
ndn::dns::AddressSelector m_addressSelector;
SuccessCallback m_onSuccess;
ErrorCallback m_onError;
Scheduler m_scheduler;
};
const std::string Resolver::NULL_PORT = "";
void
asyncResolve(const std::string& host,
const SuccessCallback& onSuccess,
const ErrorCallback& onError,
boost::asio::io_service& ioService,
const ndn::dns::AddressSelector& addressSelector,
const time::nanoseconds& timeout)
{
shared_ptr<Resolver> resolver = make_shared<Resolver>(onSuccess, onError,
addressSelector, ndn::ref(ioService));
resolver->asyncResolve(host, timeout, resolver);
// resolver will be destroyed when async operation finishes or global IO service stops
}
IpAddress
syncResolve(const std::string& host, boost::asio::io_service& ioService,
const ndn::dns::AddressSelector& addressSelector)
{
Resolver resolver(SuccessCallback(), ErrorCallback(), addressSelector, ioService);
BoostResolver::query query(host, Resolver::NULL_PORT
#if not defined(__FreeBSD__)
, BoostResolver::query::all_matching
#endif
);
BoostResolver::iterator remoteEndpoint = resolver.syncResolve(query);
BoostResolver::iterator end;
for (; remoteEndpoint != end; ++remoteEndpoint)
{
if (addressSelector(EndPoint(*remoteEndpoint).address()))
{
return EndPoint(*remoteEndpoint).address();
}
}
throw Error("No endpoint matching the specified address selector found");
}
} // namespace dns
} // namespace ndn