2
// resolver_service.hpp
3
// ~~~~~~~~~~~~~~~~~~~~
5
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7
// Distributed under the Boost Software License, Version 1.0. (See accompanying
8
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
11
#ifndef ASIO_DETAIL_RESOLVER_SERVICE_HPP
12
#define ASIO_DETAIL_RESOLVER_SERVICE_HPP
14
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
16
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18
#include "asio/detail/push_options.hpp"
20
#include "asio/detail/push_options.hpp"
22
#include <boost/scoped_ptr.hpp>
23
#include <boost/shared_ptr.hpp>
24
#include <boost/weak_ptr.hpp>
25
#include "asio/detail/pop_options.hpp"
27
#include "asio/error.hpp"
28
#include "asio/io_service.hpp"
29
#include "asio/detail/bind_handler.hpp"
30
#include "asio/detail/mutex.hpp"
31
#include "asio/detail/noncopyable.hpp"
32
#include "asio/detail/service_base.hpp"
33
#include "asio/detail/socket_ops.hpp"
34
#include "asio/detail/socket_types.hpp"
35
#include "asio/detail/thread.hpp"
40
template <typename Protocol>
41
class resolver_service
42
: public asio::detail::service_base<resolver_service<Protocol> >
45
// Helper class to perform exception-safe cleanup of addrinfo objects.
47
: private asio::detail::noncopyable
50
explicit auto_addrinfo(asio::detail::addrinfo_type* ai)
58
socket_ops::freeaddrinfo(ai_);
61
operator asio::detail::addrinfo_type*()
67
asio::detail::addrinfo_type* ai_;
71
// The implementation type of the resolver. The shared pointer is used as a
72
// cancellation token to indicate to the background thread that the operation
73
// has been cancelled.
74
typedef boost::shared_ptr<void> implementation_type;
75
struct noop_deleter { void operator()(void*) {} };
78
typedef typename Protocol::endpoint endpoint_type;
81
typedef typename Protocol::resolver_query query_type;
84
typedef typename Protocol::resolver_iterator iterator_type;
87
resolver_service(asio::io_service& io_service)
88
: asio::detail::service_base<
89
resolver_service<Protocol> >(io_service),
91
work_io_service_(new asio::io_service),
92
work_(new asio::io_service::work(*work_io_service_)),
103
// Destroy all user-defined handler objects owned by the service.
104
void shutdown_service()
107
if (work_io_service_)
109
work_io_service_->stop();
112
work_thread_->join();
113
work_thread_.reset();
115
work_io_service_.reset();
119
// Construct a new resolver implementation.
120
void construct(implementation_type& impl)
122
impl.reset(static_cast<void*>(0), noop_deleter());
125
// Destroy a resolver implementation.
126
void destroy(implementation_type&)
130
// Cancel pending asynchronous operations.
131
void cancel(implementation_type& impl)
133
impl.reset(static_cast<void*>(0), noop_deleter());
136
// Resolve a query to a list of entries.
137
iterator_type resolve(implementation_type&, const query_type& query,
138
asio::error_code& ec)
140
asio::detail::addrinfo_type* address_info = 0;
141
std::string host_name = query.host_name();
142
std::string service_name = query.service_name();
143
asio::detail::addrinfo_type hints = query.hints();
145
socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0,
146
service_name.c_str(), &hints, &address_info, ec);
147
auto_addrinfo auto_address_info(address_info);
150
return iterator_type();
152
return iterator_type::create(address_info, host_name, service_name);
155
template <typename Handler>
156
class resolve_query_handler
159
resolve_query_handler(implementation_type impl, const query_type& query,
160
asio::io_service& io_service, Handler handler)
163
io_service_(io_service),
171
// Check if the operation has been cancelled.
174
iterator_type iterator;
175
io_service_.post(asio::detail::bind_handler(handler_,
176
asio::error::operation_aborted, iterator));
180
// Perform the blocking host resolution operation.
181
asio::detail::addrinfo_type* address_info = 0;
182
std::string host_name = query_.host_name();
183
std::string service_name = query_.service_name();
184
asio::detail::addrinfo_type hints = query_.hints();
186
socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0,
187
service_name.c_str(), &hints, &address_info, ec);
188
auto_addrinfo auto_address_info(address_info);
190
// Invoke the handler and pass the result.
191
iterator_type iterator;
193
iterator = iterator_type::create(address_info, host_name, service_name);
194
io_service_.post(asio::detail::bind_handler(
195
handler_, ec, iterator));
199
boost::weak_ptr<void> impl_;
201
asio::io_service& io_service_;
202
asio::io_service::work work_;
206
// Asynchronously resolve a query to a list of entries.
207
template <typename Handler>
208
void async_resolve(implementation_type& impl, const query_type& query,
211
if (work_io_service_)
214
work_io_service_->post(
215
resolve_query_handler<Handler>(
216
impl, query, this->get_io_service(), handler));
220
// Resolve an endpoint to a list of entries.
221
iterator_type resolve(implementation_type&,
222
const endpoint_type& endpoint, asio::error_code& ec)
224
// First try resolving with the service name. If that fails try resolving
225
// but allow the service to be returned as a number.
226
char host_name[NI_MAXHOST];
227
char service_name[NI_MAXSERV];
228
int flags = endpoint.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0;
229
socket_ops::getnameinfo(endpoint.data(), endpoint.size(),
230
host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
233
flags |= NI_NUMERICSERV;
234
socket_ops::getnameinfo(endpoint.data(), endpoint.size(),
235
host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
239
return iterator_type();
241
return iterator_type::create(endpoint, host_name, service_name);
244
template <typename Handler>
245
class resolve_endpoint_handler
248
resolve_endpoint_handler(implementation_type impl,
249
const endpoint_type& endpoint, asio::io_service& io_service,
253
io_service_(io_service),
261
// Check if the operation has been cancelled.
264
iterator_type iterator;
265
io_service_.post(asio::detail::bind_handler(handler_,
266
asio::error::operation_aborted, iterator));
271
// First try resolving with the service name. If that fails try resolving
272
// but allow the service to be returned as a number.
273
char host_name[NI_MAXHOST];
274
char service_name[NI_MAXSERV];
275
int flags = endpoint_.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0;
277
socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(),
278
host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
281
flags |= NI_NUMERICSERV;
282
socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(),
283
host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
286
// Invoke the handler and pass the result.
287
iterator_type iterator;
289
iterator = iterator_type::create(endpoint_, host_name, service_name);
290
io_service_.post(asio::detail::bind_handler(
291
handler_, ec, iterator));
295
boost::weak_ptr<void> impl_;
296
endpoint_type endpoint_;
297
asio::io_service& io_service_;
298
asio::io_service::work work_;
302
// Asynchronously resolve an endpoint to a list of entries.
303
template <typename Handler>
304
void async_resolve(implementation_type& impl, const endpoint_type& endpoint,
307
if (work_io_service_)
310
work_io_service_->post(
311
resolve_endpoint_handler<Handler>(
312
impl, endpoint, this->get_io_service(), handler));
317
// Helper class to run the work io_service in a thread.
318
class work_io_service_runner
321
work_io_service_runner(asio::io_service& io_service)
322
: io_service_(io_service) {}
323
void operator()() { io_service_.run(); }
325
asio::io_service& io_service_;
328
// Start the work thread if it's not already running.
329
void start_work_thread()
331
asio::detail::mutex::scoped_lock lock(mutex_);
332
if (work_thread_ == 0)
334
work_thread_.reset(new asio::detail::thread(
335
work_io_service_runner(*work_io_service_)));
339
// Mutex to protect access to internal data.
340
asio::detail::mutex mutex_;
342
// Private io_service used for performing asynchronous host resolution.
343
boost::scoped_ptr<asio::io_service> work_io_service_;
345
// Work for the private io_service to perform.
346
boost::scoped_ptr<asio::io_service::work> work_;
348
// Thread used for running the work io_service's run loop.
349
boost::scoped_ptr<asio::detail::thread> work_thread_;
352
} // namespace detail
355
#include "asio/detail/pop_options.hpp"
357
#endif // ASIO_DETAIL_RESOLVER_SERVICE_HPP