blob: 73fd8b1d6a427daad7b73c12844b0cda3fca1403 [file] [log] [blame]
Vince Lehman7a6bb352014-09-22 15:58:19 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Davide Pesavento537dc3a2016-02-18 19:35:26 +01003 * Copyright (c) 2013-2016 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"
Vince Lehman7a6bb352014-09-22 15:58:19 -050023#include "scheduler.hpp"
24
Davide Pesavento537dc3a2016-02-18 19:35:26 +010025#include <boost/asio/io_service.hpp>
26#include <boost/asio/ip/udp.hpp>
27
Vince Lehman7a6bb352014-09-22 15:58:19 -050028namespace ndn {
29namespace dns {
30
Vince Lehman7a6bb352014-09-22 15:58:19 -050031class Resolver : noncopyable
32{
33public:
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020034 typedef boost::asio::ip::udp protocol;
35 typedef protocol::resolver::iterator iterator;
36 typedef protocol::resolver::query query;
37
38public:
39 Resolver(boost::asio::io_service& ioService,
40 const AddressSelector& addressSelector)
Vince Lehman7a6bb352014-09-22 15:58:19 -050041 : m_resolver(ioService)
42 , m_addressSelector(addressSelector)
Vince Lehman7a6bb352014-09-22 15:58:19 -050043 , m_scheduler(ioService)
44 {
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020045 BOOST_ASSERT(m_addressSelector != nullptr);
Vince Lehman7a6bb352014-09-22 15:58:19 -050046 }
47
48 void
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020049 asyncResolve(const query& q,
50 const SuccessCallback& onSuccess,
51 const ErrorCallback& onError,
52 time::nanoseconds timeout,
Vince Lehman7a6bb352014-09-22 15:58:19 -050053 const shared_ptr<Resolver>& self)
54 {
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020055 m_onSuccess = onSuccess;
56 m_onError = onError;
Vince Lehman7a6bb352014-09-22 15:58:19 -050057
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020058 m_resolver.async_resolve(q, bind(&Resolver::onResolveResult, this, _1, _2, self));
Vince Lehman7a6bb352014-09-22 15:58:19 -050059
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020060 m_resolveTimeout = m_scheduler.scheduleEvent(timeout, bind(&Resolver::onResolveTimeout, this, self));
Vince Lehman7a6bb352014-09-22 15:58:19 -050061 }
62
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020063 iterator
64 syncResolve(const query& q)
Vince Lehman7a6bb352014-09-22 15:58:19 -050065 {
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020066 return selectAddress(m_resolver.resolve(q));
Vince Lehman7a6bb352014-09-22 15:58:19 -050067 }
68
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020069private:
Vince Lehman7a6bb352014-09-22 15:58:19 -050070 void
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020071 onResolveResult(const boost::system::error_code& error,
72 iterator it, const shared_ptr<Resolver>& self)
Vince Lehman7a6bb352014-09-22 15:58:19 -050073 {
74 m_scheduler.cancelEvent(m_resolveTimeout);
Davide Pesaventofd5de112015-10-24 01:47:10 +020075 // ensure the Resolver isn't destructed while callbacks are still pending, see #2653
76 m_resolver.get_io_service().post(bind([] (const shared_ptr<Resolver>&) {}, self));
Vince Lehman7a6bb352014-09-22 15:58:19 -050077
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020078 if (error) {
79 if (error == boost::asio::error::operation_aborted)
80 return;
Vince Lehman7a6bb352014-09-22 15:58:19 -050081
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020082 if (m_onError)
83 m_onError("Hostname cannot be resolved: " + error.message());
Vince Lehman7a6bb352014-09-22 15:58:19 -050084
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020085 return;
86 }
Vince Lehman7a6bb352014-09-22 15:58:19 -050087
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020088 it = selectAddress(it);
Vince Lehman7a6bb352014-09-22 15:58:19 -050089
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020090 if (it != iterator() && m_onSuccess) {
91 m_onSuccess(it->endpoint().address());
92 }
93 else if (m_onError) {
94 m_onError("No endpoints match the specified address selector");
95 }
Vince Lehman7a6bb352014-09-22 15:58:19 -050096 }
97
98 void
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020099 onResolveTimeout(const shared_ptr<Resolver>& self)
Vince Lehman7a6bb352014-09-22 15:58:19 -0500100 {
101 m_resolver.cancel();
Davide Pesaventofd5de112015-10-24 01:47:10 +0200102 // ensure the Resolver isn't destructed while callbacks are still pending, see #2653
103 m_resolver.get_io_service().post(bind([] (const shared_ptr<Resolver>&) {}, self));
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200104
105 if (m_onError)
106 m_onError("Hostname resolution timed out");
Vince Lehman7a6bb352014-09-22 15:58:19 -0500107 }
108
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200109 iterator
110 selectAddress(iterator it) const
111 {
112 while (it != iterator() &&
113 !m_addressSelector(it->endpoint().address())) {
114 ++it;
115 }
116
117 return it;
118 }
Vince Lehman7a6bb352014-09-22 15:58:19 -0500119
120private:
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200121 protocol::resolver m_resolver;
Vince Lehman7a6bb352014-09-22 15:58:19 -0500122
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200123 AddressSelector m_addressSelector;
Vince Lehman7a6bb352014-09-22 15:58:19 -0500124 SuccessCallback m_onSuccess;
125 ErrorCallback m_onError;
126
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200127 util::scheduler::Scheduler m_scheduler;
128 util::scheduler::EventId m_resolveTimeout;
Vince Lehman7a6bb352014-09-22 15:58:19 -0500129};
130
Vince Lehman7a6bb352014-09-22 15:58:19 -0500131void
132asyncResolve(const std::string& host,
133 const SuccessCallback& onSuccess,
134 const ErrorCallback& onError,
135 boost::asio::io_service& ioService,
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200136 const AddressSelector& addressSelector,
137 time::nanoseconds timeout)
Vince Lehman7a6bb352014-09-22 15:58:19 -0500138{
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200139 auto resolver = make_shared<Resolver>(ref(ioService), addressSelector);
140 resolver->asyncResolve(Resolver::query(host, ""), onSuccess, onError, timeout, resolver);
141 // resolver will be destroyed when async operation finishes or ioService stops
Vince Lehman7a6bb352014-09-22 15:58:19 -0500142}
143
144IpAddress
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200145syncResolve(const std::string& host,
146 boost::asio::io_service& ioService,
147 const AddressSelector& addressSelector)
Vince Lehman7a6bb352014-09-22 15:58:19 -0500148{
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200149 Resolver resolver(ioService, addressSelector);
150 auto it = resolver.syncResolve(Resolver::query(host, ""));
Vince Lehman7a6bb352014-09-22 15:58:19 -0500151
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200152 if (it == Resolver::iterator()) {
153 BOOST_THROW_EXCEPTION(Error("No endpoints match the specified address selector"));
154 }
Vince Lehman7a6bb352014-09-22 15:58:19 -0500155
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200156 return it->endpoint().address();
Vince Lehman7a6bb352014-09-22 15:58:19 -0500157}
158
159} // namespace dns
160} // namespace ndn