blob: d14464573316389df7ce4eeeb5cc47da38f77bb8 [file] [log] [blame]
Alexander Afanasyev452e2822014-02-27 14:48:04 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Junxiao Shi1e46be32015-01-08 20:18:05 -07003 * Copyright (c) 2014-2015, Regents of the University of California,
4 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -070010 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
Junxiao Shi1e46be32015-01-08 20:18:05 -070024 */
Alexander Afanasyev452e2822014-02-27 14:48:04 -080025
26#ifndef NFD_CORE_RESOLVER_H
27#define NFD_CORE_RESOLVER_H
28
29#include "common.hpp"
30#include "core/global-io.hpp"
Alexander Afanasyev452e2822014-02-27 14:48:04 -080031#include "core/scheduler.hpp"
32
33namespace nfd {
34namespace resolver {
35
36typedef function<bool (const boost::asio::ip::address& address)> AddressSelector;
37
38struct AnyAddress {
39 bool
40 operator()(const boost::asio::ip::address& address)
41 {
42 return true;
43 }
44};
45
46struct Ipv4Address {
47 bool
48 operator()(const boost::asio::ip::address& address)
49 {
50 return address.is_v4();
51 }
52};
53
54struct Ipv6Address {
55 bool
56 operator()(const boost::asio::ip::address& address)
57 {
58 return address.is_v6();
59 }
60};
61
62} // namespace resolver
63
64template<class Protocol>
65class Resolver
66{
67public:
68 struct Error : public std::runtime_error
69 {
70 Error(const std::string& what) : std::runtime_error(what) {}
71 };
72
73 typedef function<void (const typename Protocol::endpoint& endpoint)> SuccessCallback;
74 typedef function<void (const std::string& reason)> ErrorCallback;
75
76 typedef boost::asio::ip::basic_resolver< Protocol > resolver;
77
78 /** \brief Asynchronously resolve host and port
79 *
80 * If an address selector predicate is specified, then each resolved IP address
81 * is checked against the predicate.
82 *
83 * Available address selector predicates:
84 *
85 * - resolver::AnyAddress()
86 * - resolver::Ipv4Address()
87 * - resolver::Ipv6Address()
88 */
89 static void
90 asyncResolve(const std::string& host, const std::string& port,
91 const SuccessCallback& onSuccess,
92 const ErrorCallback& onError,
93 const nfd::resolver::AddressSelector& addressSelector = nfd::resolver::AnyAddress(),
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -070094 const time::seconds& timeout = time::seconds(4))
Alexander Afanasyev452e2822014-02-27 14:48:04 -080095 {
96 shared_ptr<Resolver> resolver =
97 shared_ptr<Resolver>(new Resolver(onSuccess, onError,
98 addressSelector));
99
100 resolver->asyncResolve(host, port, timeout, resolver);
101 // resolver will be destroyed when async operation finishes or global IO service stops
102 }
103
104 /** \brief Synchronously resolve host and port
105 *
106 * If an address selector predicate is specified, then each resolved IP address
107 * is checked against the predicate.
108 *
109 * Available address selector predicates:
110 *
111 * - resolver::AnyAddress()
112 * - resolver::Ipv4Address()
113 * - resolver::Ipv6Address()
114 */
115 static typename Protocol::endpoint
116 syncResolve(const std::string& host, const std::string& port,
117 const nfd::resolver::AddressSelector& addressSelector = nfd::resolver::AnyAddress())
118 {
119 Resolver resolver(SuccessCallback(), ErrorCallback(), addressSelector);
120
Alexander Afanasyev500b2532014-03-31 12:29:25 -0700121 typename resolver::query query(host, port
122#if not defined(__FreeBSD__)
123 , resolver::query::all_matching
124#endif
125 );
Alexander Afanasyev452e2822014-02-27 14:48:04 -0800126
127 typename resolver::iterator remoteEndpoint = resolver.m_resolver.resolve(query);
128 typename resolver::iterator end;
129 for (; remoteEndpoint != end; ++remoteEndpoint)
130 {
131 if (addressSelector(typename Protocol::endpoint(*remoteEndpoint).address()))
132 return *remoteEndpoint;
133 }
134 throw Error("No endpoint matching the specified address selector found");
135 }
136
137private:
138 Resolver(const SuccessCallback& onSuccess,
139 const ErrorCallback& onError,
140 const nfd::resolver::AddressSelector& addressSelector)
141 : m_resolver(getGlobalIoService())
142 , m_addressSelector(addressSelector)
143 , m_onSuccess(onSuccess)
144 , m_onError(onError)
145 {
146 }
147
148 void
149 asyncResolve(const std::string& host, const std::string& port,
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -0700150 const time::seconds& timeout,
Alexander Afanasyev452e2822014-02-27 14:48:04 -0800151 const shared_ptr<Resolver>& self)
152 {
Alexander Afanasyev500b2532014-03-31 12:29:25 -0700153 typename resolver::query query(host, port
154#if not defined(__FreeBSD__)
155 , resolver::query::all_matching
156#endif
157 );
Alexander Afanasyev452e2822014-02-27 14:48:04 -0800158
159 m_resolver.async_resolve(query,
160 bind(&Resolver::onResolveSuccess, this, _1, _2, self));
161
162 m_resolveTimeout = scheduler::schedule(timeout,
163 bind(&Resolver::onResolveError, this,
164 "Timeout", self));
165 }
166
167 void
168 onResolveSuccess(const boost::system::error_code& error,
169 typename resolver::iterator remoteEndpoint,
170 const shared_ptr<Resolver>& self)
171 {
172 scheduler::cancel(m_resolveTimeout);
173
174 if (error)
175 {
176 if (error == boost::system::errc::operation_canceled)
177 return;
178
179 return m_onError("Remote endpoint hostname or port cannot be resolved: " +
180 error.category().message(error.value()));
181 }
182
183 typename resolver::iterator end;
184 for (; remoteEndpoint != end; ++remoteEndpoint)
185 {
186 if (m_addressSelector(typename Protocol::endpoint(*remoteEndpoint).address()))
187 return m_onSuccess(*remoteEndpoint);
188 }
189
190 m_onError("No endpoint matching the specified address selector found");
191 }
192
193 void
194 onResolveError(const std::string& errorInfo,
195 const shared_ptr<Resolver>& self)
196 {
197 m_resolver.cancel();
198 m_onError(errorInfo);
199 }
200
201private:
202 resolver m_resolver;
Junxiao Shi1e46be32015-01-08 20:18:05 -0700203 scheduler::EventId m_resolveTimeout;
Alexander Afanasyev452e2822014-02-27 14:48:04 -0800204
205 nfd::resolver::AddressSelector m_addressSelector;
206 SuccessCallback m_onSuccess;
207 ErrorCallback m_onError;
208};
209
210typedef Resolver<boost::asio::ip::tcp> TcpResolver;
211typedef Resolver<boost::asio::ip::udp> UdpResolver;
212
213} // namespace nfd
214
215#endif // NFD_CORE_RESOLVER_H