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