1 //
2 // detail/winrt_resolver_service.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
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)
9 //
10 
11 #ifndef BOOST_ASIO_DETAIL_WINRT_RESOLVER_SERVICE_HPP
12 #define BOOST_ASIO_DETAIL_WINRT_RESOLVER_SERVICE_HPP
13 
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17 
18 #include <boost/asio/detail/config.hpp>
19 
20 #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
21 
22 #include <boost/asio/ip/basic_resolver_query.hpp>
23 #include <boost/asio/ip/basic_resolver_results.hpp>
24 #include <boost/asio/post.hpp>
25 #include <boost/asio/detail/bind_handler.hpp>
26 #include <boost/asio/detail/memory.hpp>
27 #include <boost/asio/detail/socket_ops.hpp>
28 #include <boost/asio/detail/winrt_async_manager.hpp>
29 #include <boost/asio/detail/winrt_resolve_op.hpp>
30 #include <boost/asio/detail/winrt_utils.hpp>
31 
32 #if defined(BOOST_ASIO_HAS_IOCP)
33 # include <boost/asio/detail/win_iocp_io_context.hpp>
34 #else // defined(BOOST_ASIO_HAS_IOCP)
35 # include <boost/asio/detail/scheduler.hpp>
36 #endif // defined(BOOST_ASIO_HAS_IOCP)
37 
38 #include <boost/asio/detail/push_options.hpp>
39 
40 namespace boost {
41 namespace asio {
42 namespace detail {
43 
44 template <typename Protocol>
45 class winrt_resolver_service :
46   public execution_context_service_base<winrt_resolver_service<Protocol> >
47 {
48 public:
49   // The implementation type of the resolver. A cancellation token is used to
50   // indicate to the asynchronous operation that the operation has been
51   // cancelled.
52   typedef socket_ops::shared_cancel_token_type implementation_type;
53 
54   // The endpoint type.
55   typedef typename Protocol::endpoint endpoint_type;
56 
57   // The query type.
58   typedef boost::asio::ip::basic_resolver_query<Protocol> query_type;
59 
60   // The results type.
61   typedef boost::asio::ip::basic_resolver_results<Protocol> results_type;
62 
63   // Constructor.
winrt_resolver_service(execution_context & context)64   winrt_resolver_service(execution_context& context)
65     : execution_context_service_base<
66         winrt_resolver_service<Protocol> >(context),
67       scheduler_(use_service<scheduler_impl>(context)),
68       async_manager_(use_service<winrt_async_manager>(context))
69   {
70   }
71 
72   // Destructor.
~winrt_resolver_service()73   ~winrt_resolver_service()
74   {
75   }
76 
77   // Destroy all user-defined handler objects owned by the service.
shutdown()78   void shutdown()
79   {
80   }
81 
82   // Perform any fork-related housekeeping.
notify_fork(execution_context::fork_event)83   void notify_fork(execution_context::fork_event)
84   {
85   }
86 
87   // Construct a new resolver implementation.
construct(implementation_type &)88   void construct(implementation_type&)
89   {
90   }
91 
92   // Move-construct a new resolver implementation.
move_construct(implementation_type &,implementation_type &)93   void move_construct(implementation_type&,
94       implementation_type&)
95   {
96   }
97 
98   // Move-assign from another resolver implementation.
move_assign(implementation_type &,winrt_resolver_service &,implementation_type &)99   void move_assign(implementation_type&,
100       winrt_resolver_service&, implementation_type&)
101   {
102   }
103 
104   // Destroy a resolver implementation.
destroy(implementation_type &)105   void destroy(implementation_type&)
106   {
107   }
108 
109   // Cancel pending asynchronous operations.
cancel(implementation_type &)110   void cancel(implementation_type&)
111   {
112   }
113 
114   // Resolve a query to a list of entries.
resolve(implementation_type &,const query_type & query,boost::system::error_code & ec)115   results_type resolve(implementation_type&,
116       const query_type& query, boost::system::error_code& ec)
117   {
118     try
119     {
120       using namespace Windows::Networking::Sockets;
121       auto endpoint_pairs = async_manager_.sync(
122           DatagramSocket::GetEndpointPairsAsync(
123             winrt_utils::host_name(query.host_name()),
124             winrt_utils::string(query.service_name())), ec);
125 
126       if (ec)
127         return results_type();
128 
129       return results_type::create(
130           endpoint_pairs, query.hints(),
131           query.host_name(), query.service_name());
132     }
133     catch (Platform::Exception^ e)
134     {
135       ec = boost::system::error_code(e->HResult,
136           boost::system::system_category());
137       return results_type();
138     }
139   }
140 
141   // Asynchronously resolve a query to a list of entries.
142   template <typename Handler, typename IoExecutor>
async_resolve(implementation_type & impl,const query_type & query,Handler & handler,const IoExecutor & io_ex)143   void async_resolve(implementation_type& impl, const query_type& query,
144       Handler& handler, const IoExecutor& io_ex)
145   {
146     bool is_continuation =
147       boost_asio_handler_cont_helpers::is_continuation(handler);
148 
149     // Allocate and construct an operation to wrap the handler.
150     typedef winrt_resolve_op<Protocol, Handler, IoExecutor> op;
151     typename op::ptr p = { boost::asio::detail::addressof(handler),
152       op::ptr::allocate(handler), 0 };
153     p.p = new (p.v) op(query, handler, io_ex);
154 
155     BOOST_ASIO_HANDLER_CREATION((scheduler_.context(),
156           *p.p, "resolver", &impl, 0, "async_resolve"));
157     (void)impl;
158 
159     try
160     {
161       using namespace Windows::Networking::Sockets;
162       async_manager_.async(DatagramSocket::GetEndpointPairsAsync(
163             winrt_utils::host_name(query.host_name()),
164             winrt_utils::string(query.service_name())), p.p);
165       p.v = p.p = 0;
166     }
167     catch (Platform::Exception^ e)
168     {
169       p.p->ec_ = boost::system::error_code(
170           e->HResult, boost::system::system_category());
171       scheduler_.post_immediate_completion(p.p, is_continuation);
172       p.v = p.p = 0;
173     }
174   }
175 
176   // Resolve an endpoint to a list of entries.
resolve(implementation_type &,const endpoint_type &,boost::system::error_code & ec)177   results_type resolve(implementation_type&,
178       const endpoint_type&, boost::system::error_code& ec)
179   {
180     ec = boost::asio::error::operation_not_supported;
181     return results_type();
182   }
183 
184   // Asynchronously resolve an endpoint to a list of entries.
185   template <typename Handler, typename IoExecutor>
async_resolve(implementation_type &,const endpoint_type &,Handler & handler,const IoExecutor & io_ex)186   void async_resolve(implementation_type&, const endpoint_type&,
187       Handler& handler, const IoExecutor& io_ex)
188   {
189     boost::system::error_code ec = boost::asio::error::operation_not_supported;
190     const results_type results;
191     boost::asio::post(io_ex, detail::bind_handler(handler, ec, results));
192   }
193 
194 private:
195   // The scheduler implementation used for delivering completions.
196 #if defined(BOOST_ASIO_HAS_IOCP)
197   typedef class win_iocp_io_context scheduler_impl;
198 #else
199   typedef class scheduler scheduler_impl;
200 #endif
201   scheduler_impl& scheduler_;
202 
203   winrt_async_manager& async_manager_;
204 };
205 
206 } // namespace detail
207 } // namespace asio
208 } // namespace boost
209 
210 #include <boost/asio/detail/pop_options.hpp>
211 
212 #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
213 
214 #endif // BOOST_ASIO_DETAIL_WINRT_RESOLVER_SERVICE_HPP
215