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