include/boost/corosio/native/native_resolver.hpp

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