00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef ASIO_DETAIL_RESOLVER_SERVICE_HPP
00012 #define ASIO_DETAIL_RESOLVER_SERVICE_HPP
00013
00014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
00015 # pragma once
00016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
00017
00018 #include "asio/detail/push_options.hpp"
00019
00020 #include "asio/detail/push_options.hpp"
00021 #include <cstring>
00022 #include <boost/scoped_ptr.hpp>
00023 #include <boost/shared_ptr.hpp>
00024 #include <boost/weak_ptr.hpp>
00025 #include "asio/detail/pop_options.hpp"
00026
00027 #include "asio/error.hpp"
00028 #include "asio/io_service.hpp"
00029 #include "asio/detail/bind_handler.hpp"
00030 #include "asio/detail/mutex.hpp"
00031 #include "asio/detail/noncopyable.hpp"
00032 #include "asio/detail/service_base.hpp"
00033 #include "asio/detail/socket_ops.hpp"
00034 #include "asio/detail/socket_types.hpp"
00035 #include "asio/detail/thread.hpp"
00036
00037 namespace asio {
00038 namespace detail {
00039
00040 template <typename Protocol>
00041 class resolver_service
00042 : public asio::detail::service_base<resolver_service<Protocol> >
00043 {
00044 private:
00045
00046 class auto_addrinfo
00047 : private asio::detail::noncopyable
00048 {
00049 public:
00050 explicit auto_addrinfo(asio::detail::addrinfo_type* ai)
00051 : ai_(ai)
00052 {
00053 }
00054
00055 ~auto_addrinfo()
00056 {
00057 if (ai_)
00058 socket_ops::freeaddrinfo(ai_);
00059 }
00060
00061 operator asio::detail::addrinfo_type*()
00062 {
00063 return ai_;
00064 }
00065
00066 private:
00067 asio::detail::addrinfo_type* ai_;
00068 };
00069
00070 public:
00071
00072
00073
00074 typedef boost::shared_ptr<void> implementation_type;
00075 struct noop_deleter { void operator()(void*) {} };
00076
00077
00078 typedef typename Protocol::endpoint endpoint_type;
00079
00080
00081 typedef typename Protocol::resolver_query query_type;
00082
00083
00084 typedef typename Protocol::resolver_iterator iterator_type;
00085
00086
00087 resolver_service(asio::io_service& io_service)
00088 : asio::detail::service_base<
00089 resolver_service<Protocol> >(io_service),
00090 mutex_(),
00091 work_io_service_(new asio::io_service),
00092 work_(new asio::io_service::work(*work_io_service_)),
00093 work_thread_(0)
00094 {
00095 }
00096
00097
00098 ~resolver_service()
00099 {
00100 shutdown_service();
00101 }
00102
00103
00104 void shutdown_service()
00105 {
00106 work_.reset();
00107 if (work_io_service_)
00108 {
00109 work_io_service_->stop();
00110 if (work_thread_)
00111 {
00112 work_thread_->join();
00113 work_thread_.reset();
00114 }
00115 work_io_service_.reset();
00116 }
00117 }
00118
00119
00120 void construct(implementation_type& impl)
00121 {
00122 impl.reset(static_cast<void*>(0), noop_deleter());
00123 }
00124
00125
00126 void destroy(implementation_type&)
00127 {
00128 }
00129
00130
00131 void cancel(implementation_type& impl)
00132 {
00133 impl.reset(static_cast<void*>(0), noop_deleter());
00134 }
00135
00136
00137 iterator_type resolve(implementation_type&, const query_type& query,
00138 asio::error_code& ec)
00139 {
00140 asio::detail::addrinfo_type* address_info = 0;
00141 std::string host_name = query.host_name();
00142 std::string service_name = query.service_name();
00143 asio::detail::addrinfo_type hints = query.hints();
00144
00145 socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0,
00146 service_name.c_str(), &hints, &address_info, ec);
00147 auto_addrinfo auto_address_info(address_info);
00148
00149 if (ec)
00150 return iterator_type();
00151
00152 return iterator_type::create(address_info, host_name, service_name);
00153 }
00154
00155 template <typename Handler>
00156 class resolve_query_handler
00157 {
00158 public:
00159 resolve_query_handler(implementation_type impl, const query_type& query,
00160 asio::io_service& io_service, Handler handler)
00161 : impl_(impl),
00162 query_(query),
00163 io_service_(io_service),
00164 work_(io_service),
00165 handler_(handler)
00166 {
00167 }
00168
00169 void operator()()
00170 {
00171
00172 if (impl_.expired())
00173 {
00174 iterator_type iterator;
00175 io_service_.post(asio::detail::bind_handler(handler_,
00176 asio::error::operation_aborted, iterator));
00177 return;
00178 }
00179
00180
00181 asio::detail::addrinfo_type* address_info = 0;
00182 std::string host_name = query_.host_name();
00183 std::string service_name = query_.service_name();
00184 asio::detail::addrinfo_type hints = query_.hints();
00185 asio::error_code ec;
00186 socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0,
00187 service_name.c_str(), &hints, &address_info, ec);
00188 auto_addrinfo auto_address_info(address_info);
00189
00190
00191 iterator_type iterator;
00192 if (!ec)
00193 iterator = iterator_type::create(address_info, host_name, service_name);
00194 io_service_.post(asio::detail::bind_handler(
00195 handler_, ec, iterator));
00196 }
00197
00198 private:
00199 boost::weak_ptr<void> impl_;
00200 query_type query_;
00201 asio::io_service& io_service_;
00202 asio::io_service::work work_;
00203 Handler handler_;
00204 };
00205
00206
00207 template <typename Handler>
00208 void async_resolve(implementation_type& impl, const query_type& query,
00209 Handler handler)
00210 {
00211 if (work_io_service_)
00212 {
00213 start_work_thread();
00214 work_io_service_->post(
00215 resolve_query_handler<Handler>(
00216 impl, query, this->get_io_service(), handler));
00217 }
00218 }
00219
00220
00221 iterator_type resolve(implementation_type&,
00222 const endpoint_type& endpoint, asio::error_code& ec)
00223 {
00224
00225
00226 char host_name[NI_MAXHOST];
00227 char service_name[NI_MAXSERV];
00228 int flags = endpoint.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0;
00229 socket_ops::getnameinfo(endpoint.data(), endpoint.size(),
00230 host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
00231 if (ec)
00232 {
00233 flags |= NI_NUMERICSERV;
00234 socket_ops::getnameinfo(endpoint.data(), endpoint.size(),
00235 host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
00236 }
00237
00238 if (ec)
00239 return iterator_type();
00240
00241 return iterator_type::create(endpoint, host_name, service_name);
00242 }
00243
00244 template <typename Handler>
00245 class resolve_endpoint_handler
00246 {
00247 public:
00248 resolve_endpoint_handler(implementation_type impl,
00249 const endpoint_type& endpoint, asio::io_service& io_service,
00250 Handler handler)
00251 : impl_(impl),
00252 endpoint_(endpoint),
00253 io_service_(io_service),
00254 work_(io_service),
00255 handler_(handler)
00256 {
00257 }
00258
00259 void operator()()
00260 {
00261
00262 if (impl_.expired())
00263 {
00264 iterator_type iterator;
00265 io_service_.post(asio::detail::bind_handler(handler_,
00266 asio::error::operation_aborted, iterator));
00267 return;
00268 }
00269
00270
00271
00272
00273 char host_name[NI_MAXHOST];
00274 char service_name[NI_MAXSERV];
00275 int flags = endpoint_.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0;
00276 asio::error_code ec;
00277 socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(),
00278 host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
00279 if (ec)
00280 {
00281 flags |= NI_NUMERICSERV;
00282 socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(),
00283 host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
00284 }
00285
00286
00287 iterator_type iterator;
00288 if (!ec)
00289 iterator = iterator_type::create(endpoint_, host_name, service_name);
00290 io_service_.post(asio::detail::bind_handler(
00291 handler_, ec, iterator));
00292 }
00293
00294 private:
00295 boost::weak_ptr<void> impl_;
00296 endpoint_type endpoint_;
00297 asio::io_service& io_service_;
00298 asio::io_service::work work_;
00299 Handler handler_;
00300 };
00301
00302
00303 template <typename Handler>
00304 void async_resolve(implementation_type& impl, const endpoint_type& endpoint,
00305 Handler handler)
00306 {
00307 if (work_io_service_)
00308 {
00309 start_work_thread();
00310 work_io_service_->post(
00311 resolve_endpoint_handler<Handler>(
00312 impl, endpoint, this->get_io_service(), handler));
00313 }
00314 }
00315
00316 private:
00317
00318 class work_io_service_runner
00319 {
00320 public:
00321 work_io_service_runner(asio::io_service& io_service)
00322 : io_service_(io_service) {}
00323 void operator()() { io_service_.run(); }
00324 private:
00325 asio::io_service& io_service_;
00326 };
00327
00328
00329 void start_work_thread()
00330 {
00331 asio::detail::mutex::scoped_lock lock(mutex_);
00332 if (work_thread_ == 0)
00333 {
00334 work_thread_.reset(new asio::detail::thread(
00335 work_io_service_runner(*work_io_service_)));
00336 }
00337 }
00338
00339
00340 asio::detail::mutex mutex_;
00341
00342
00343 boost::scoped_ptr<asio::io_service> work_io_service_;
00344
00345
00346 boost::scoped_ptr<asio::io_service::work> work_;
00347
00348
00349 boost::scoped_ptr<asio::detail::thread> work_thread_;
00350 };
00351
00352 }
00353 }
00354
00355 #include "asio/detail/pop_options.hpp"
00356
00357 #endif // ASIO_DETAIL_RESOLVER_SERVICE_HPP