95.45% Lines (21/22) 100.00% Functions (7/7)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2026 Steve Gerbino 2   // Copyright (c) 2026 Steve Gerbino
3   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 4   // Distributed under the Boost Software License, Version 1.0. (See accompanying
5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/cppalliance/corosio 7   // Official repository: https://github.com/cppalliance/corosio
8   // 8   //
9   9  
10   #ifndef BOOST_COROSIO_NATIVE_NATIVE_RESOLVER_HPP 10   #ifndef BOOST_COROSIO_NATIVE_NATIVE_RESOLVER_HPP
11   #define BOOST_COROSIO_NATIVE_NATIVE_RESOLVER_HPP 11   #define BOOST_COROSIO_NATIVE_NATIVE_RESOLVER_HPP
12   12  
13   #include <boost/corosio/resolver.hpp> 13   #include <boost/corosio/resolver.hpp>
14   #include <boost/corosio/backend.hpp> 14   #include <boost/corosio/backend.hpp>
15   15  
16   #ifndef BOOST_COROSIO_MRDOCS 16   #ifndef BOOST_COROSIO_MRDOCS
17   #if BOOST_COROSIO_HAS_EPOLL || BOOST_COROSIO_HAS_SELECT || \ 17   #if BOOST_COROSIO_HAS_EPOLL || BOOST_COROSIO_HAS_SELECT || \
18   BOOST_COROSIO_HAS_KQUEUE 18   BOOST_COROSIO_HAS_KQUEUE
19   #include <boost/corosio/native/detail/posix/posix_resolver_service.hpp> 19   #include <boost/corosio/native/detail/posix/posix_resolver_service.hpp>
20   #endif 20   #endif
21   21  
22   #if BOOST_COROSIO_HAS_IOCP 22   #if BOOST_COROSIO_HAS_IOCP
23   #include <boost/corosio/native/detail/iocp/win_resolver_service.hpp> 23   #include <boost/corosio/native/detail/iocp/win_resolver_service.hpp>
24   #endif 24   #endif
25   #endif // !BOOST_COROSIO_MRDOCS 25   #endif // !BOOST_COROSIO_MRDOCS
26   26  
27   namespace boost::corosio { 27   namespace boost::corosio {
28   28  
29   /** An asynchronous DNS resolver with devirtualized operations. 29   /** An asynchronous DNS resolver with devirtualized operations.
30   30  
31   This class template inherits from @ref resolver and shadows 31   This class template inherits from @ref resolver and shadows
32   the `resolve` operations with versions that call the backend 32   the `resolve` operations with versions that call the backend
33   implementation directly, allowing the compiler to inline 33   implementation directly, allowing the compiler to inline
34   through the entire call chain. 34   through the entire call chain.
35   35  
36   Non-async operations (`cancel`) remain unchanged and dispatch 36   Non-async operations (`cancel`) remain unchanged and dispatch
37   through the compiled library. 37   through the compiled library.
38   38  
39   A `native_resolver` IS-A `resolver` and can be passed to any 39   A `native_resolver` IS-A `resolver` and can be passed to any
40   function expecting `resolver&`. 40   function expecting `resolver&`.
41   41  
42   @tparam Backend A backend tag value (e.g., `epoll`). 42   @tparam Backend A backend tag value (e.g., `epoll`).
43   43  
44   @par Thread Safety 44   @par Thread Safety
45   Same as @ref resolver. 45   Same as @ref resolver.
46   46  
47   @see resolver, epoll_t, iocp_t 47   @see resolver, epoll_t, iocp_t
48   */ 48   */
49   template<auto Backend> 49   template<auto Backend>
50   class native_resolver : public resolver 50   class native_resolver : public resolver
51   { 51   {
52   using backend_type = decltype(Backend); 52   using backend_type = decltype(Backend);
53   using impl_type = typename backend_type::resolver_type; 53   using impl_type = typename backend_type::resolver_type;
54   54  
HITCBC 55   2 impl_type& get_impl() noexcept 55   2 impl_type& get_impl() noexcept
56   { 56   {
HITCBC 57   2 return *static_cast<impl_type*>(h_.get()); 57   2 return *static_cast<impl_type*>(h_.get());
58   } 58   }
59   59  
60   struct native_resolve_awaitable 60   struct native_resolve_awaitable
61   { 61   {
62   native_resolver& self_; 62   native_resolver& self_;
63   std::string host_; 63   std::string host_;
64   std::string service_; 64   std::string service_;
65   resolve_flags flags_; 65   resolve_flags flags_;
66   std::stop_token token_; 66   std::stop_token token_;
67   mutable std::error_code ec_; 67   mutable std::error_code ec_;
68   mutable resolver_results results_; 68   mutable resolver_results results_;
69   69  
HITCBC 70   2 native_resolve_awaitable( 70   2 native_resolve_awaitable(
71   native_resolver& self, 71   native_resolver& self,
72   std::string_view host, 72   std::string_view host,
73   std::string_view service, 73   std::string_view service,
74   resolve_flags flags) noexcept 74   resolve_flags flags) noexcept
HITCBC 75   2 : self_(self) 75   2 : self_(self)
HITCBC 76   4 , host_(host) 76   4 , host_(host)
HITCBC 77   4 , service_(service) 77   4 , service_(service)
HITCBC 78   2 , flags_(flags) 78   2 , flags_(flags)
79   { 79   {
HITCBC 80   2 } 80   2 }
81   81  
HITCBC 82   2 bool await_ready() const noexcept 82   2 bool await_ready() const noexcept
83   { 83   {
HITCBC 84   2 return token_.stop_requested(); 84   2 return token_.stop_requested();
85   } 85   }
86   86  
HITCBC 87   2 capy::io_result<resolver_results> await_resume() const noexcept 87   2 capy::io_result<resolver_results> await_resume() const noexcept
88   { 88   {
HITCBC 89   2 if (token_.stop_requested()) 89   2 if (token_.stop_requested())
MISUBC 90   return {make_error_code(std::errc::operation_canceled), {}}; 90   return {make_error_code(std::errc::operation_canceled), {}};
HITCBC 91   2 return {ec_, std::move(results_)}; 91   2 return {ec_, std::move(results_)};
92   } 92   }
93   93  
HITCBC 94   2 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env) 94   2 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
95   -> std::coroutine_handle<> 95   -> std::coroutine_handle<>
96   { 96   {
HITCBC 97   2 token_ = env->stop_token; 97   2 token_ = env->stop_token;
HITCBC 98   6 return self_.get_impl().resolve( 98   6 return self_.get_impl().resolve(
HITCBC 99   2 h, env->executor, host_, service_, flags_, token_, &ec_, 99   2 h, env->executor, host_, service_, flags_, token_, &ec_,
HITCBC 100   4 &results_); 100   4 &results_);
101   } 101   }
102   }; 102   };
103   103  
104   struct native_reverse_awaitable 104   struct native_reverse_awaitable
105   { 105   {
106   native_resolver& self_; 106   native_resolver& self_;
107   endpoint ep_; 107   endpoint ep_;
108   reverse_flags flags_; 108   reverse_flags flags_;
109   std::stop_token token_; 109   std::stop_token token_;
110   mutable std::error_code ec_; 110   mutable std::error_code ec_;
111   mutable reverse_resolver_result result_; 111   mutable reverse_resolver_result result_;
112   112  
113   native_reverse_awaitable( 113   native_reverse_awaitable(
114   native_resolver& self, 114   native_resolver& self,
115   endpoint const& ep, 115   endpoint const& ep,
116   reverse_flags flags) noexcept 116   reverse_flags flags) noexcept
117   : self_(self) 117   : self_(self)
118   , ep_(ep) 118   , ep_(ep)
119   , flags_(flags) 119   , flags_(flags)
120   { 120   {
121   } 121   }
122   122  
123   bool await_ready() const noexcept 123   bool await_ready() const noexcept
124   { 124   {
125   return token_.stop_requested(); 125   return token_.stop_requested();
126   } 126   }
127   127  
128   capy::io_result<reverse_resolver_result> await_resume() const noexcept 128   capy::io_result<reverse_resolver_result> await_resume() const noexcept
129   { 129   {
130   if (token_.stop_requested()) 130   if (token_.stop_requested())
131   return {make_error_code(std::errc::operation_canceled), {}}; 131   return {make_error_code(std::errc::operation_canceled), {}};
132   return {ec_, std::move(result_)}; 132   return {ec_, std::move(result_)};
133   } 133   }
134   134  
135   auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env) 135   auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
136   -> std::coroutine_handle<> 136   -> std::coroutine_handle<>
137   { 137   {
138   token_ = env->stop_token; 138   token_ = env->stop_token;
139   return self_.get_impl().reverse_resolve( 139   return self_.get_impl().reverse_resolve(
140   h, env->executor, ep_, flags_, token_, &ec_, &result_); 140   h, env->executor, ep_, flags_, token_, &ec_, &result_);
141   } 141   }
142   }; 142   };
143   143  
144   public: 144   public:
145   /** Construct a native resolver from an execution context. 145   /** Construct a native resolver from an execution context.
146   146  
147   @param ctx The execution context that will own this resolver. 147   @param ctx The execution context that will own this resolver.
148   */ 148   */
HITCBC 149   6 explicit native_resolver(capy::execution_context& ctx) : resolver(ctx) {} 149   6 explicit native_resolver(capy::execution_context& ctx) : resolver(ctx) {}
150   150  
151   /** Construct a native resolver from an executor. 151   /** Construct a native resolver from an executor.
152   152  
153   @param ex The executor whose context will own the resolver. 153   @param ex The executor whose context will own the resolver.
154   */ 154   */
155   template<class Ex> 155   template<class Ex>
156   requires(!std::same_as<std::remove_cvref_t<Ex>, native_resolver>) && 156   requires(!std::same_as<std::remove_cvref_t<Ex>, native_resolver>) &&
157   capy::Executor<Ex> 157   capy::Executor<Ex>
158   explicit native_resolver(Ex const& ex) : native_resolver(ex.context()) 158   explicit native_resolver(Ex const& ex) : native_resolver(ex.context())
159   { 159   {
160   } 160   }
161   161  
162   /** Move construct. 162   /** Move construct.
163   163  
164   @pre No awaitables returned by @p other's `resolve` methods 164   @pre No awaitables returned by @p other's `resolve` methods
165   exist. 165   exist.
166   @pre The execution context associated with @p other must 166   @pre The execution context associated with @p other must
167   outlive this resolver. 167   outlive this resolver.
168   */ 168   */
169   native_resolver(native_resolver&&) noexcept = default; 169   native_resolver(native_resolver&&) noexcept = default;
170   170  
171   /** Move assign. 171   /** Move assign.
172   172  
173   @pre No awaitables returned by either `*this` or the source's 173   @pre No awaitables returned by either `*this` or the source's
174   `resolve` methods exist. 174   `resolve` methods exist.
175   @pre The execution context associated with the source must 175   @pre The execution context associated with the source must
176   outlive this resolver. 176   outlive this resolver.
177   */ 177   */
178   native_resolver& operator=(native_resolver&&) noexcept = default; 178   native_resolver& operator=(native_resolver&&) noexcept = default;
179   179  
180   native_resolver(native_resolver const&) = delete; 180   native_resolver(native_resolver const&) = delete;
181   native_resolver& operator=(native_resolver const&) = delete; 181   native_resolver& operator=(native_resolver const&) = delete;
182   182  
183   /** Asynchronously resolve a host and service to endpoints. 183   /** Asynchronously resolve a host and service to endpoints.
184   184  
185   Calls the backend implementation directly, bypassing virtual 185   Calls the backend implementation directly, bypassing virtual
186   dispatch. Otherwise identical to @ref resolver::resolve. 186   dispatch. Otherwise identical to @ref resolver::resolve.
187   187  
188   This resolver must outlive the returned awaitable. 188   This resolver must outlive the returned awaitable.
189   189  
190   @param host The host name or address string. 190   @param host The host name or address string.
191   @param service The service name or port string. 191   @param service The service name or port string.
192   192  
193   @return An awaitable yielding `io_result<resolver_results>`. 193   @return An awaitable yielding `io_result<resolver_results>`.
194   */ 194   */
HITCBC 195   2 auto resolve(std::string_view host, std::string_view service) 195   2 auto resolve(std::string_view host, std::string_view service)
196   { 196   {
197   return native_resolve_awaitable( 197   return native_resolve_awaitable(
HITCBC 198   2 *this, host, service, resolve_flags::none); 198   2 *this, host, service, resolve_flags::none);
199   } 199   }
200   200  
201   /** Asynchronously resolve a host and service with flags. 201   /** Asynchronously resolve a host and service with flags.
202   202  
203   This resolver must outlive the returned awaitable. 203   This resolver must outlive the returned awaitable.
204   204  
205   @param host The host name or address string. 205   @param host The host name or address string.
206   @param service The service name or port string. 206   @param service The service name or port string.
207   @param flags Flags controlling resolution behavior. 207   @param flags Flags controlling resolution behavior.
208   208  
209   @return An awaitable yielding `io_result<resolver_results>`. 209   @return An awaitable yielding `io_result<resolver_results>`.
210   */ 210   */
211   auto resolve( 211   auto resolve(
212   std::string_view host, std::string_view service, resolve_flags flags) 212   std::string_view host, std::string_view service, resolve_flags flags)
213   { 213   {
214   return native_resolve_awaitable(*this, host, service, flags); 214   return native_resolve_awaitable(*this, host, service, flags);
215   } 215   }
216   216  
217   /** Asynchronously reverse-resolve an endpoint. 217   /** Asynchronously reverse-resolve an endpoint.
218   218  
219   Calls the backend implementation directly, bypassing virtual 219   Calls the backend implementation directly, bypassing virtual
220   dispatch. Otherwise identical to the endpoint overload of 220   dispatch. Otherwise identical to the endpoint overload of
221   @ref resolver::resolve. 221   @ref resolver::resolve.
222   222  
223   This resolver must outlive the returned awaitable. 223   This resolver must outlive the returned awaitable.
224   224  
225   @param ep The endpoint to resolve. 225   @param ep The endpoint to resolve.
226   226  
227   @return An awaitable yielding 227   @return An awaitable yielding
228   `io_result<reverse_resolver_result>`. 228   `io_result<reverse_resolver_result>`.
229   */ 229   */
230   auto resolve(endpoint const& ep) 230   auto resolve(endpoint const& ep)
231   { 231   {
232   return native_reverse_awaitable(*this, ep, reverse_flags::none); 232   return native_reverse_awaitable(*this, ep, reverse_flags::none);
233   } 233   }
234   234  
235   /** Asynchronously reverse-resolve an endpoint with flags. 235   /** Asynchronously reverse-resolve an endpoint with flags.
236   236  
237   This resolver must outlive the returned awaitable. 237   This resolver must outlive the returned awaitable.
238   238  
239   @param ep The endpoint to resolve. 239   @param ep The endpoint to resolve.
240   @param flags Flags controlling resolution behavior. 240   @param flags Flags controlling resolution behavior.
241   241  
242   @return An awaitable yielding 242   @return An awaitable yielding
243   `io_result<reverse_resolver_result>`. 243   `io_result<reverse_resolver_result>`.
244   */ 244   */
245   auto resolve(endpoint const& ep, reverse_flags flags) 245   auto resolve(endpoint const& ep, reverse_flags flags)
246   { 246   {
247   return native_reverse_awaitable(*this, ep, flags); 247   return native_reverse_awaitable(*this, ep, flags);
248   } 248   }
249   }; 249   };
250   250  
251   } // namespace boost::corosio 251   } // namespace boost::corosio
252   252  
253   #endif 253   #endif