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