Time Shield Library
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_NTP_CLIENT_HPP_INCLUDED
4#define _TIME_SHIELD_NTP_CLIENT_HPP_INCLUDED
5
11
12#include "config.hpp"
13
14#if TIME_SHIELD_ENABLE_NTP_CLIENT
15
16#include "time_utils.hpp"
20
21#if TIME_SHIELD_PLATFORM_WINDOWS
23#elif TIME_SHIELD_PLATFORM_UNIX
25#endif
26
27#include <atomic>
28#include <cstdint>
29#include <string>
30
31namespace time_shield {
32
33#if TIME_SHIELD_PLATFORM_WINDOWS
35#elif TIME_SHIELD_PLATFORM_UNIX
36 namespace detail { using PlatformUdpTransport = UdpTransportPosix; }
37#endif
38
39#if TIME_SHIELD_PLATFORM_WINDOWS || TIME_SHIELD_PLATFORM_UNIX
40
43 class NtpClient {
44 public:
48 NtpClient(std::string server = "pool.ntp.org", int port = 123)
49 : m_host(std::move(server))
50 , m_port(port)
51 , m_offset_us(0)
52 , m_delay_us(0)
53 , m_stratum(-1)
54 , m_is_success(false) {
56 }
57
61 bool query() {
63
64#if TIME_SHIELD_PLATFORM_WINDOWS
65 if (!WsaGuard::instance().success()) {
67 m_is_success = false;
68 return false;
69 }
70#endif
71
74
75 int error_code = 0;
76 int64_t offset = 0;
77 int64_t delay = 0;
78 int stratum = -1;
79
80 const bool ok = core.query(
81 transport,
82 m_host,
83 m_port,
85 error_code,
86 offset,
87 delay,
89 );
90
91 last_error_code_slot() = error_code;
92
93 if (!ok) {
94 m_delay_us = 0;
95 m_stratum = -1;
96 m_is_success = false;
97 return false;
98 }
99
100 m_offset_us = offset;
101 m_delay_us = delay;
103 m_is_success = true;
104 return true;
105 }
106
109 bool success() const noexcept { return m_is_success.load(); }
110
113 int64_t offset_us() const noexcept { return m_offset_us; }
114
117 int64_t delay_us() const noexcept { return m_delay_us; }
118
121 int stratum() const noexcept { return m_stratum; }
122
125 int64_t utc_time_us() const noexcept { return now_realtime_us() + m_offset_us.load(); }
126
129 int64_t utc_time_ms() const noexcept { return utc_time_us() / 1000; }
130
133 time_t utc_time_sec() const noexcept { return static_cast<time_t>(utc_time_us() / 1000000); }
134
137 int last_error_code() const noexcept { return last_error_code_slot(); }
138
139 private:
140 std::string m_host;
142 std::atomic<int64_t> m_offset_us;
143 std::atomic<int64_t> m_delay_us;
144 std::atomic<int> m_stratum;
145 std::atomic<bool> m_is_success;
146 static const int k_default_timeout_ms = 5000;
147
148 static int& last_error_code_slot() noexcept {
149 static TIME_SHIELD_THREAD_LOCAL int value = 0;
150 return value;
151 }
152 };
153
154#else
155
156 class NtpClient {
157 public:
159 static_assert(sizeof(void*) == 0, "NtpClient is disabled by configuration.");
160 }
161 };
162
163#endif // platform switch
164
165} // namespace time_shield
166
167#else // TIME_SHIELD_ENABLE_NTP_CLIENT
168
169namespace time_shield {
170 class NtpClient {
171 public:
173 static_assert(sizeof(void*) == 0, "NtpClient is disabled by configuration.");
174 }
175 };
176} // namespace time_shield
177
178#endif // TIME_SHIELD_ENABLE_NTP_CLIENT
179
180#endif // _TIME_SHIELD_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:40
static const WsaGuard & instance()
Returns the singleton instance, initializing WSA if needed.
Definition wsa_guard.hpp:29
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.
Configuration macros for the library.
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.
Header file with time-related utility functions.