blob: 508e26d8c4f676bcb54007a0400bd4d9e99b7a54 [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
102 typename resolver::query query(host, port,
103 resolver::query::all_matching);
104
105 typename resolver::iterator remoteEndpoint = resolver.m_resolver.resolve(query);
106 typename resolver::iterator end;
107 for (; remoteEndpoint != end; ++remoteEndpoint)
108 {
109 if (addressSelector(typename Protocol::endpoint(*remoteEndpoint).address()))
110 return *remoteEndpoint;
111 }
112 throw Error("No endpoint matching the specified address selector found");
113 }
114
115private:
116 Resolver(const SuccessCallback& onSuccess,
117 const ErrorCallback& onError,
118 const nfd::resolver::AddressSelector& addressSelector)
119 : m_resolver(getGlobalIoService())
120 , m_addressSelector(addressSelector)
121 , m_onSuccess(onSuccess)
122 , m_onError(onError)
123 {
124 }
125
126 void
127 asyncResolve(const std::string& host, const std::string& port,
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -0700128 const time::seconds& timeout,
Alexander Afanasyev452e2822014-02-27 14:48:04 -0800129 const shared_ptr<Resolver>& self)
130 {
131 typename resolver::query query(host, port,
132 resolver::query::all_matching);
133
134 m_resolver.async_resolve(query,
135 bind(&Resolver::onResolveSuccess, this, _1, _2, self));
136
137 m_resolveTimeout = scheduler::schedule(timeout,
138 bind(&Resolver::onResolveError, this,
139 "Timeout", self));
140 }
141
142 void
143 onResolveSuccess(const boost::system::error_code& error,
144 typename resolver::iterator remoteEndpoint,
145 const shared_ptr<Resolver>& self)
146 {
147 scheduler::cancel(m_resolveTimeout);
148
149 if (error)
150 {
151 if (error == boost::system::errc::operation_canceled)
152 return;
153
154 return m_onError("Remote endpoint hostname or port cannot be resolved: " +
155 error.category().message(error.value()));
156 }
157
158 typename resolver::iterator end;
159 for (; remoteEndpoint != end; ++remoteEndpoint)
160 {
161 if (m_addressSelector(typename Protocol::endpoint(*remoteEndpoint).address()))
162 return m_onSuccess(*remoteEndpoint);
163 }
164
165 m_onError("No endpoint matching the specified address selector found");
166 }
167
168 void
169 onResolveError(const std::string& errorInfo,
170 const shared_ptr<Resolver>& self)
171 {
172 m_resolver.cancel();
173 m_onError(errorInfo);
174 }
175
176private:
177 resolver m_resolver;
178 EventId m_resolveTimeout;
179
180 nfd::resolver::AddressSelector m_addressSelector;
181 SuccessCallback m_onSuccess;
182 ErrorCallback m_onError;
183};
184
185typedef Resolver<boost::asio::ip::tcp> TcpResolver;
186typedef Resolver<boost::asio::ip::udp> UdpResolver;
187
188} // namespace nfd
189
190#endif // NFD_CORE_RESOLVER_H