blob: a02047e0529cddbe84d795e38c8ec0c52e845bf9 [file] [log] [blame]
Alexander Afanasyev452e2822014-02-27 14:48:04 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (C) 2014 Named Data Networking Project
4 * See COPYING for copyright and distribution information.
5 */
6
7#ifndef NFD_CORE_RESOLVER_H
8#define NFD_CORE_RESOLVER_H
9
10#include "common.hpp"
11#include "core/global-io.hpp"
Alexander Afanasyev452e2822014-02-27 14:48:04 -080012#include "core/scheduler.hpp"
13
14namespace nfd {
15namespace resolver {
16
17typedef function<bool (const boost::asio::ip::address& address)> AddressSelector;
18
19struct AnyAddress {
20 bool
21 operator()(const boost::asio::ip::address& address)
22 {
23 return true;
24 }
25};
26
27struct Ipv4Address {
28 bool
29 operator()(const boost::asio::ip::address& address)
30 {
31 return address.is_v4();
32 }
33};
34
35struct Ipv6Address {
36 bool
37 operator()(const boost::asio::ip::address& address)
38 {
39 return address.is_v6();
40 }
41};
42
43} // namespace resolver
44
45template<class Protocol>
46class Resolver
47{
48public:
49 struct Error : public std::runtime_error
50 {
51 Error(const std::string& what) : std::runtime_error(what) {}
52 };
53
54 typedef function<void (const typename Protocol::endpoint& endpoint)> SuccessCallback;
55 typedef function<void (const std::string& reason)> ErrorCallback;
56
57 typedef boost::asio::ip::basic_resolver< Protocol > resolver;
58
59 /** \brief Asynchronously resolve host and port
60 *
61 * If an address selector predicate is specified, then each resolved IP address
62 * is checked against the predicate.
63 *
64 * Available address selector predicates:
65 *
66 * - resolver::AnyAddress()
67 * - resolver::Ipv4Address()
68 * - resolver::Ipv6Address()
69 */
70 static void
71 asyncResolve(const std::string& host, const std::string& port,
72 const SuccessCallback& onSuccess,
73 const ErrorCallback& onError,
74 const nfd::resolver::AddressSelector& addressSelector = nfd::resolver::AnyAddress(),
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -070075 const time::seconds& timeout = time::seconds(4))
Alexander Afanasyev452e2822014-02-27 14:48:04 -080076 {
77 shared_ptr<Resolver> resolver =
78 shared_ptr<Resolver>(new Resolver(onSuccess, onError,
79 addressSelector));
80
81 resolver->asyncResolve(host, port, timeout, resolver);
82 // resolver will be destroyed when async operation finishes or global IO service stops
83 }
84
85 /** \brief Synchronously resolve host and port
86 *
87 * If an address selector predicate is specified, then each resolved IP address
88 * is checked against the predicate.
89 *
90 * Available address selector predicates:
91 *
92 * - resolver::AnyAddress()
93 * - resolver::Ipv4Address()
94 * - resolver::Ipv6Address()
95 */
96 static typename Protocol::endpoint
97 syncResolve(const std::string& host, const std::string& port,
98 const nfd::resolver::AddressSelector& addressSelector = nfd::resolver::AnyAddress())
99 {
100 Resolver resolver(SuccessCallback(), ErrorCallback(), addressSelector);
101
Alexander Afanasyev500b2532014-03-31 12:29:25 -0700102 typename resolver::query query(host, port
103#if not defined(__FreeBSD__)
104 , resolver::query::all_matching
105#endif
106 );
Alexander Afanasyev452e2822014-02-27 14:48:04 -0800107
108 typename resolver::iterator remoteEndpoint = resolver.m_resolver.resolve(query);
109 typename resolver::iterator end;
110 for (; remoteEndpoint != end; ++remoteEndpoint)
111 {
112 if (addressSelector(typename Protocol::endpoint(*remoteEndpoint).address()))
113 return *remoteEndpoint;
114 }
115 throw Error("No endpoint matching the specified address selector found");
116 }
117
118private:
119 Resolver(const SuccessCallback& onSuccess,
120 const ErrorCallback& onError,
121 const nfd::resolver::AddressSelector& addressSelector)
122 : m_resolver(getGlobalIoService())
123 , m_addressSelector(addressSelector)
124 , m_onSuccess(onSuccess)
125 , m_onError(onError)
126 {
127 }
128
129 void
130 asyncResolve(const std::string& host, const std::string& port,
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -0700131 const time::seconds& timeout,
Alexander Afanasyev452e2822014-02-27 14:48:04 -0800132 const shared_ptr<Resolver>& self)
133 {
Alexander Afanasyev500b2532014-03-31 12:29:25 -0700134 typename resolver::query query(host, port
135#if not defined(__FreeBSD__)
136 , resolver::query::all_matching
137#endif
138 );
Alexander Afanasyev452e2822014-02-27 14:48:04 -0800139
140 m_resolver.async_resolve(query,
141 bind(&Resolver::onResolveSuccess, this, _1, _2, self));
142
143 m_resolveTimeout = scheduler::schedule(timeout,
144 bind(&Resolver::onResolveError, this,
145 "Timeout", self));
146 }
147
148 void
149 onResolveSuccess(const boost::system::error_code& error,
150 typename resolver::iterator remoteEndpoint,
151 const shared_ptr<Resolver>& self)
152 {
153 scheduler::cancel(m_resolveTimeout);
154
155 if (error)
156 {
157 if (error == boost::system::errc::operation_canceled)
158 return;
159
160 return m_onError("Remote endpoint hostname or port cannot be resolved: " +
161 error.category().message(error.value()));
162 }
163
164 typename resolver::iterator end;
165 for (; remoteEndpoint != end; ++remoteEndpoint)
166 {
167 if (m_addressSelector(typename Protocol::endpoint(*remoteEndpoint).address()))
168 return m_onSuccess(*remoteEndpoint);
169 }
170
171 m_onError("No endpoint matching the specified address selector found");
172 }
173
174 void
175 onResolveError(const std::string& errorInfo,
176 const shared_ptr<Resolver>& self)
177 {
178 m_resolver.cancel();
179 m_onError(errorInfo);
180 }
181
182private:
183 resolver m_resolver;
184 EventId m_resolveTimeout;
185
186 nfd::resolver::AddressSelector m_addressSelector;
187 SuccessCallback m_onSuccess;
188 ErrorCallback m_onError;
189};
190
191typedef Resolver<boost::asio::ip::tcp> TcpResolver;
192typedef Resolver<boost::asio::ip::udp> UdpResolver;
193
194} // namespace nfd
195
196#endif // NFD_CORE_RESOLVER_H