96.25% Lines (77/80) 100.00% Functions (25/25)
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/corosio/resolver_results.hpp>  
20   #include <boost/capy/io_result.hpp> 19   #include <boost/capy/io_result.hpp>
21   #include <boost/capy/ex/executor_ref.hpp> 20   #include <boost/capy/ex/executor_ref.hpp>
22   #include <boost/capy/ex/execution_context.hpp> 21   #include <boost/capy/ex/execution_context.hpp>
23   #include <boost/capy/ex/io_env.hpp> 22   #include <boost/capy/ex/io_env.hpp>
24   #include <boost/capy/concept/executor.hpp> 23   #include <boost/capy/concept/executor.hpp>
25   24  
26   #include <system_error> 25   #include <system_error>
27   26  
28   #include <cassert> 27   #include <cassert>
29   #include <concepts> 28   #include <concepts>
30   #include <coroutine> 29   #include <coroutine>
31   #include <stop_token> 30   #include <stop_token>
32   #include <string> 31   #include <string>
33   #include <string_view> 32   #include <string_view>
  33 + #include <vector>
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   181 operator&(resolve_flags a, resolve_flags b) noexcept 90   205 operator&(resolve_flags a, resolve_flags b) noexcept
91   { 91   {
92   return static_cast<resolve_flags>( 92   return static_cast<resolve_flags>(
HITCBC 93   181 static_cast<unsigned int>(a) & static_cast<unsigned int>(b)); 93   205 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   75 operator&(reverse_flags a, reverse_flags b) noexcept 144   75 operator&(reverse_flags a, reverse_flags b) noexcept
145   { 145   {
146   return static_cast<reverse_flags>( 146   return static_cast<reverse_flags>(
HITCBC 147   75 static_cast<unsigned int>(a) & static_cast<unsigned int>(b)); 147   75 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 + /** The name of an endpoint.
  159 +
  160 + Reverse resolution translates an endpoint into its symbolic
  161 + spelling: the host name and the service name. Both fields carry
  162 + resolved data; the endpoint they name is the one the caller
  163 + passed to `resolve`.
  164 + */
  165 + struct endpoint_name
  166 + {
  167 + /// The resolved host name.
  168 + std::string host_name;
  169 +
  170 + /// The resolved service name.
  171 + std::string service_name;
  172 + };
  173 +
158   /** An asynchronous DNS resolver for coroutine I/O. 174   /** An asynchronous DNS resolver for coroutine I/O.
159   175  
160   This class provides asynchronous DNS resolution operations that return 176   This class provides asynchronous DNS resolution operations that return
161   awaitable types. Each operation participates in the affine awaitable 177   awaitable types. Each operation participates in the affine awaitable
162   protocol, ensuring coroutines resume on the correct executor. 178   protocol, ensuring coroutines resume on the correct executor.
163   179  
164   @par Thread Safety 180   @par Thread Safety
165   Distinct objects: Safe.@n 181   Distinct objects: Safe.@n
166   Shared objects: Unsafe. A resolver must not have concurrent resolve 182   Shared objects: Unsafe. A resolver must not have concurrent resolve
167   operations. 183   operations.
168   184  
169   @par Semantics 185   @par Semantics
170   Wraps platform DNS resolution (getaddrinfo/getnameinfo). 186   Wraps platform DNS resolution (getaddrinfo/getnameinfo).
171   Operations dispatch to OS resolver APIs via the io_context 187   Operations dispatch to OS resolver APIs via the io_context
172   thread pool. 188   thread pool.
173   189  
174   @par Example 190   @par Example
175   @par !example resolver 191   @par !example resolver
176   */ 192   */
177   class BOOST_COROSIO_DECL resolver : public io_object 193   class BOOST_COROSIO_DECL resolver : public io_object
178   { 194   {
179   struct resolve_awaitable 195   struct resolve_awaitable
180 - : detail::value_op_base<resolve_awaitable, resolver_results> 196 + : detail::value_op_base<resolve_awaitable, std::vector<endpoint>>
181   { 197   {
182   resolver& r_; 198   resolver& r_;
183   std::string host_; 199   std::string host_;
184   std::string service_; 200   std::string service_;
185   resolve_flags flags_; 201   resolve_flags flags_;
186   202  
HITCBC 187   30 resolve_awaitable( 203   29 resolve_awaitable(
188   resolver& r, 204   resolver& r,
189   std::string_view host, 205   std::string_view host,
190   std::string_view service, 206   std::string_view service,
191   resolve_flags flags) noexcept 207   resolve_flags flags) noexcept
HITCBC 192   60 : r_(r) 208   58 : r_(r)
HITCBC 193   60 , host_(host) 209   58 , host_(host)
HITCBC 194   60 , service_(service) 210   58 , service_(service)
HITCBC 195   30 , flags_(flags) 211   29 , flags_(flags)
196   { 212   {
HITCBC 197   30 } 213   29 }
198   214  
199   std::coroutine_handle<> 215   std::coroutine_handle<>
HITCBC 200   29 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 216   28 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
201   { 217   {
HITCBC 202   87 return r_.get().resolve( 218   84 return r_.get().resolve(
HITCBC 203   87 h, ex, host_, service_, flags_, token_, &ec_, &value_); 219   84 h, ex, host_, service_, flags_, token_, &ec_, &value_);
204   } 220   }
205   }; 221   };
206   222  
  223 + struct resolve_host_awaitable
  224 + : detail::value_op_base<resolve_host_awaitable, std::vector<endpoint>>
  225 + {
  226 + resolver& r_;
  227 + std::string host_;
  228 + resolve_flags flags_;
  229 +
HITGNC   230 + 6 resolve_host_awaitable(
  231 + resolver& r, std::string_view host, resolve_flags flags) noexcept
HITGNC   232 + 12 : r_(r)
HITGNC   233 + 12 , host_(host)
HITGNC   234 + 6 , flags_(flags)
  235 + {
HITGNC   236 + 6 }
  237 +
  238 + std::coroutine_handle<>
HITGNC   239 + 5 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
  240 + {
  241 + // An empty service reaches the system resolver as null,
  242 + // which is the host-only query
HITGNC   243 + 15 return r_.get().resolve(
HITGNC   244 + 15 h, ex, host_, {}, flags_, token_, &ec_, &value_);
  245 + }
  246 +
  247 + // Shadows the base: the endpoint result is reshaped into
  248 + // the honest address list
  249 + [[nodiscard]] capy::io_result<std::vector<ip_address>>
HITGNC   250 + 6 await_resume() const
  251 + {
HITGNC   252 + 6 std::vector<ip_address> addrs;
HITGNC   253 + 6 addrs.reserve(value_.size());
HITGNC   254 + 9 for (auto const& entry : value_)
  255 + {
HITGNC   256 + 3 auto a = entry.address();
HITGNC   257 + 3 bool duplicate = false;
HITGNC   258 + 3 for (auto const& seen : addrs)
  259 + {
MISUNC   260 + ✗ if (seen == a)
  261 + {
MISUNC   262 + ✗ duplicate = true;
MISUNC   263 + ✗ break;
  264 + }
  265 + }
  266 + // The same address can come back more than once
  267 + // (mixed name sources, repeated records); each
  268 + // address is reported once
HITGNC   269 + 3 if (!duplicate)
HITGNC   270 + 3 addrs.push_back(a);
  271 + }
HITGNC   272 + 12 return {ec_, std::move(addrs)};
HITGNC   273 + 6 }
  274 + };
  275 +
207   struct reverse_resolve_awaitable 276   struct reverse_resolve_awaitable
208 - : detail:: 277 + : detail::value_op_base<reverse_resolve_awaitable, endpoint_name>
209 - value_op_base<reverse_resolve_awaitable, reverse_resolver_result>  
210   { 278   {
211   resolver& r_; 279   resolver& r_;
212   endpoint ep_; 280   endpoint ep_;
213   reverse_flags flags_; 281   reverse_flags flags_;
214   282  
HITCBC 215   20 reverse_resolve_awaitable( 283   20 reverse_resolve_awaitable(
216   resolver& r, endpoint const& ep, reverse_flags flags) noexcept 284   resolver& r, endpoint const& ep, reverse_flags flags) noexcept
HITCBC 217   40 : r_(r) 285   40 : r_(r)
HITCBC 218   20 , ep_(ep) 286   20 , ep_(ep)
HITCBC 219   20 , flags_(flags) 287   20 , flags_(flags)
220   { 288   {
HITCBC 221   20 } 289   20 }
222   290  
223   std::coroutine_handle<> 291   std::coroutine_handle<>
HITCBC 224   19 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 292   19 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
225   { 293   {
HITCBC 226   38 return r_.get().reverse_resolve( 294   38 return r_.get().reverse_resolve(
HITCBC 227   38 h, ex, ep_, flags_, token_, &ec_, &value_); 295   38 h, ex, ep_, flags_, token_, &ec_, &value_);
228   } 296   }
229   }; 297   };
230   298  
231   public: 299   public:
232   /** Destructor. 300   /** Destructor.
233   301  
234   Cancels any pending operations. 302   Cancels any pending operations.
235   */ 303   */
236   ~resolver() override; 304   ~resolver() override;
237   305  
238   /** Construct a resolver from an execution context. 306   /** Construct a resolver from an execution context.
239   307  
240   @param ctx The execution context that will own this resolver. 308   @param ctx The execution context that will own this resolver.
241   */ 309   */
242   explicit resolver(capy::execution_context& ctx); 310   explicit resolver(capy::execution_context& ctx);
243   311  
244   /** Construct a resolver from an executor. 312   /** Construct a resolver from an executor.
245   313  
246   The resolver is associated with the executor's context. 314   The resolver is associated with the executor's context.
247   315  
248   @param ex The executor whose context will own the resolver. 316   @param ex The executor whose context will own the resolver.
249   */ 317   */
250   template<class Ex> 318   template<class Ex>
251   requires(!std::same_as<std::remove_cvref_t<Ex>, resolver>) && 319   requires(!std::same_as<std::remove_cvref_t<Ex>, resolver>) &&
252   capy::Executor<Ex> 320   capy::Executor<Ex>
HITCBC 253   1 explicit resolver(Ex const& ex) : resolver(ex.context()) 321   1 explicit resolver(Ex const& ex) : resolver(ex.context())
254   { 322   {
HITCBC 255   1 } 323   1 }
256   324  
257   /** Move constructor. 325   /** Move constructor.
258   326  
259   Transfers ownership of the resolver resources. After the move, 327   Transfers ownership of the resolver resources. After the move,
260   @p other is in a moved-from state and may only be destroyed or 328   @p other is in a moved-from state and may only be destroyed or
261   assigned to. 329   assigned to.
262   330  
263   @param other The resolver to move from. 331   @param other The resolver to move from.
264   332  
265   @pre No awaitables returned by @p other's `resolve` methods 333   @pre No awaitables returned by @p other's `resolve` methods
266   exist. 334   exist.
267   @pre The execution context associated with @p other must 335   @pre The execution context associated with @p other must
268   outlive this resolver. 336   outlive this resolver.
269   */ 337   */
HITCBC 270   2 resolver(resolver&& other) noexcept : io_object(std::move(other)) {} 338   2 resolver(resolver&& other) noexcept : io_object(std::move(other)) {}
271   339  
272   /** Move assignment operator. 340   /** Move assignment operator.
273   341  
274   Destroys the current implementation and transfers ownership 342   Destroys the current implementation and transfers ownership
275   from @p other. After the move, @p other is in a moved-from 343   from @p other. After the move, @p other is in a moved-from
276   state and may only be destroyed or assigned to. 344   state and may only be destroyed or assigned to.
277   345  
278   @param other The resolver to move from. 346   @param other The resolver to move from.
279   347  
280   @pre No awaitables returned by either `*this` or @p other's 348   @pre No awaitables returned by either `*this` or @p other's
281   `resolve` methods exist. 349   `resolve` methods exist.
282   @pre The execution context associated with @p other must 350   @pre The execution context associated with @p other must
283   outlive this resolver. 351   outlive this resolver.
284   352  
285   @return Reference to this resolver. 353   @return Reference to this resolver.
286   */ 354   */
HITCBC 287   2 resolver& operator=(resolver&& other) noexcept 355   2 resolver& operator=(resolver&& other) noexcept
288   { 356   {
HITCBC 289   2 if (this != &other) 357   2 if (this != &other)
HITCBC 290   2 h_ = std::move(other.h_); 358   2 h_ = std::move(other.h_);
HITCBC 291   2 return *this; 359   2 return *this;
292   } 360   }
293   361  
294   resolver(resolver const&) = delete; 362   resolver(resolver const&) = delete;
295   resolver& operator=(resolver const&) = delete; 363   resolver& operator=(resolver const&) = delete;
296   364  
297   /** Initiate an asynchronous resolve operation. 365   /** Initiate an asynchronous resolve operation.
298   366  
299   Resolves the host and service names into a list of endpoints. 367   Resolves the host and service names into a list of endpoints.
300   368  
301   This resolver must outlive the returned awaitable. 369   This resolver must outlive the returned awaitable.
302   370  
303   @param host A string identifying a location. May be a descriptive 371   @param host A string identifying a location. May be a descriptive
304   name or a numeric address string. 372   name or a numeric address string.
305   373  
306   @param service A string identifying the requested service. This may 374   @param service A string identifying the requested service. This may
307   be a descriptive name or a numeric string corresponding to a 375   be a descriptive name or a numeric string corresponding to a
308   port number. 376   port number.
309   377  
310 - @return An awaitable that completes with `io_result<resolver_results>`. 378 + @return An awaitable that completes with
311 - 379 + `io_result<std::vector<endpoint>>`.
312 - @note `resolver_results` is an alias for `std::vector<resolver_entry>`.  
313 - Copying it deep-copies every entry (each owns two `std::string`s);  
314 - move it (`std::move(results)`) or pass iterators when handing it to  
315 - a by-value sink such as @ref connect.  
316   380  
317   @par Example 381   @par Example
318   @par !example forward_resolve 382   @par !example forward_resolve
319   */ 383   */
HITCBC 320   14 [[nodiscard]] auto resolve(std::string_view host, std::string_view service) 384   13 [[nodiscard]] auto resolve(std::string_view host, std::string_view service)
321   { 385   {
HITCBC 322   14 return resolve_awaitable(*this, host, service, resolve_flags::none); 386   13 return resolve_awaitable(*this, host, service, resolve_flags::none);
323   } 387   }
324   388  
  389 + /** Initiate an asynchronous host-only resolve operation.
  390 +
  391 + Resolves a host name into its addresses, with no service or
  392 + port involved — the query `getaddrinfo` performs with a null
  393 + service. Use this when the host and port travel separately,
  394 + as they do in most configuration.
  395 +
  396 + Each address appears once in the result even when the query
  397 + reports it more than once, and link-local results keep
  398 + their zone.
  399 +
  400 + @param host The host name or numeric address string.
  401 +
  402 + @return An awaitable that completes with
  403 + `io_result<std::vector<ip_address>>`.
  404 +
  405 + @par Example
  406 + @par !example host_only_resolve
  407 + */
HITGNC   408 + 3 [[nodiscard]] auto resolve(std::string_view host)
  409 + {
HITGNC   410 + 3 return resolve_host_awaitable(*this, host, resolve_flags::none);
  411 + }
  412 +
  413 + /** Initiate an asynchronous host-only resolve operation with flags.
  414 +
  415 + @param host The host name or numeric address string.
  416 + @param flags Resolution behavior flags.
  417 +
  418 + @return An awaitable that completes with
  419 + `io_result<std::vector<ip_address>>`.
  420 + */
HITGNC   421 + 3 [[nodiscard]] auto resolve(std::string_view host, resolve_flags flags)
  422 + {
HITGNC   423 + 3 return resolve_host_awaitable(*this, host, flags);
  424 + }
  425 +
325   /** Initiate an asynchronous resolve operation with flags. 426   /** Initiate an asynchronous resolve operation with flags.
326   427  
327   Resolves the host and service names into a list of endpoints. 428   Resolves the host and service names into a list of endpoints.
328   429  
329   This resolver must outlive the returned awaitable. 430   This resolver must outlive the returned awaitable.
330   431  
331   @param host A string identifying a location. 432   @param host A string identifying a location.
332   433  
333   @param service A string identifying the requested service. 434   @param service A string identifying the requested service.
334   435  
335   @param flags Flags controlling resolution behavior. 436   @param flags Flags controlling resolution behavior.
336   437  
337 - @return An awaitable that completes with `io_result<resolver_results>`. 438 + @return An awaitable that completes with
  439 + `io_result<std::vector<endpoint>>`.
338   */ 440   */
HITCBC 339   16 [[nodiscard]] auto resolve( 441   16 [[nodiscard]] auto resolve(
340   std::string_view host, std::string_view service, resolve_flags flags) 442   std::string_view host, std::string_view service, resolve_flags flags)
341   { 443   {
HITCBC 342   16 return resolve_awaitable(*this, host, service, flags); 444   16 return resolve_awaitable(*this, host, service, flags);
343   } 445   }
344   446  
345   /** Initiate an asynchronous reverse resolve operation. 447   /** Initiate an asynchronous reverse resolve operation.
346   448  
347   Resolves an endpoint into a hostname and service name using 449   Resolves an endpoint into a hostname and service name using
348   reverse DNS lookup (PTR record query). 450   reverse DNS lookup (PTR record query).
349   451  
350   This resolver must outlive the returned awaitable. 452   This resolver must outlive the returned awaitable.
351   453  
352   @param ep The endpoint to resolve. 454   @param ep The endpoint to resolve.
353   455  
354   @return An awaitable that completes with 456   @return An awaitable that completes with
355 - `io_result<reverse_resolver_result>`. 457 + `io_result<endpoint_name>`.
356   458  
357   @par Example 459   @par Example
358   @par !example reverse_resolve 460   @par !example reverse_resolve
359   */ 461   */
HITCBC 360   11 [[nodiscard]] auto resolve(endpoint const& ep) 462   11 [[nodiscard]] auto resolve(endpoint const& ep)
361   { 463   {
HITCBC 362   11 return reverse_resolve_awaitable(*this, ep, reverse_flags::none); 464   11 return reverse_resolve_awaitable(*this, ep, reverse_flags::none);
363   } 465   }
364   466  
365   /** Initiate an asynchronous reverse resolve operation with flags. 467   /** Initiate an asynchronous reverse resolve operation with flags.
366   468  
367   Resolves an endpoint into a hostname and service name using 469   Resolves an endpoint into a hostname and service name using
368   reverse DNS lookup (PTR record query). 470   reverse DNS lookup (PTR record query).
369   471  
370   This resolver must outlive the returned awaitable. 472   This resolver must outlive the returned awaitable.
371   473  
372   @param ep The endpoint to resolve. 474   @param ep The endpoint to resolve.
373   475  
374   @param flags Flags controlling resolution behavior. See reverse_flags. 476   @param flags Flags controlling resolution behavior. See reverse_flags.
375   477  
376   @return An awaitable that completes with 478   @return An awaitable that completes with
377 - `io_result<reverse_resolver_result>`. 479 + `io_result<endpoint_name>`.
378   */ 480   */
HITCBC 379   9 [[nodiscard]] auto resolve(endpoint const& ep, reverse_flags flags) 481   9 [[nodiscard]] auto resolve(endpoint const& ep, reverse_flags flags)
380   { 482   {
HITCBC 381   9 return reverse_resolve_awaitable(*this, ep, flags); 483   9 return reverse_resolve_awaitable(*this, ep, flags);
382   } 484   }
383   485  
384   /** Cancel any pending asynchronous operations. 486   /** Cancel any pending asynchronous operations.
385   487  
386   Operations still in flight complete with `errc::operation_canceled`; 488   Operations still in flight complete with `errc::operation_canceled`;
387   an operation whose result is already decided reports that result. 489   an operation whose result is already decided reports that result.
388   Check `ec == cond::canceled` for portable comparison. 490   Check `ec == cond::canceled` for portable comparison.
389   */ 491   */
390   void cancel() noexcept; 492   void cancel() noexcept;
391   493  
392   public: 494   public:
393   /** Backend interface for DNS resolution operations. 495   /** Backend interface for DNS resolution operations.
394   496  
395   Platform backends derive from this to implement forward and 497   Platform backends derive from this to implement forward and
396   reverse DNS resolution via getaddrinfo/getnameinfo. 498   reverse DNS resolution via getaddrinfo/getnameinfo.
397   */ 499   */
398   struct implementation : io_object::implementation 500   struct implementation : io_object::implementation
399   { 501   {
400   /// Initiate an asynchronous forward DNS resolution. 502   /// Initiate an asynchronous forward DNS resolution.
401   virtual std::coroutine_handle<> resolve( 503   virtual std::coroutine_handle<> resolve(
402   std::coroutine_handle<>, 504   std::coroutine_handle<>,
403   capy::executor_ref, 505   capy::executor_ref,
404   std::string_view host, 506   std::string_view host,
405   std::string_view service, 507   std::string_view service,
406   resolve_flags flags, 508   resolve_flags flags,
407   std::stop_token, 509   std::stop_token,
408   std::error_code*, 510   std::error_code*,
409 - resolver_results*) = 0; 511 + std::vector<endpoint>*) = 0;
410   512  
411   /// Initiate an asynchronous reverse DNS resolution. 513   /// Initiate an asynchronous reverse DNS resolution.
412   virtual std::coroutine_handle<> reverse_resolve( 514   virtual std::coroutine_handle<> reverse_resolve(
413   std::coroutine_handle<>, 515   std::coroutine_handle<>,
414   capy::executor_ref, 516   capy::executor_ref,
415   endpoint const& ep, 517   endpoint const& ep,
416   reverse_flags flags, 518   reverse_flags flags,
417   std::stop_token, 519   std::stop_token,
418   std::error_code*, 520   std::error_code*,
419 - reverse_resolver_result*) = 0; 521 + endpoint_name*) = 0;
420   522  
421   /// Cancel pending resolve operations. 523   /// Cancel pending resolve operations.
422   virtual void cancel() noexcept = 0; 524   virtual void cancel() noexcept = 0;
423   }; 525   };
424   526  
425   protected: 527   protected:
426   explicit resolver(handle h) noexcept : io_object(std::move(h)) {} 528   explicit resolver(handle h) noexcept : io_object(std::move(h)) {}
427   529  
428   private: 530   private:
HITCBC 429   55 inline implementation& get() const noexcept 531   59 inline implementation& get() const noexcept
430   { 532   {
HITCBC 431   55 return *static_cast<implementation*>(h_.get()); 533   59 return *static_cast<implementation*>(h_.get());
432   } 534   }
433   }; 535   };
434   536  
435   } // namespace boost::corosio 537   } // namespace boost::corosio
436   538  
437   #endif 539   #endif