8 #ifndef XCLOX_QUERY_HPP
9 #define XCLOX_QUERY_HPP
11 #include "query_series.hpp"
19 std::string getHost(
const std::string& server)
21 return server.find(
':') == std::string::npos ? server : server.substr(0, server.find(
':'));
24 std::string getPort(
const std::string& server)
26 return server.find(
':') == std::string::npos ?
"123" : server.substr(server.find(
':') + 1);
29 auto stringify = [](
const asio::ip::udp::endpoint& endpoint) {
44 class Query :
public std::enable_shared_from_this<Query> {
64 using Callback = std::function<void(
const std::string&,
const std::string&,
Status,
const Packet&,
const std::chrono::steady_clock::duration&)>;
72 , m_callback(callback)
87 static std::weak_ptr<Query>
start(asio::thread_pool& pool,
const std::string& server,
Callback callback,
const std::chrono::milliseconds& timeout = std::chrono::milliseconds(DefaultTimeout::ms))
92 auto query = std::make_shared<Query>(server, callback);
93 query->m_timer.expires_after(timeout);
94 query->m_timer.async_wait([
self = std::weak_ptr<Query>(query->shared_from_this())](
const asio::error_code& error) {
95 if (error != asio::error::operation_aborted) {
96 if (auto query = self.lock()) {
98 query->finalize(query->m_server,
"", Status::TimeoutError, Packet(), std::chrono::seconds(0));
102 query->m_resolver.async_resolve(
103 internal::getHost(server),
104 internal::getPort(server),
105 [query = std::weak_ptr<Query>(query->shared_from_this())](
106 const asio::error_code& error,
107 const asio::ip::udp::resolver::results_type& endpoints) {
108 auto self = query.lock();
113 self->m_timer.cancel();
120 [query = std::weak_ptr<Query>(self->shared_from_this())](
121 const asio::ip::udp::endpoint& endpoint,
122 const asio::error_code& error,
123 const Packet& packet,
124 const std::chrono::steady_clock::duration& rtt) {
125 auto self = query.lock();
129 self->m_timer.cancel();
132 internal::stringify(endpoint),
138 asio::post(pool, [
self = query] {
147 asio::dispatch(m_io, [query = std::weak_ptr<Query>(shared_from_this())] {
148 auto self = query.lock();
149 if (
self && !self->m_io.stopped()) {
151 self->finalize(self->m_server,
"", Status::Cancelled, Packet(), std::chrono::seconds(0));
157 void finalize(
const std::string& name,
const std::string& address, Status status,
const Packet& packet,
const std::chrono::steady_clock::duration& rtt)
160 m_callback(name, address, status, packet, rtt);
165 std::string m_server;
167 asio::io_context m_io;
168 asio::steady_timer m_timer;
169 asio::ip::udp::resolver m_resolver;
170 std::weak_ptr<QuerySeries> m_subquery;
Packet is an immutable raw NTP packet.
Definition: packet.hpp:54
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
Query is an ephemeral class representing a NTP query from start to end.
Definition: query.hpp:44
internal::DefaultTimeout< QuerySingle, 5000 > DefaultTimeout
Type of query timeout milliseconds holder.
Definition: query.hpp:65
void cancel()
Cancels the query reporting Query::Status::Cancelled to the caller.
Definition: query.hpp:145
std::function< void(const std::string &, const std::string &, Status, const Packet &, const std::chrono::steady_clock::duration &)> Callback
Type of query callback.
Definition: query.hpp:64
Query(const std::string &server, Callback callback)
Constructs a NTP query that targets server and uses callback for reporting back its result.
Definition: query.hpp:70
static std::weak_ptr< Query > start(asio::thread_pool &pool, const std::string &server, Callback callback, const std::chrono::milliseconds &timeout=std::chrono::milliseconds(DefaultTimeout::ms))
Starts querying all resolved addresses of server one at a time until success.
Definition: query.hpp:87
Status
Type of query status.
Definition: query.hpp:55
@ ResolveError
The server domain name is not resolved.
@ ReceiveError
The server packet is not received by the client.
@ TimeoutError
The query timed out while waiting for the server's packet.
@ Succeeded
The client received the server's packet successfully.
@ Cancelled
The client cancelled the query.
@ SendError
The client packet is not sent to the server.