blob: 0aebc3ac3d02fce48bcf6b7e84b3fad7f280fa42 [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);
73
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020074 if (error) {
75 if (error == boost::asio::error::operation_aborted)
76 return;
Vince Lehman7a6bb352014-09-22 15:58:19 -050077
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020078 if (m_onError)
79 m_onError("Hostname cannot be resolved: " + error.message());
Vince Lehman7a6bb352014-09-22 15:58:19 -050080
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020081 return;
82 }
Vince Lehman7a6bb352014-09-22 15:58:19 -050083
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020084 it = selectAddress(it);
Vince Lehman7a6bb352014-09-22 15:58:19 -050085
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020086 if (it != iterator() && m_onSuccess) {
87 m_onSuccess(it->endpoint().address());
88 }
89 else if (m_onError) {
90 m_onError("No endpoints match the specified address selector");
91 }
Vince Lehman7a6bb352014-09-22 15:58:19 -050092 }
93
94 void
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020095 onResolveTimeout(const shared_ptr<Resolver>& self)
Vince Lehman7a6bb352014-09-22 15:58:19 -050096 {
97 m_resolver.cancel();
Davide Pesaventoa2de7e42015-10-24 00:14:49 +020098
99 if (m_onError)
100 m_onError("Hostname resolution timed out");
Vince Lehman7a6bb352014-09-22 15:58:19 -0500101 }
102
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200103 iterator
104 selectAddress(iterator it) const
105 {
106 while (it != iterator() &&
107 !m_addressSelector(it->endpoint().address())) {
108 ++it;
109 }
110
111 return it;
112 }
Vince Lehman7a6bb352014-09-22 15:58:19 -0500113
114private:
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200115 protocol::resolver m_resolver;
Vince Lehman7a6bb352014-09-22 15:58:19 -0500116
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200117 AddressSelector m_addressSelector;
Vince Lehman7a6bb352014-09-22 15:58:19 -0500118 SuccessCallback m_onSuccess;
119 ErrorCallback m_onError;
120
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200121 util::scheduler::Scheduler m_scheduler;
122 util::scheduler::EventId m_resolveTimeout;
Vince Lehman7a6bb352014-09-22 15:58:19 -0500123};
124
Vince Lehman7a6bb352014-09-22 15:58:19 -0500125void
126asyncResolve(const std::string& host,
127 const SuccessCallback& onSuccess,
128 const ErrorCallback& onError,
129 boost::asio::io_service& ioService,
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200130 const AddressSelector& addressSelector,
131 time::nanoseconds timeout)
Vince Lehman7a6bb352014-09-22 15:58:19 -0500132{
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200133 auto resolver = make_shared<Resolver>(ref(ioService), addressSelector);
134 resolver->asyncResolve(Resolver::query(host, ""), onSuccess, onError, timeout, resolver);
135 // resolver will be destroyed when async operation finishes or ioService stops
Vince Lehman7a6bb352014-09-22 15:58:19 -0500136}
137
138IpAddress
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200139syncResolve(const std::string& host,
140 boost::asio::io_service& ioService,
141 const AddressSelector& addressSelector)
Vince Lehman7a6bb352014-09-22 15:58:19 -0500142{
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200143 Resolver resolver(ioService, addressSelector);
144 auto it = resolver.syncResolve(Resolver::query(host, ""));
Vince Lehman7a6bb352014-09-22 15:58:19 -0500145
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200146 if (it == Resolver::iterator()) {
147 BOOST_THROW_EXCEPTION(Error("No endpoints match the specified address selector"));
148 }
Vince Lehman7a6bb352014-09-22 15:58:19 -0500149
Davide Pesaventoa2de7e42015-10-24 00:14:49 +0200150 return it->endpoint().address();
Vince Lehman7a6bb352014-09-22 15:58:19 -0500151}
152
153} // namespace dns
154} // namespace ndn