include/boost/corosio/resolver.hpp

100.0% Lines (54/0/54) 100.0% List of functions (20/0/20)
resolver.hpp
f(x) Functions (20)
Function Calls Lines Blocks
boost::corosio::operator|(boost::corosio::resolve_flags, boost::corosio::resolve_flags) :74 17x 100.0% 100.0% boost::corosio::operator|=(boost::corosio::resolve_flags&, boost::corosio::resolve_flags) :82 1x 100.0% 100.0% boost::corosio::operator&(boost::corosio::resolve_flags, boost::corosio::resolve_flags) :90 199x 100.0% 100.0% boost::corosio::operator&=(boost::corosio::resolve_flags&, boost::corosio::resolve_flags) :98 1x 100.0% 100.0% boost::corosio::operator|(boost::corosio::reverse_flags, boost::corosio::reverse_flags) :128 9x 100.0% 100.0% boost::corosio::operator|=(boost::corosio::reverse_flags&, boost::corosio::reverse_flags) :136 1x 100.0% 100.0% boost::corosio::operator&(boost::corosio::reverse_flags, boost::corosio::reverse_flags) :144 79x 100.0% 100.0% boost::corosio::operator&=(boost::corosio::reverse_flags&, boost::corosio::reverse_flags) :152 1x 100.0% 100.0% boost::corosio::resolver::resolve_awaitable::resolve_awaitable(boost::corosio::resolver&, std::basic_string_view<char, std::char_traits<char> >, std::basic_string_view<char, std::char_traits<char> >, boost::corosio::resolve_flags) :187 30x 100.0% 100.0% boost::corosio::resolver::resolve_awaitable::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :199 30x 100.0% 83.0% boost::corosio::resolver::reverse_resolve_awaitable::reverse_resolve_awaitable(boost::corosio::resolver&, boost::corosio::endpoint const&, boost::corosio::reverse_flags) :214 20x 100.0% 100.0% boost::corosio::resolver::reverse_resolve_awaitable::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :222 20x 100.0% 80.0% boost::corosio::resolver::resolver<boost::corosio::io_context::executor_type>(boost::corosio::io_context::executor_type const&) :252 1x 100.0% 100.0% boost::corosio::resolver::resolver(boost::corosio::resolver&&) :269 2x 100.0% 100.0% boost::corosio::resolver::operator=(boost::corosio::resolver&&) :286 2x 100.0% 100.0% boost::corosio::resolver::resolve(std::basic_string_view<char, std::char_traits<char> >, std::basic_string_view<char, std::char_traits<char> >) :319 14x 100.0% 100.0% boost::corosio::resolver::resolve(std::basic_string_view<char, std::char_traits<char> >, std::basic_string_view<char, std::char_traits<char> >, boost::corosio::resolve_flags) :338 16x 100.0% 100.0% boost::corosio::resolver::resolve(boost::corosio::endpoint const&) :359 11x 100.0% 100.0% boost::corosio::resolver::resolve(boost::corosio::endpoint const&, boost::corosio::reverse_flags) :378 9x 100.0% 100.0% boost::corosio::resolver::get() const :427 57x 100.0% 100.0%
Line TLA Hits Source Code
1 //
2 // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3 // Copyright (c) 2026 Steve Gerbino
4 // Copyright (c) 2026 Michael Vandeberg
5 //
6 // Distributed under the Boost Software License, Version 1.0. (See accompanying
7 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 //
9 // Official repository: https://github.com/cppalliance/corosio
10 //
11
12 #ifndef BOOST_COROSIO_RESOLVER_HPP
13 #define BOOST_COROSIO_RESOLVER_HPP
14
15 #include <boost/corosio/detail/config.hpp>
16 #include <boost/corosio/detail/op_base.hpp>
17 #include <boost/corosio/endpoint.hpp>
18 #include <boost/corosio/io/io_object.hpp>
19 #include <boost/capy/io_result.hpp>
20 #include <boost/corosio/resolver_results.hpp>
21 #include <boost/capy/ex/executor_ref.hpp>
22 #include <boost/capy/ex/execution_context.hpp>
23 #include <boost/capy/ex/io_env.hpp>
24 #include <boost/capy/concept/executor.hpp>
25
26 #include <system_error>
27
28 #include <cassert>
29 #include <concepts>
30 #include <coroutine>
31 #include <stop_token>
32 #include <string>
33 #include <string_view>
34 #include <type_traits>
35
36 namespace boost::corosio {
37
38 /** Bitmask flags for resolver queries.
39
40 These flags correspond to the hints parameter of getaddrinfo.
41 */
42 enum class resolve_flags : unsigned int
43 {
44 /// No flags.
45 none = 0,
46
47 /// Indicate that returned endpoint is intended for use as a locally
48 /// bound socket endpoint.
49 passive = 0x01,
50
51 /// Host name should be treated as a numeric string defining an IPv4
52 /// or IPv6 address and no name resolution should be attempted.
53 numeric_host = 0x04,
54
55 /// Service name should be treated as a numeric string defining a port
56 /// number and no name resolution should be attempted.
57 numeric_service = 0x08,
58
59 /// Only return IPv4 addresses if a non-loopback IPv4 address is
60 /// configured for the system. Only return IPv6 addresses if a
61 /// non-loopback IPv6 address is configured for the system.
62 address_configured = 0x20,
63
64 /// If the query protocol family is specified as IPv6, return
65 /// IPv4-mapped IPv6 addresses on finding no IPv6 addresses.
66 v4_mapped = 0x800,
67
68 /// If used with v4_mapped, return all matching IPv6 and IPv4 addresses.
69 all_matching = 0x100
70 };
71
72 /** Combine two resolve_flags. */
73 inline resolve_flags
74 17x operator|(resolve_flags a, resolve_flags b) noexcept
75 {
76 return static_cast<resolve_flags>(
77 17x static_cast<unsigned int>(a) | static_cast<unsigned int>(b));
78 }
79
80 /** Combine two resolve_flags. */
81 inline resolve_flags&
82 1x operator|=(resolve_flags& a, resolve_flags b) noexcept
83 {
84 1x a = a | b;
85 1x return a;
86 }
87
88 /** Intersect two resolve_flags. */
89 inline resolve_flags
90 199x operator&(resolve_flags a, resolve_flags b) noexcept
91 {
92 return static_cast<resolve_flags>(
93 199x static_cast<unsigned int>(a) & static_cast<unsigned int>(b));
94 }
95
96 /** Intersect two resolve_flags. */
97 inline resolve_flags&
98 1x operator&=(resolve_flags& a, resolve_flags b) noexcept
99 {
100 1x a = a & b;
101 1x return a;
102 }
103
104 /** Bitmask flags for reverse resolver queries.
105
106 These flags correspond to the flags parameter of getnameinfo.
107 */
108 enum class reverse_flags : unsigned int
109 {
110 /// No flags.
111 none = 0,
112
113 /// Return the numeric form of the hostname instead of its name.
114 numeric_host = 0x01,
115
116 /// Return the numeric form of the service name instead of its name.
117 numeric_service = 0x02,
118
119 /// Return an error if the hostname cannot be resolved.
120 name_required = 0x04,
121
122 /// Lookup for datagram (UDP) service instead of stream (TCP).
123 datagram_service = 0x08
124 };
125
126 /** Combine two reverse_flags. */
127 inline reverse_flags
128 9x operator|(reverse_flags a, reverse_flags b) noexcept
129 {
130 return static_cast<reverse_flags>(
131 9x static_cast<unsigned int>(a) | static_cast<unsigned int>(b));
132 }
133
134 /** Combine two reverse_flags. */
135 inline reverse_flags&
136 1x operator|=(reverse_flags& a, reverse_flags b) noexcept
137 {
138 1x a = a | b;
139 1x return a;
140 }
141
142 /** Intersect two reverse_flags. */
143 inline reverse_flags
144 79x operator&(reverse_flags a, reverse_flags b) noexcept
145 {
146 return static_cast<reverse_flags>(
147 79x static_cast<unsigned int>(a) & static_cast<unsigned int>(b));
148 }
149
150 /** Intersect two reverse_flags. */
151 inline reverse_flags&
152 1x operator&=(reverse_flags& a, reverse_flags b) noexcept
153 {
154 1x a = a & b;
155 1x return a;
156 }
157
158 /** An asynchronous DNS resolver for coroutine I/O.
159
160 This class provides asynchronous DNS resolution operations that return
161 awaitable types. Each operation participates in the affine awaitable
162 protocol, ensuring coroutines resume on the correct executor.
163
164 @par Thread Safety
165 Distinct objects: Safe.@n
166 Shared objects: Unsafe. A resolver must not have concurrent resolve
167 operations.
168
169 @par Semantics
170 Wraps platform DNS resolution (getaddrinfo/getnameinfo).
171 Operations dispatch to OS resolver APIs via the io_context
172 thread pool.
173
174 @par Example
175 @par !example resolver
176 */
177 class BOOST_COROSIO_DECL resolver : public io_object
178 {
179 struct resolve_awaitable
180 : detail::value_op_base<resolve_awaitable, resolver_results>
181 {
182 resolver& r_;
183 std::string host_;
184 std::string service_;
185 resolve_flags flags_;
186
187 30x resolve_awaitable(
188 resolver& r,
189 std::string_view host,
190 std::string_view service,
191 resolve_flags flags) noexcept
192 60x : r_(r)
193 60x , host_(host)
194 60x , service_(service)
195 30x , flags_(flags)
196 {
197 30x }
198
199 30x std::coroutine_handle<> dispatch(
200 std::coroutine_handle<> h, capy::executor_ref ex) const
201 {
202 90x return r_.get().resolve(
203 90x h, ex, host_, service_, flags_, token_, &ec_, &value_);
204 }
205 };
206
207 struct reverse_resolve_awaitable
208 : detail::value_op_base<reverse_resolve_awaitable, reverse_resolver_result>
209 {
210 resolver& r_;
211 endpoint ep_;
212 reverse_flags flags_;
213
214 20x reverse_resolve_awaitable(
215 resolver& r, endpoint const& ep, reverse_flags flags) noexcept
216 40x : r_(r)
217 20x , ep_(ep)
218 20x , flags_(flags)
219 {
220 20x }
221
222 20x std::coroutine_handle<> dispatch(
223 std::coroutine_handle<> h, capy::executor_ref ex) const
224 {
225 40x return r_.get().reverse_resolve(
226 40x h, ex, ep_, flags_, token_, &ec_, &value_);
227 }
228 };
229
230 public:
231 /** Destructor.
232
233 Cancels any pending operations.
234 */
235 ~resolver() override;
236
237 /** Construct a resolver from an execution context.
238
239 @param ctx The execution context that will own this resolver.
240 */
241 explicit resolver(capy::execution_context& ctx);
242
243 /** Construct a resolver from an executor.
244
245 The resolver is associated with the executor's context.
246
247 @param ex The executor whose context will own the resolver.
248 */
249 template<class Ex>
250 requires(!std::same_as<std::remove_cvref_t<Ex>, resolver>) &&
251 capy::Executor<Ex>
252 1x explicit resolver(Ex const& ex) : resolver(ex.context())
253 {
254 1x }
255
256 /** Move constructor.
257
258 Transfers ownership of the resolver resources. After the move,
259 @p other is in a moved-from state and may only be destroyed or
260 assigned to.
261
262 @param other The resolver to move from.
263
264 @pre No awaitables returned by @p other's `resolve` methods
265 exist.
266 @pre The execution context associated with @p other must
267 outlive this resolver.
268 */
269 2x resolver(resolver&& other) noexcept : io_object(std::move(other)) {}
270
271 /** Move assignment operator.
272
273 Destroys the current implementation and transfers ownership
274 from @p other. After the move, @p other is in a moved-from
275 state and may only be destroyed or assigned to.
276
277 @param other The resolver to move from.
278
279 @pre No awaitables returned by either `*this` or @p other's
280 `resolve` methods exist.
281 @pre The execution context associated with @p other must
282 outlive this resolver.
283
284 @return Reference to this resolver.
285 */
286 2x resolver& operator=(resolver&& other) noexcept
287 {
288 2x if (this != &other)
289 2x h_ = std::move(other.h_);
290 2x return *this;
291 }
292
293 resolver(resolver const&) = delete;
294 resolver& operator=(resolver const&) = delete;
295
296 /** Initiate an asynchronous resolve operation.
297
298 Resolves the host and service names into a list of endpoints.
299
300 This resolver must outlive the returned awaitable.
301
302 @param host A string identifying a location. May be a descriptive
303 name or a numeric address string.
304
305 @param service A string identifying the requested service. This may
306 be a descriptive name or a numeric string corresponding to a
307 port number.
308
309 @return An awaitable that completes with `io_result<resolver_results>`.
310
311 @note `resolver_results` is an alias for `std::vector<resolver_entry>`.
312 Copying it deep-copies every entry (each owns two `std::string`s);
313 move it (`std::move(results)`) or pass iterators when handing it to
314 a by-value sink such as @ref connect.
315
316 @par Example
317 @par !example forward_resolve
318 */
319 14x [[nodiscard]] auto resolve(std::string_view host, std::string_view service)
320 {
321 14x return resolve_awaitable(*this, host, service, resolve_flags::none);
322 }
323
324 /** Initiate an asynchronous resolve operation with flags.
325
326 Resolves the host and service names into a list of endpoints.
327
328 This resolver must outlive the returned awaitable.
329
330 @param host A string identifying a location.
331
332 @param service A string identifying the requested service.
333
334 @param flags Flags controlling resolution behavior.
335
336 @return An awaitable that completes with `io_result<resolver_results>`.
337 */
338 16x [[nodiscard]] auto resolve(
339 std::string_view host, std::string_view service, resolve_flags flags)
340 {
341 16x return resolve_awaitable(*this, host, service, flags);
342 }
343
344 /** Initiate an asynchronous reverse resolve operation.
345
346 Resolves an endpoint into a hostname and service name using
347 reverse DNS lookup (PTR record query).
348
349 This resolver must outlive the returned awaitable.
350
351 @param ep The endpoint to resolve.
352
353 @return An awaitable that completes with
354 `io_result<reverse_resolver_result>`.
355
356 @par Example
357 @par !example reverse_resolve
358 */
359 11x [[nodiscard]] auto resolve(endpoint const& ep)
360 {
361 11x return reverse_resolve_awaitable(*this, ep, reverse_flags::none);
362 }
363
364 /** Initiate an asynchronous reverse resolve operation with flags.
365
366 Resolves an endpoint into a hostname and service name using
367 reverse DNS lookup (PTR record query).
368
369 This resolver must outlive the returned awaitable.
370
371 @param ep The endpoint to resolve.
372
373 @param flags Flags controlling resolution behavior. See reverse_flags.
374
375 @return An awaitable that completes with
376 `io_result<reverse_resolver_result>`.
377 */
378 9x [[nodiscard]] auto resolve(endpoint const& ep, reverse_flags flags)
379 {
380 9x return reverse_resolve_awaitable(*this, ep, flags);
381 }
382
383 /** Cancel any pending asynchronous operations.
384
385 All outstanding operations complete with `errc::operation_canceled`.
386 Check `ec == cond::canceled` for portable comparison.
387 */
388 void cancel() noexcept;
389
390 public:
391 /** Backend interface for DNS resolution operations.
392
393 Platform backends derive from this to implement forward and
394 reverse DNS resolution via getaddrinfo/getnameinfo.
395 */
396 struct implementation : io_object::implementation
397 {
398 /// Initiate an asynchronous forward DNS resolution.
399 virtual std::coroutine_handle<> resolve(
400 std::coroutine_handle<>,
401 capy::executor_ref,
402 std::string_view host,
403 std::string_view service,
404 resolve_flags flags,
405 std::stop_token,
406 std::error_code*,
407 resolver_results*) = 0;
408
409 /// Initiate an asynchronous reverse DNS resolution.
410 virtual std::coroutine_handle<> reverse_resolve(
411 std::coroutine_handle<>,
412 capy::executor_ref,
413 endpoint const& ep,
414 reverse_flags flags,
415 std::stop_token,
416 std::error_code*,
417 reverse_resolver_result*) = 0;
418
419 /// Cancel pending resolve operations.
420 virtual void cancel() noexcept = 0;
421 };
422
423 protected:
424 explicit resolver(handle h) noexcept : io_object(std::move(h)) {}
425
426 private:
427 57x inline implementation& get() const noexcept
428 {
429 57x return *static_cast<implementation*>(h_.get());
430 }
431 };
432
433 } // namespace boost::corosio
434
435 #endif
436