8 #ifndef XCLOX_COMPOUND_QUERY_HPP
9 #define XCLOX_COMPOUND_QUERY_HPP
11 #include "query_single.hpp"
37 explicit QuerySeries(asio::io_context& io,
const asio::ip::udp::resolver::results_type& endpoints,
const std::chrono::milliseconds& timeout)
39 , m_endpoints(endpoints)
40 , m_timer(io, timeout)
52 static std::weak_ptr<QuerySeries>
start(asio::io_context& io,
const asio::ip::udp::resolver::results_type& endpoints,
Callback callback,
const std::chrono::milliseconds& timeout = std::chrono::milliseconds(DefaultTimeout::ms))
54 if (!callback || endpoints.empty()) {
57 auto query = std::make_shared<QuerySeries>(io, endpoints, timeout);
58 query->m_timer.async_wait([query](
const asio::error_code& error) {
59 if (error != asio::error::operation_aborted) {
60 query->m_timer.expires_at(std::chrono::steady_clock::time_point::min());
61 if (
auto currentQuery = query->m_subquery.lock())
62 currentQuery->cancel();
65 query->m_callback = [query, callback](
const asio::ip::udp::endpoint& endpoint,
const asio::error_code& error,
const Packet& packet,
const std::chrono::steady_clock::duration& rtt) {
66 if (error && error != asio::error::operation_aborted && query->index(endpoint) < query->m_endpoints.size() - 1) {
67 query->m_subquery =
QuerySingle::start(query->m_io, std::next(query->m_endpoints.cbegin(), query->index(endpoint) + 1)->endpoint(), query->m_callback);
69 query->m_timer.cancel();
70 query->m_callback = {};
73 query->m_timer.expiry() == std::chrono::steady_clock::time_point::max() ? asio::error::operation_aborted : (query->m_timer.expiry() == std::chrono::steady_clock::time_point::min() ? asio::error::timed_out : error),
78 query->m_subquery =
QuerySingle::start(io, endpoints.cbegin()->endpoint(), query->m_callback);
85 m_timer.expires_at(std::chrono::steady_clock::time_point::max());
86 if (
auto query = m_subquery.lock())
91 size_t index(
const asio::ip::udp::endpoint& endpoint)
const
93 return std::distance(m_endpoints.cbegin(), std::find_if(m_endpoints.cbegin(), m_endpoints.cend(), [&endpoint](
const asio::ip::basic_resolver_entry<asio::ip::udp>& entry) { return entry.endpoint() == endpoint; }));
96 asio::io_context& m_io;
97 asio::ip::udp::resolver::results_type m_endpoints;
98 asio::steady_timer m_timer;
100 std::weak_ptr<QuerySingle> m_subquery;
Packet is an immutable raw NTP packet.
Definition: packet.hpp:54
QuerySeries is an ephemeral class representing a series of NTP queries.
Definition: query_series.hpp:24
static std::weak_ptr< QuerySeries > start(asio::io_context &io, const asio::ip::udp::resolver::results_type &endpoints, Callback callback, const std::chrono::milliseconds &timeout=std::chrono::milliseconds(DefaultTimeout::ms))
Starts querying the given endpoints one at a time until success or all endpoints are queried.
Definition: query_series.hpp:52
QuerySingle::Callback Callback
Type of query callback.
Definition: query_series.hpp:31
QuerySeries(asio::io_context &io, const asio::ip::udp::resolver::results_type &endpoints, const std::chrono::milliseconds &timeout)
Constructs a NTP query series on the given context that targets the given endpoints one at a time unt...
Definition: query_series.hpp:37
void cancel()
Cancels the query reporting asio::error::operation_aborted to the caller.
Definition: query_series.hpp:83
internal::DefaultTimeout< QuerySingle, 5000 > DefaultTimeout
Type of query timeout milliseconds holder.
Definition: query_series.hpp:32
static std::weak_ptr< QuerySingle > start(asio::io_context &io, const asio::ip::udp::endpoint &server, Callback callback, const std::chrono::milliseconds &timeout=std::chrono::milliseconds(DefaultTimeout::ms))
Starts querying the given endpoint.
Definition: query_single.hpp:68
std::function< void(const asio::ip::udp::endpoint &, const asio::error_code &, const Packet &, const std::chrono::steady_clock::duration &)> Callback
Type of query callback.
Definition: query_single.hpp:48