1212
1313#include < boost/corosio/detail/config.hpp>
1414#include < boost/corosio/detail/except.hpp>
15+ #include < boost/corosio/endpoint.hpp>
1516#include < boost/corosio/io_object.hpp>
1617#include < boost/capy/io_result.hpp>
1718#include < boost/corosio/resolver_results.hpp>
@@ -107,6 +108,68 @@ operator&=(resolve_flags& a, resolve_flags b) noexcept
107108
108109// ------------------------------------------------------------------------------
109110
111+ /* * Bitmask flags for reverse resolver queries.
112+
113+ These flags correspond to the flags parameter of getnameinfo.
114+ */
115+ enum class reverse_flags : unsigned int
116+ {
117+ // / No flags.
118+ none = 0 ,
119+
120+ // / Return the numeric form of the hostname instead of its name.
121+ numeric_host = 0x01 ,
122+
123+ // / Return the numeric form of the service name instead of its name.
124+ numeric_service = 0x02 ,
125+
126+ // / Return an error if the hostname cannot be resolved.
127+ name_required = 0x04 ,
128+
129+ // / Lookup for datagram (UDP) service instead of stream (TCP).
130+ datagram_service = 0x08
131+ };
132+
133+ /* * Combine two reverse_flags. */
134+ inline
135+ reverse_flags
136+ operator |(reverse_flags a, reverse_flags b) noexcept
137+ {
138+ return static_cast <reverse_flags>(
139+ static_cast <unsigned int >(a) |
140+ static_cast <unsigned int >(b));
141+ }
142+
143+ /* * Combine two reverse_flags. */
144+ inline
145+ reverse_flags&
146+ operator |=(reverse_flags& a, reverse_flags b) noexcept
147+ {
148+ a = a | b;
149+ return a;
150+ }
151+
152+ /* * Intersect two reverse_flags. */
153+ inline
154+ reverse_flags
155+ operator &(reverse_flags a, reverse_flags b) noexcept
156+ {
157+ return static_cast <reverse_flags>(
158+ static_cast <unsigned int >(a) &
159+ static_cast <unsigned int >(b));
160+ }
161+
162+ /* * Intersect two reverse_flags. */
163+ inline
164+ reverse_flags&
165+ operator &=(reverse_flags& a, reverse_flags b) noexcept
166+ {
167+ a = a & b;
168+ return a;
169+ }
170+
171+ // ------------------------------------------------------------------------------
172+
110173/* * An asynchronous DNS resolver for coroutine I/O.
111174
112175 This class provides asynchronous DNS resolution operations that return
@@ -192,6 +255,58 @@ class BOOST_COROSIO_DECL resolver : public io_object
192255 }
193256 };
194257
258+ struct reverse_resolve_awaitable
259+ {
260+ resolver& r_;
261+ endpoint ep_;
262+ reverse_flags flags_;
263+ std::stop_token token_;
264+ mutable system::error_code ec_;
265+ mutable reverse_resolver_result result_;
266+
267+ reverse_resolve_awaitable (
268+ resolver& r,
269+ endpoint const & ep,
270+ reverse_flags flags) noexcept
271+ : r_(r)
272+ , ep_(ep)
273+ , flags_(flags)
274+ {
275+ }
276+
277+ bool await_ready () const noexcept
278+ {
279+ return token_.stop_requested ();
280+ }
281+
282+ capy::io_result<reverse_resolver_result> await_resume () const noexcept
283+ {
284+ if (token_.stop_requested ())
285+ return {make_error_code (system::errc::operation_canceled), {}};
286+ return {ec_, std::move (result_)};
287+ }
288+
289+ template <typename Ex>
290+ auto await_suspend (
291+ std::coroutine_handle<> h,
292+ Ex const & ex) -> std::coroutine_handle<>
293+ {
294+ r_.get ().reverse_resolve (h, ex, ep_, flags_, token_, &ec_, &result_);
295+ return std::noop_coroutine ();
296+ }
297+
298+ template <typename Ex>
299+ auto await_suspend (
300+ std::coroutine_handle<> h,
301+ Ex const & ex,
302+ std::stop_token token) -> std::coroutine_handle<>
303+ {
304+ token_ = std::move (token);
305+ r_.get ().reverse_resolve (h, ex, ep_, flags_, token_, &ec_, &result_);
306+ return std::noop_coroutine ();
307+ }
308+ };
309+
195310public:
196311 /* * Destructor.
197312
@@ -306,6 +421,46 @@ class BOOST_COROSIO_DECL resolver : public io_object
306421 return resolve_awaitable (*this , host, service, flags);
307422 }
308423
424+ /* * Initiate an asynchronous reverse resolve operation.
425+
426+ Resolves an endpoint into a hostname and service name using
427+ reverse DNS lookup (PTR record query).
428+
429+ @param ep The endpoint to resolve.
430+
431+ @return An awaitable that completes with
432+ `io_result<reverse_resolver_result>`.
433+
434+ @par Example
435+ @code
436+ endpoint ep(urls::ipv4_address({127, 0, 0, 1}), 80);
437+ auto [ec, result] = co_await r.resolve(ep);
438+ if (!ec)
439+ std::cout << result.host_name() << ":" << result.service_name();
440+ @endcode
441+ */
442+ auto resolve (endpoint const & ep)
443+ {
444+ return reverse_resolve_awaitable (*this , ep, reverse_flags::none);
445+ }
446+
447+ /* * Initiate an asynchronous reverse resolve operation with flags.
448+
449+ Resolves an endpoint into a hostname and service name using
450+ reverse DNS lookup (PTR record query).
451+
452+ @param ep The endpoint to resolve.
453+
454+ @param flags Flags controlling resolution behavior. See reverse_flags.
455+
456+ @return An awaitable that completes with
457+ `io_result<reverse_resolver_result>`.
458+ */
459+ auto resolve (endpoint const & ep, reverse_flags flags)
460+ {
461+ return reverse_resolve_awaitable (*this , ep, flags);
462+ }
463+
309464 /* * Cancel any pending asynchronous operations.
310465
311466 All outstanding operations complete with `errc::operation_canceled`.
@@ -326,6 +481,15 @@ class BOOST_COROSIO_DECL resolver : public io_object
326481 system::error_code*,
327482 resolver_results*) = 0;
328483
484+ virtual void reverse_resolve (
485+ std::coroutine_handle<>,
486+ capy::executor_ref,
487+ endpoint const & ep,
488+ reverse_flags flags,
489+ std::stop_token,
490+ system::error_code*,
491+ reverse_resolver_result*) = 0;
492+
329493 virtual void cancel () noexcept = 0;
330494 };
331495
0 commit comments