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