Skip to content

Commit 2d43af0

Browse files
committed
Add reverse DNS resolution support to resolver
Implement reverse DNS lookup capability for the resolver class, enabling hostname lookups from IP addresses using getnameinfo() on POSIX and GetNameInfoW() on Windows. New API: - resolve(endpoint) - reverse resolve with default flags - resolve(endpoint, reverse_flags) - reverse resolve with custom flags - reverse_flags enum (numeric_host, numeric_service, name_required, datagram_service) - reverse_resolver_result class with endpoint(), host_name(), service_name() Implementation uses worker threads on both platforms since the underlying APIs (getnameinfo/GetNameInfoW) are synchronous. Thread lifetime is managed via shared_ptr to prevent use-after-free during shutdown.
1 parent a700836 commit 2d43af0

6 files changed

Lines changed: 1113 additions & 47 deletions

File tree

include/boost/corosio/resolver.hpp

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
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+
195310
public:
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

include/boost/corosio/resolver_results.hpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,65 @@ class resolver_results
200200
}
201201
};
202202

203+
//------------------------------------------------------------------------------
204+
205+
/** The result of a reverse DNS resolution.
206+
207+
This class holds the result of resolving an endpoint
208+
into a hostname and service name.
209+
210+
@par Thread Safety
211+
Distinct objects: Safe.@n
212+
Shared objects: Safe.
213+
*/
214+
class reverse_resolver_result
215+
{
216+
corosio::endpoint ep_;
217+
std::string host_;
218+
std::string service_;
219+
220+
public:
221+
/** Default constructor. */
222+
reverse_resolver_result() = default;
223+
224+
/** Construct with endpoint, host name, and service name.
225+
226+
@param ep The endpoint that was resolved.
227+
@param host The resolved host name.
228+
@param service The resolved service name.
229+
*/
230+
reverse_resolver_result(
231+
corosio::endpoint ep,
232+
std::string host,
233+
std::string service)
234+
: ep_(ep)
235+
, host_(std::move(host))
236+
, service_(std::move(service))
237+
{
238+
}
239+
240+
/** Get the endpoint that was resolved. */
241+
corosio::endpoint
242+
endpoint() const noexcept
243+
{
244+
return ep_;
245+
}
246+
247+
/** Get the resolved host name. */
248+
std::string const&
249+
host_name() const noexcept
250+
{
251+
return host_;
252+
}
253+
254+
/** Get the resolved service name. */
255+
std::string const&
256+
service_name() const noexcept
257+
{
258+
return service_;
259+
}
260+
};
261+
203262
} // namespace corosio
204263
} // namespace boost
205264

0 commit comments

Comments
 (0)