Time Shield Library 2.0.0
C++ library for working with time
Loading...
Searching...
No Matches
ntp_client.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT
2#pragma once
3#ifndef TIME_SHIELD_HEADER_NTP_NTP_CLIENT_HPP_INCLUDED
4#define TIME_SHIELD_HEADER_NTP_NTP_CLIENT_HPP_INCLUDED
5
11
12#include <time_shield/core.hpp>
13
14#if TIME_SHIELD_ENABLE_NTP_CLIENT
15
17#include "detail/ntp_packet.hpp"
19
20#if TIME_SHIELD_PLATFORM_WINDOWS
22#elif TIME_SHIELD_PLATFORM_UNIX
24#endif
25
26#include <atomic>
27#include <cstdint>
28#include <string>
29
30namespace time_shield {
31
32#if TIME_SHIELD_PLATFORM_WINDOWS
33 namespace detail { using PlatformUdpTransport = UdpTransportWin; }
34#elif TIME_SHIELD_PLATFORM_UNIX
35 namespace detail { using PlatformUdpTransport = UdpTransportPosix; }
36#endif
37
38#if TIME_SHIELD_PLATFORM_WINDOWS || TIME_SHIELD_PLATFORM_UNIX
39
42 class NtpClient {
43 public:
47 NtpClient(std::string server = "pool.ntp.org", int port = 123)
48 : m_host(std::move(server))
49 , m_port(port)
50 , m_offset_us(0)
51 , m_delay_us(0)
52 , m_stratum(-1)
53 , m_is_success(false) {
55 }
56
60 bool query() {
62
63#if TIME_SHIELD_PLATFORM_WINDOWS
64 if (!WsaGuard::instance().success()) {
66 m_is_success = false;
67 return false;
68 }
69#endif
70
73
74 int error_code = 0;
75 int64_t offset = 0;
76 int64_t delay = 0;
77 int stratum = -1;
78
79 const bool ok = core.query(
80 transport,
81 m_host,
82 m_port,
84 error_code,
85 offset,
86 delay,
88 );
89
90 last_error_code_slot() = error_code;
91
92 if (!ok) {
93 m_delay_us = 0;
94 m_stratum = -1;
95 m_is_success = false;
96 return false;
97 }
98
99 m_offset_us = offset;
100 m_delay_us = delay;
102 m_is_success = true;
103 return true;
104 }
105
108 bool success() const noexcept { return m_is_success.load(); }
109
112 int64_t offset_us() const noexcept { return m_offset_us; }
113
116 int64_t delay_us() const noexcept { return m_delay_us; }
117
120 int stratum() const noexcept { return m_stratum; }
121
124 int64_t utc_time_us() const noexcept { return now_realtime_us() + m_offset_us.load(); }
125
128 int64_t utc_time_ms() const noexcept { return utc_time_us() / 1000; }
129
132 time_t utc_time_sec() const noexcept { return static_cast<time_t>(utc_time_us() / 1000000); }
133
136 int last_error_code() const noexcept { return last_error_code_slot(); }
137
138 private:
139 std::string m_host;
141 std::atomic<int64_t> m_offset_us;
142 std::atomic<int64_t> m_delay_us;
143 std::atomic<int> m_stratum;
144 std::atomic<bool> m_is_success;
145 static const int k_default_timeout_ms = 5000;
146
147 static int& last_error_code_slot() noexcept {
148 static TIME_SHIELD_THREAD_LOCAL int value = 0;
149 return value;
150 }
151 };
152
153#else
154
155 class NtpClient {
156 public:
158 static_assert(sizeof(void*) == 0, "NtpClient is disabled by configuration.");
159 }
160 };
161
162#endif // platform switch
163
164} // namespace time_shield
165
166#else // TIME_SHIELD_ENABLE_NTP_CLIENT
167
168namespace time_shield {
169 class NtpClient {
170 public:
172 static_assert(sizeof(void*) == 0, "NtpClient is disabled by configuration.");
173 }
174 };
175} // namespace time_shield
176
177#endif // TIME_SHIELD_ENABLE_NTP_CLIENT
178
179#endif // TIME_SHIELD_HEADER_NTP_NTP_CLIENT_HPP_INCLUDED
NTP client for measuring time offset.
int64_t offset_us() const noexcept
Returns the last measured offset in microseconds.
int64_t utc_time_ms() const noexcept
Returns current UTC time in milliseconds based on last NTP offset.
static const int k_default_timeout_ms
bool success() const noexcept
Returns whether the last NTP query was successful.
NtpClient(std::string server="pool.ntp.org", int port=123)
Constructs NTP client with specified host and port.
std::atomic< int64_t > m_delay_us
time_t utc_time_sec() const noexcept
Returns current UTC time as time_t (seconds since Unix epoch).
std::atomic< int > m_stratum
int last_error_code() const noexcept
Returns last socket error code (if any).
int64_t utc_time_us() const noexcept
Returns current UTC time in microseconds based on last NTP offset.
static int & last_error_code_slot() noexcept
std::atomic< int64_t > m_offset_us
int64_t delay_us() const noexcept
Returns the last measured delay in microseconds.
std::atomic< bool > m_is_success
bool query()
Queries the NTP server and updates the local offset.
int stratum() const noexcept
Returns the last received stratum value.
int ret_code() const noexcept
Returns the result code from WSAStartup.
Definition wsa_guard.hpp:44
static const WsaGuard & instance()
Returns the singleton instance, initializing WSA if needed.
Definition wsa_guard.hpp:33
Core NTP query logic that parses packets and computes offsets.
bool query(IUdpTransport &transport, const std::string &host, int port, int timeout_ms, int &out_error_code, int64_t &out_offset_us, int64_t &out_delay_us, int &out_stratum) noexcept
Perform one NTP transaction using a UDP transport.
Windows UDP transport for NTP queries.
int64_t now_realtime_us()
Get current real time in microseconds using a platform-specific method.
UdpTransportWin PlatformUdpTransport
Main namespace for the Time Shield library.