dns.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013-2021 Regents of the University of California.
4  *
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 "ndn-cxx/net/dns.hpp"
24 
25 #include <boost/asio/io_service.hpp>
26 #include <boost/asio/ip/udp.hpp>
27 #if BOOST_VERSION >= 106600
28 #include <boost/asio/post.hpp>
29 #endif
30 
31 namespace ndn {
32 namespace dns {
33 
34 class Resolver : noncopyable
35 {
36 public:
37  using protocol = boost::asio::ip::udp;
38  using iterator = protocol::resolver::iterator;
39  using query = protocol::resolver::query;
40 
41 public:
42  Resolver(boost::asio::io_service& ioService,
43  const AddressSelector& addressSelector)
44  : m_resolver(ioService)
45  , m_addressSelector(addressSelector)
46  , m_scheduler(ioService)
47  {
48  BOOST_ASSERT(m_addressSelector != nullptr);
49  }
50 
51  void
52  asyncResolve(const query& q,
53  const SuccessCallback& onSuccess,
54  const ErrorCallback& onError,
55  time::nanoseconds timeout,
56  const shared_ptr<Resolver>& self)
57  {
58  m_onSuccess = onSuccess;
59  m_onError = onError;
60 
61  m_resolver.async_resolve(q, [=] (auto&&... args) {
62  onResolveResult(std::forward<decltype(args)>(args)..., self);
63  });
64 
65  m_resolveTimeout = m_scheduler.schedule(timeout, [=] { onResolveTimeout(self); });
66  }
67 
68  iterator
69  syncResolve(const query& q)
70  {
71  return selectAddress(m_resolver.resolve(q));
72  }
73 
74 private:
75  void
76  onResolveResult(const boost::system::error_code& error,
77  iterator it, const shared_ptr<Resolver>& self)
78  {
79  m_resolveTimeout.cancel();
80 
81  // ensure the Resolver isn't destructed while callbacks are still pending, see #2653
82 #if BOOST_VERSION >= 106600
83  boost::asio::post(m_resolver.get_executor(), [self] {});
84 #else
85  m_resolver.get_io_service().post([self] {});
86 #endif
87 
88  if (error) {
89  if (error == boost::asio::error::operation_aborted)
90  return;
91 
92  if (m_onError)
93  m_onError("Hostname cannot be resolved: " + error.message());
94 
95  return;
96  }
97 
98  it = selectAddress(it);
99 
100  if (it != iterator() && m_onSuccess) {
101  m_onSuccess(it->endpoint().address());
102  }
103  else if (m_onError) {
104  m_onError("No endpoints match the specified address selector");
105  }
106  }
107 
108  void
109  onResolveTimeout(const shared_ptr<Resolver>& self)
110  {
111  m_resolver.cancel();
112 
113  // ensure the Resolver isn't destructed while callbacks are still pending, see #2653
114 #if BOOST_VERSION >= 106600
115  boost::asio::post(m_resolver.get_executor(), [self] {});
116 #else
117  m_resolver.get_io_service().post([self] {});
118 #endif
119 
120  if (m_onError)
121  m_onError("Hostname resolution timed out");
122  }
123 
124  iterator
125  selectAddress(iterator it) const
126  {
127  while (it != iterator() && !m_addressSelector(it->endpoint().address())) {
128  ++it;
129  }
130  return it;
131  }
132 
133 private:
134  protocol::resolver m_resolver;
135 
136  AddressSelector m_addressSelector;
137  SuccessCallback m_onSuccess;
138  ErrorCallback m_onError;
139 
140  Scheduler m_scheduler;
141  scheduler::EventId m_resolveTimeout;
142 };
143 
144 void
145 asyncResolve(const std::string& host,
146  const SuccessCallback& onSuccess,
147  const ErrorCallback& onError,
148  boost::asio::io_service& ioService,
149  const AddressSelector& addressSelector,
150  time::nanoseconds timeout)
151 {
152  auto resolver = make_shared<Resolver>(ioService, addressSelector);
153  resolver->asyncResolve(Resolver::query(host, ""), onSuccess, onError, timeout, resolver);
154  // resolver will be destroyed when async operation finishes or ioService stops
155 }
156 
157 IpAddress
158 syncResolve(const std::string& host,
159  boost::asio::io_service& ioService,
160  const AddressSelector& addressSelector)
161 {
162  Resolver resolver(ioService, addressSelector);
163  auto it = resolver.syncResolve(Resolver::query(host, ""));
164 
165  if (it == Resolver::iterator()) {
166  NDN_THROW(Error("No endpoints match the specified address selector"));
167  }
168 
169  return it->endpoint().address();
170 }
171 
172 } // namespace dns
173 } // namespace ndn
A handle for a scheduled event.
Definition: scheduler.hpp:61
Generic time-based scheduler.
Definition: scheduler.hpp:135
#define NDN_THROW(e)
Definition: exception.hpp:61
boost::asio::ip::address IpAddress
Definition: dns.hpp:33
void asyncResolve(const std::string &host, const SuccessCallback &onSuccess, const ErrorCallback &onError, boost::asio::io_service &ioService, const AddressSelector &addressSelector, time::nanoseconds timeout)
Asynchronously resolve host.
Definition: dns.cpp:145
function< void(const IpAddress &address)> SuccessCallback
Definition: dns.hpp:69
function< bool(const IpAddress &address)> AddressSelector
Definition: dns.hpp:34
function< void(const std::string &reason)> ErrorCallback
Definition: dns.hpp:70
IpAddress syncResolve(const std::string &host, boost::asio::io_service &ioService, const AddressSelector &addressSelector)
Synchronously resolve host.
Definition: dns.cpp:158
boost::chrono::nanoseconds nanoseconds
Definition: time.hpp:50
Definition: data.cpp:25