1#include <xrpl/basics/ResolverAsio.h>
3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/Resolver.h>
5#include <xrpl/beast/net/IPAddressConversion.h>
6#include <xrpl/beast/net/IPEndpoint.h>
7#include <xrpl/beast/utility/Journal.h>
8#include <xrpl/beast/utility/instrumentation.h>
10#include <boost/asio/bind_executor.hpp>
11#include <boost/asio/dispatch.hpp>
12#include <boost/asio/error.hpp>
13#include <boost/asio/io_context.hpp>
14#include <boost/asio/ip/tcp.hpp>
15#include <boost/asio/post.hpp>
16#include <boost/asio/strand.hpp>
17#include <boost/system/detail/error_code.hpp>
40template <
class Derived>
51 XRPL_ASSERT(
pending_.load() == 0,
"xrpl::AsyncObject::~AsyncObject : nothing pending");
73 if (--
owner_->pending_ == 0)
74 owner_->asyncHandlersComplete();
94 (
static_cast<Derived*
>(
this))->asyncHandlersComplete();
112 boost::asio::strand<boost::asio::io_context::executor_type>
strand;
128 template <
class StringSequence>
131 names.reserve(inNames.size());
151 XRPL_ASSERT(
work.empty(),
"xrpl::ResolverAsioImpl::~ResolverAsioImpl : no pending work");
152 XRPL_ASSERT(
stopped,
"xrpl::ResolverAsioImpl::~ResolverAsioImpl : stopped");
174 XRPL_ASSERT(
stopped ==
true,
"xrpl::ResolverAsioImpl::start : stopped");
175 XRPL_ASSERT(
stopCalled ==
false,
"xrpl::ResolverAsioImpl::start : not stopping");
192 boost::asio::dispatch(
194 boost::asio::bind_executor(
197 JLOG(
journal.debug()) <<
"Queued a stop request";
206 JLOG(
journal.debug()) <<
"Waiting to stop";
210 JLOG(
journal.debug()) <<
"Stopped";
216 XRPL_ASSERT(
stopCalled ==
false,
"xrpl::ResolverAsioImpl::resolve : not stopping");
217 XRPL_ASSERT(!names.
empty(),
"xrpl::ResolverAsioImpl::resolve : names non-empty");
221 boost::asio::dispatch(
223 boost::asio::bind_executor(
234 XRPL_ASSERT(
stopCalled ==
true,
"xrpl::ResolverAsioImpl::doStop : stopping");
248 boost::system::error_code
const& ec,
250 boost::asio::ip::tcp::resolver::results_type results,
253 if (ec == boost::asio::error::operation_aborted)
257 auto iter = results.
begin();
263 while (iter != results.end())
270 handler(name, addresses);
274 boost::asio::bind_executor(
286 return make_pair(result->address().to_string(),
std::to_string(result->port()));
294 auto const findWhitespace =
303 if (hostFirst >= portLast)
307 auto const findPortSeparator = [](
char const c) ->
bool {
308 if (std::isspace(
static_cast<unsigned char>(c)))
317 auto hostLast =
std::find_if(hostFirst, portLast, findPortSeparator);
337 work.front().names.pop_back();
339 if (
work.front().names.empty())
342 auto const [host, port] =
parseName(name);
346 JLOG(
journal.error()) <<
"Unable to parse '" << name <<
"'";
350 boost::asio::bind_executor(
363 std::placeholders::_1,
365 std::placeholders::_2,
366 CompletionCounter(
this)));
372 XRPL_ASSERT(!names.
empty(),
"xrpl::ResolverAsioImpl::doResolve : names non-empty");
376 work.emplace_back(names, handler);
378 JLOG(
journal.debug()) <<
"Queued new job with " << names.
size() <<
" tasks. "
379 <<
work.size() <<
" jobs outstanding.";
385 boost::asio::bind_executor(
T back_inserter(T... args)
static std::optional< Endpoint > fromStringChecked(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)
std::atomic< int > pending_
void resolve(std::vector< std::string > const &names, HandlerType const &handler) override
void stopAsync() override
Issue an asynchronous stop request.
void start() override
Issue a synchronous start request.
ResolverAsioImpl(boost::asio::io_context &ioContext, beast::Journal journal)
std::condition_variable cv
std::atomic< bool > stopCalled
void doWork(CompletionCounter)
void stop() override
Issue a synchronous stop request.
~ResolverAsioImpl() override
bool asyncHandlersCompleted
static HostAndPort parseName(std::string const &str)
void doFinish(std::string name, boost::system::error_code const &ec, HandlerType handler, boost::asio::ip::tcp::resolver::results_type results, CompletionCounter)
boost::asio::ip::tcp::resolver resolver
boost::asio::strand< boost::asio::io_context::executor_type > strand
std::pair< std::string, std::string > HostAndPort
boost::asio::io_context & ioContext
std::atomic< bool > stopped
void doStop(CompletionCounter)
void asyncHandlersComplete()
void doResolve(std::vector< std::string > const &names, HandlerType const &handler, CompletionCounter)
static std::unique_ptr< ResolverAsio > make(boost::asio::io_context &, beast::Journal)
std::function< void(std::string, std::vector< beast::IP::Endpoint >)> HandlerType
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
T reverse_copy(T... args)
static IP::Endpoint fromAsio(boost::asio::ip::address const &address)
Work(StringSequence const &inNames, HandlerType handler)
std::vector< std::string > names