TLA Line data 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 HIT 2 : impl_type& get_impl() noexcept
56 : {
57 2 : 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 2 : native_resolve_awaitable(
71 : native_resolver& self,
72 : std::string_view host,
73 : std::string_view service,
74 : resolve_flags flags) noexcept
75 2 : : self_(self)
76 4 : , host_(host)
77 4 : , service_(service)
78 2 : , flags_(flags)
79 : {
80 2 : }
81 :
82 2 : bool await_ready() const noexcept
83 : {
84 2 : return token_.stop_requested();
85 : }
86 :
87 2 : capy::io_result<resolver_results> await_resume() const noexcept
88 : {
89 2 : if (token_.stop_requested())
90 MIS 0 : return {make_error_code(std::errc::operation_canceled), {}};
91 HIT 2 : return {ec_, std::move(results_)};
92 : }
93 :
94 2 : auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
95 : -> std::coroutine_handle<>
96 : {
97 2 : token_ = env->stop_token;
98 6 : return self_.get_impl().resolve(
99 2 : h, env->executor, host_, service_, flags_, token_, &ec_,
100 4 : &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 6 : 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 2 : auto resolve(std::string_view host, std::string_view service)
196 : {
197 : return native_resolve_awaitable(
198 2 : *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
|