1#include <xrpl/basics/Log.h>
2#include <xrpl/basics/Resolver.h>
3#include <xrpl/basics/ResolverAsio.h>
4#include <xrpl/beast/net/IPAddressConversion.h>
5#include <xrpl/beast/net/IPEndpoint.h>
6#include <xrpl/beast/utility/Journal.h>
7#include <xrpl/beast/utility/instrumentation.h>
9#include <boost/asio/bind_executor.hpp>
10#include <boost/asio/error.hpp>
11#include <boost/asio/io_context.hpp>
12#include <boost/asio/ip/tcp.hpp>
13#include <boost/system/detail/error_code.hpp>
35template <
class Derived>
46 XRPL_ASSERT(
m_pending.
load() == 0,
"xrpl::AsyncObject::~AsyncObject : nothing pending");
69 m_owner->asyncHandlersComplete();
89 (
static_cast<Derived*
>(
this))->asyncHandlersComplete();
107 boost::asio::strand<boost::asio::io_context::executor_type>
m_strand;
123 template <
class StringSequence>
146 XRPL_ASSERT(
m_work.empty(),
"xrpl::ResolverAsioImpl::~ResolverAsioImpl : no pending work");
147 XRPL_ASSERT(
m_stopped,
"xrpl::ResolverAsioImpl::~ResolverAsioImpl : stopped");
169 XRPL_ASSERT(
m_stopped ==
true,
"xrpl::ResolverAsioImpl::start : stopped");
170 XRPL_ASSERT(
m_stop_called ==
false,
"xrpl::ResolverAsioImpl::start : not stopping");
187 boost::asio::dispatch(
189 boost::asio::bind_executor(
212 XRPL_ASSERT(
m_stop_called ==
false,
"xrpl::ResolverAsioImpl::resolve : not stopping");
213 XRPL_ASSERT(!names.
empty(),
"xrpl::ResolverAsioImpl::resolve : names non-empty");
217 boost::asio::dispatch(
219 boost::asio::bind_executor(
230 XRPL_ASSERT(
m_stop_called ==
true,
"xrpl::ResolverAsioImpl::do_stop : stopping");
244 boost::system::error_code
const& ec,
246 boost::asio::ip::tcp::resolver::results_type results,
249 if (ec == boost::asio::error::operation_aborted)
253 auto iter = results.
begin();
259 while (iter != results.end())
266 handler(name, addresses);
270 boost::asio::bind_executor(
282 return make_pair(result->address().to_string(),
std::to_string(result->port()));
290 auto const find_whitespace =
298 if (host_first >= port_last)
302 auto const find_port_separator = [](
char const c) ->
bool {
312 auto host_last =
std::find_if(host_first, port_last, find_port_separator);
314 auto port_first =
std::find_if_not(host_last, port_last, find_port_separator);
332 m_work.front().names.pop_back();
334 if (
m_work.front().names.empty())
337 auto const [host, port] =
parseName(name);
345 boost::asio::bind_executor(
359 std::placeholders::_1,
361 std::placeholders::_2,
362 CompletionCounter(
this)));
368 XRPL_ASSERT(!names.
empty(),
"xrpl::ResolverAsioImpl::do_resolve : names non-empty");
372 m_work.emplace_back(names, handler);
375 <<
m_work.size() <<
" jobs outstanding.";
381 boost::asio::bind_executor(
T back_inserter(T... args)
static std::optional< Endpoint > from_string_checked(std::string const &s)
Create an Endpoint from a string.
A generic endpoint for log messages.
RAII container that maintains the count of pending I/O.
CompletionCounter & operator=(CompletionCounter const &)=delete
CompletionCounter(Derived *owner)
CompletionCounter(CompletionCounter const &other)
Mix-in to track when all pending I/O is complete.
std::atomic< int > m_pending
std::atomic< bool > m_stop_called
void do_stop(CompletionCounter)
boost::asio::io_context & m_io_context
boost::asio::ip::tcp::resolver m_resolver
ResolverAsioImpl(boost::asio::io_context &io_context, beast::Journal journal)
bool m_asyncHandlersCompleted
void resolve(std::vector< std::string > const &names, HandlerType const &handler) override
void start() override
Issue a synchronous start request.
void do_finish(std::string name, boost::system::error_code const &ec, HandlerType handler, boost::asio::ip::tcp::resolver::results_type results, CompletionCounter)
std::deque< Work > m_work
void stop() override
Issue a synchronous stop request.
~ResolverAsioImpl() override
std::condition_variable m_cv
std::atomic< bool > m_stopped
boost::asio::strand< boost::asio::io_context::executor_type > m_strand
void do_resolve(std::vector< std::string > const &names, HandlerType const &handler, CompletionCounter)
static HostAndPort parseName(std::string const &str)
std::pair< std::string, std::string > HostAndPort
void stop_async() override
Issue an asynchronous stop request.
void asyncHandlersComplete()
void do_work(CompletionCounter)
static std::unique_ptr< ResolverAsio > New(boost::asio::io_context &, beast::Journal)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
T reverse_copy(T... args)
static IP::Endpoint from_asio(boost::asio::ip::address const &address)
std::vector< std::string > names
Work(StringSequence const &names_, HandlerType const &handler_)