include/boost/corosio/native/native_resolver.hpp

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