resolver_service.hpp
Go to the documentation of this file.
00001 //
00002 // resolver_service.hpp
00003 // ~~~~~~~~~~~~~~~~~~~~
00004 //
00005 // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
00006 //
00007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
00008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
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   // Helper class to perform exception-safe cleanup of addrinfo objects.
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   // The implementation type of the resolver. The shared pointer is used as a
00072   // cancellation token to indicate to the background thread that the operation
00073   // has been cancelled.
00074   typedef boost::shared_ptr<void> implementation_type;
00075   struct noop_deleter { void operator()(void*) {} };
00076 
00077   // The endpoint type.
00078   typedef typename Protocol::endpoint endpoint_type;
00079 
00080   // The query type.
00081   typedef typename Protocol::resolver_query query_type;
00082 
00083   // The iterator type.
00084   typedef typename Protocol::resolver_iterator iterator_type;
00085 
00086   // Constructor.
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   // Destructor.
00098   ~resolver_service()
00099   {
00100     shutdown_service();
00101   }
00102 
00103   // Destroy all user-defined handler objects owned by the service.
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   // Construct a new resolver implementation.
00120   void construct(implementation_type& impl)
00121   {
00122     impl.reset(static_cast<void*>(0), noop_deleter());
00123   }
00124 
00125   // Destroy a resolver implementation.
00126   void destroy(implementation_type&)
00127   {
00128   }
00129 
00130   // Cancel pending asynchronous operations.
00131   void cancel(implementation_type& impl)
00132   {
00133     impl.reset(static_cast<void*>(0), noop_deleter());
00134   }
00135 
00136   // Resolve a query to a list of entries.
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       // Check if the operation has been cancelled.
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       // Perform the blocking host resolution operation.
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       // Invoke the handler and pass the result.
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   // Asynchronously resolve a query to a list of entries.
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   // Resolve an endpoint to a list of entries.
00221   iterator_type resolve(implementation_type&,
00222       const endpoint_type& endpoint, asio::error_code& ec)
00223   {
00224     // First try resolving with the service name. If that fails try resolving
00225     // but allow the service to be returned as a number.
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       // Check if the operation has been cancelled.
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       // First try resolving with the service name. If that fails try resolving
00272       // but allow the service to be returned as a number.
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       // Invoke the handler and pass the result.
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   // Asynchronously resolve an endpoint to a list of entries.
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   // Helper class to run the work io_service in a thread.
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   // Start the work thread if it's not already running.
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   // Mutex to protect access to internal data.
00340   asio::detail::mutex mutex_;
00341 
00342   // Private io_service used for performing asynchronous host resolution.
00343   boost::scoped_ptr<asio::io_service> work_io_service_;
00344 
00345   // Work for the private io_service to perform.
00346   boost::scoped_ptr<asio::io_service::work> work_;
00347 
00348   // Thread used for running the work io_service's run loop.
00349   boost::scoped_ptr<asio::detail::thread> work_thread_;
00350 };
00351 
00352 } // namespace detail
00353 } // namespace asio
00354 
00355 #include "asio/detail/pop_options.hpp"
00356 
00357 #endif // ASIO_DETAIL_RESOLVER_SERVICE_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines


Castor
Author(s): Carpe Noctem
autogenerated on Fri Nov 8 2013 11:05:39