blob: 0adfbd2eb8a2d5ab55703711f39d164a2b714143 [file] [log] [blame]
Vince Lehman7a6bb352014-09-22 15:58:19 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyev5946ed12015-01-19 23:41:39 -08003 * Copyright (c) 2013-2015 Regents of the University of California.
Vince Lehman7a6bb352014-09-22 15:58:19 -05004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
22#include "dns.hpp"
23
24#include "scheduler.hpp"
25
26namespace ndn {
27namespace dns {
28
Vince Lehman7a6bb352014-09-22 15:58:19 -050029class Resolver : noncopyable
30{
31public:
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020032 typedef boost::asio::ip::udp protocol;
33 typedef protocol::resolver::iterator iterator;
34 typedef protocol::resolver::query query;
35
36public:
37 Resolver(boost::asio::io_service& ioService,
38 const AddressSelector& addressSelector)
Vince Lehman7a6bb352014-09-22 15:58:19 -050039 : m_resolver(ioService)
40 , m_addressSelector(addressSelector)
Vince Lehman7a6bb352014-09-22 15:58:19 -050041 , m_scheduler(ioService)
42 {
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020043 BOOST_ASSERT(m_addressSelector != nullptr);
Vince Lehman7a6bb352014-09-22 15:58:19 -050044 }
45
46 void
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020047 asyncResolve(const query& q,
48 const SuccessCallback& onSuccess,
49 const ErrorCallback& onError,
50 time::nanoseconds timeout,
Vince Lehman7a6bb352014-09-22 15:58:19 -050051 const shared_ptr<Resolver>& self)
52 {
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020053 m_onSuccess = onSuccess;
54 m_onError = onError;
Vince Lehman7a6bb352014-09-22 15:58:19 -050055
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020056 m_resolver.async_resolve(q, bind(&Resolver::onResolveResult, this, _1, _2, self));
Vince Lehman7a6bb352014-09-22 15:58:19 -050057
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020058 m_resolveTimeout = m_scheduler.scheduleEvent(timeout, bind(&Resolver::onResolveTimeout, this, self));
Vince Lehman7a6bb352014-09-22 15:58:19 -050059 }
60
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020061 iterator
62 syncResolve(const query& q)
Vince Lehman7a6bb352014-09-22 15:58:19 -050063 {
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020064 return selectAddress(m_resolver.resolve(q));
Vince Lehman7a6bb352014-09-22 15:58:19 -050065 }
66
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020067private:
Vince Lehman7a6bb352014-09-22 15:58:19 -050068 void
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020069 onResolveResult(const boost::system::error_code& error,
70 iterator it, const shared_ptr<Resolver>& self)
Vince Lehman7a6bb352014-09-22 15:58:19 -050071 {
72 m_scheduler.cancelEvent(m_resolveTimeout);
Davide Pesaventofd5de112015-10-24 01:47:10 +020073 // ensure the Resolver isn't destructed while callbacks are still pending, see #2653
74 m_resolver.get_io_service().post(bind([] (const shared_ptr<Resolver>&) {}, self));
Vince Lehman7a6bb352014-09-22 15:58:19 -050075
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020076 if (error) {
77 if (error == boost::asio::error::operation_aborted)
78 return;
Vince Lehman7a6bb352014-09-22 15:58:19 -050079
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020080 if (m_onError)
81 m_onError("Hostname cannot be resolved: " + error.message());
Vince Lehman7a6bb352014-09-22 15:58:19 -050082
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020083 return;
84 }
Vince Lehman7a6bb352014-09-22 15:58:19 -050085
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020086 it = selectAddress(it);
Vince Lehman7a6bb352014-09-22 15:58:19 -050087
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020088 if (it != iterator() && m_onSuccess) {
89 m_onSuccess(it->endpoint().address());
90 }
91 else if (m_onError) {
92 m_onError("No endpoints match the specified address selector");
93 }
Vince Lehman7a6bb352014-09-22 15:58:19 -050094 }
95
96 void
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020097 onResolveTimeout(const shared_ptr<Resolver>& self)
Vince Lehman7a6bb352014-09-22 15:58:19 -050098 {
99 m_resolver.cancel();
Davide Pesaventofd5de112015-10-24 01:47:10 +0200100 // ensure the Resolver isn't destructed while callbacks are still pending, see #2653
101 m_resolver.get_io_service().post(bind([] (const shared_ptr<Resolver>&) {}, self));
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200102
103 if (m_onError)
104 m_onError("Hostname resolution timed out");
Vince Lehman7a6bb352014-09-22 15:58:19 -0500105 }
106
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200107 iterator
108 selectAddress(iterator it) const
109 {
110 while (it != iterator() &&
111 !m_addressSelector(it->endpoint().address())) {
112 ++it;
113 }
114
115 return it;
116 }
Vince Lehman7a6bb352014-09-22 15:58:19 -0500117
118private:
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200119 protocol::resolver m_resolver;
Vince Lehman7a6bb352014-09-22 15:58:19 -0500120
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200121 AddressSelector m_addressSelector;
Vince Lehman7a6bb352014-09-22 15:58:19 -0500122 SuccessCallback m_onSuccess;
123 ErrorCallback m_onError;
124
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200125 util::scheduler::Scheduler m_scheduler;
126 util::scheduler::EventId m_resolveTimeout;
Vince Lehman7a6bb352014-09-22 15:58:19 -0500127};
128
Vince Lehman7a6bb352014-09-22 15:58:19 -0500129void
130asyncResolve(const std::string& host,
131 const SuccessCallback& onSuccess,
132 const ErrorCallback& onError,
133 boost::asio::io_service& ioService,
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200134 const AddressSelector& addressSelector,
135 time::nanoseconds timeout)
Vince Lehman7a6bb352014-09-22 15:58:19 -0500136{
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200137 auto resolver = make_shared<Resolver>(ref(ioService), addressSelector);
138 resolver->asyncResolve(Resolver::query(host, ""), onSuccess, onError, timeout, resolver);
139 // resolver will be destroyed when async operation finishes or ioService stops
Vince Lehman7a6bb352014-09-22 15:58:19 -0500140}
141
142IpAddress
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200143syncResolve(const std::string& host,
144 boost::asio::io_service& ioService,
145 const AddressSelector& addressSelector)
Vince Lehman7a6bb352014-09-22 15:58:19 -0500146{
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200147 Resolver resolver(ioService, addressSelector);
148 auto it = resolver.syncResolve(Resolver::query(host, ""));
Vince Lehman7a6bb352014-09-22 15:58:19 -0500149
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200150 if (it == Resolver::iterator()) {
151 BOOST_THROW_EXCEPTION(Error("No endpoints match the specified address selector"));
152 }
Vince Lehman7a6bb352014-09-22 15:58:19 -0500153
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200154 return it->endpoint().address();
Vince Lehman7a6bb352014-09-22 15:58:19 -0500155}
156
157} // namespace dns
158} // namespace ndn