3#ifndef _TIME_SHIELD_NTP_TIME_SERVICE_HPP_INCLUDED
4#define _TIME_SHIELD_NTP_TIME_SERVICE_HPP_INCLUDED
8#if TIME_SHIELD_ENABLE_NTP_CLIENT
16#include <condition_variable>
26 template <
class RunnerT>
30#ifdef TIME_SHIELD_TEST_FAKE_NTP
48 bool start(std::chrono::milliseconds interval = std::chrono::seconds(30),
49 bool measure_immediately =
true) {
53 if (interval.count() <= 0) {
54 interval = std::chrono::milliseconds(1);
71 bool start(
int interval_ms,
bool measure_immediately =
true) {
72 return start(std::chrono::milliseconds(interval_ms), measure_immediately);
136 std::unique_lock<std::mutex> lk(
m_cv_mtx);
137 m_cv.wait_for(lk, sleep_interval, [
this]() {
153 m_offset_us.store(
static_cast<int64_t
>(count * 1000));
162 std::chrono::milliseconds
m_interval{std::chrono::seconds(30)};
182#ifndef _TIME_SHIELD_CPP17
183#if defined(TIME_SHIELD_TEST_FAKE_NTP)
199 template <
class RunnerT>
205#ifdef TIME_SHIELD_CPP17
225 bool init(std::chrono::milliseconds interval,
bool measure_immediately =
true) {
226 std::unique_ptr<RunnerT> local_runner;
228 std::lock_guard<std::mutex> lk(
m_mtx);
232 if (interval.count() <= 0) {
233 interval = std::chrono::milliseconds(1);
250 is_ok = local_runner->measure_now();
256 std::lock_guard<std::mutex> lk(
m_mtx);
264 std::unique_ptr<RunnerT> local_runner;
266 std::lock_guard<std::mutex> lk(
m_mtx);
273 local_runner->stop();
282 std::lock_guard<std::mutex> lk(
m_mtx);
298 std::lock_guard<std::mutex> lk(
m_mtx);
307 std::lock_guard<std::mutex> lk(
m_mtx);
327 std::lock_guard<std::mutex> lk(
m_mtx);
335 std::lock_guard<std::mutex> lk(
m_mtx);
343 std::lock_guard<std::mutex> lk(
m_mtx);
351 std::lock_guard<std::mutex> lk(
m_mtx);
353 return m_runner->last_update_realtime_us();
359 std::lock_guard<std::mutex> lk(
m_mtx);
361 return m_runner->last_success_realtime_us();
367 bool stale(std::chrono::milliseconds max_age)
const noexcept {
373 return age > max_age.count() * 1000;
380 std::lock_guard<std::mutex> lk(
m_mtx);
392 std::lock_guard<std::mutex> lk(
m_mtx);
404 std::lock_guard<std::mutex> lk(
m_mtx);
417 std::lock_guard<std::mutex> lk(
m_mtx);
429 std::lock_guard<std::mutex> lk(
m_mtx);
439 std::lock_guard<std::mutex> lk(
m_mtx);
454 std::unique_ptr<RunnerT> new_runner;
455 std::unique_ptr<RunnerT> old_runner;
456 std::chrono::milliseconds interval;
457 bool measure_immediately =
true;
459 std::lock_guard<std::mutex> lk(
m_mtx);
476 if (!new_runner->start(interval, measure_immediately)) {
482 is_ok = new_runner->measure_now();
488 std::lock_guard<std::mutex> lk(
m_mtx);
502 std::vector<NtpServerConfig> servers;
511 pool.set_servers(std::move(servers));
513 std::unique_ptr<RunnerT> runner;
515 runner.reset(
new RunnerT(std::move(pool)));
524 std::chrono::milliseconds
m_interval{std::chrono::seconds(30)};
535#ifdef TIME_SHIELD_CPP17
540#ifdef TIME_SHIELD_CPP17
541 template <
class RunnerT>
545#ifndef _TIME_SHIELD_CPP17
547#if defined(TIME_SHIELD_NTP_TIME_SERVICE_DEFINE)
553#if defined(TIME_SHIELD_TEST_FAKE_NTP)
570 inline bool init(std::chrono::milliseconds interval = std::chrono::seconds(30),
571 bool measure_immediately =
true) {
580 inline bool init(
int interval_ms,
581 bool measure_immediately =
true) {
658 inline bool stale(std::chrono::milliseconds max_age)
noexcept {
672 static_assert(
sizeof(
void*) == 0,
"NtpTimeService is disabled by configuration.");
static std::vector< NtpServerConfig > build_default_servers()
Singleton service for background NTP measurements.
std::unique_ptr< RunnerT > build_runner_locked()
Build a runner with current server list and pool config.
NtpTimeServiceT()=default
Construct service.
NtpTimeServiceT(const NtpTimeServiceT &)=delete
uint64_t measure_count() const noexcept
Return total number of measurement attempts.
bool is_running_locked() const noexcept
Check runner status under lock.
int64_t last_success_realtime_us() const noexcept
Return realtime timestamp of last successful measurement.
NtpPoolConfig pool_config() const
Return current pool configuration.
void shutdown()
Stop background measurements and release resources.
~NtpTimeServiceT()
Stop background runner on destruction.
bool clear_servers()
Clear custom server list and return to default behavior.
int64_t utc_time_sec() noexcept
Return current UTC time in seconds based on offset.
bool init()
Start background measurements using stored interval.
bool set_pool_config(NtpPoolConfig cfg)
Override pool configuration for new runner instances.
NtpTimeServiceT & operator=(const NtpTimeServiceT &)=delete
bool running() const noexcept
Return true when background runner is active.
bool stale(std::chrono::milliseconds max_age) const noexcept
Return true when last measurement is older than max_age.
int64_t utc_time_ms() noexcept
Return current UTC time in milliseconds based on offset.
bool m_has_custom_pool_cfg
static NtpTimeServiceT & instance() noexcept
Return the singleton instance.
bool m_has_custom_servers
bool last_measure_ok() const noexcept
Return whether last measurement updated the offset.
std::vector< NtpServerConfig > m_servers
bool set_servers(std::vector< NtpServerConfig > servers)
Replace server list used for new runner instances.
int64_t offset_us() noexcept
Return last estimated offset in microseconds.
static NtpTimeServiceT m_instance
uint64_t fail_count() const noexcept
Return number of failed measurement attempts.
bool m_measure_immediately
bool set_default_servers()
Use conservative default servers for new runner instances.
bool apply_config_now()
Apply current config by rebuilding the runner.
std::unique_ptr< detail::FakeNtpRunner > m_runner
int64_t utc_time_us() noexcept
Return current UTC time in microseconds based on offset.
bool init(std::chrono::milliseconds interval, bool measure_immediately=true)
Start background measurements with interval and immediate flag.
std::vector< NtpSample > last_samples() const
Return copy of last measurement samples.
std::chrono::milliseconds m_interval
void ensure_started() noexcept
Ensure background runner is started with current config.
int64_t last_update_realtime_us() const noexcept
Return realtime timestamp of last measurement attempt.
static NtpTimeService & instance()
Fake runner for tests without network access.
std::atomic< bool > m_is_stop_requested
int64_t last_update_realtime_us() const noexcept
Return realtime timestamp of last measurement attempt.
int64_t utc_time_sec() const noexcept
Return current UTC time in seconds based on offset.
std::atomic< int64_t > m_last_success_realtime_us
FakeNtpRunner()=default
Construct fake runner.
int64_t utc_time_us() const noexcept
Return current UTC time in microseconds based on offset.
FakeNtpRunner(const FakeNtpRunner &)=delete
std::atomic< bool > m_last_measure_ok
std::atomic< bool > m_is_force_requested
bool last_measure_ok() const noexcept
Return whether last measurement updated the offset.
int64_t last_success_realtime_us() const noexcept
Return realtime timestamp of last successful measurement.
bool force_measure()
Wake the worker thread and request a measurement.
bool running() const noexcept
Return true when background thread is running.
uint64_t fail_count() const noexcept
Return number of failed measurement attempts.
std::atomic< int64_t > m_last_update_realtime_us
bool start(std::chrono::milliseconds interval=std::chrono::seconds(30), bool measure_immediately=true)
Start fake measurements on a background thread.
int64_t offset_us() const noexcept
Return last estimated offset in microseconds.
bool do_measure()
Update fake offset and stats.
std::atomic< uint64_t > m_measure_count
void run_loop()
Background loop for fake measurements.
int64_t utc_time_ms() const noexcept
Return current UTC time in milliseconds based on offset.
bool m_measure_immediately
std::chrono::milliseconds m_interval
std::atomic< int64_t > m_offset_us
std::atomic< bool > m_is_running
bool measure_now()
Perform one measurement immediately.
~FakeNtpRunner()
Stop background thread on destruction.
uint64_t measure_count() const noexcept
Return total number of measurement attempts.
bool start(int interval_ms, bool measure_immediately=true)
Start fake measurements using milliseconds.
void stop()
Stop background measurements.
FakeNtpRunner(NtpClientPool)
Construct fake runner with an unused pool.
FakeNtpRunner & operator=(const FakeNtpRunner &)=delete
std::vector< NtpSample > last_samples() const
Return copy of most recent samples.
std::atomic< uint64_t > m_fail_count
std::condition_variable m_cv
Configuration macros for the library.
void init()
Initializes the Time Shield library.
int64_t utc_time_sec() noexcept
Return current UTC time in seconds based on offset.
uint64_t measure_count() noexcept
Return total number of measurement attempts.
bool stale(std::chrono::milliseconds max_age) noexcept
Return true when last measurement is older than max_age.
bool last_measure_ok() noexcept
Return whether last measurement updated the offset.
int64_t offset_us() noexcept
Return last estimated offset in microseconds.
void shutdown()
Stop NTP time service.
int64_t utc_time_ms() noexcept
Return current UTC time in milliseconds based on offset.
int64_t last_success_realtime_us() noexcept
Return realtime timestamp of last successful measurement.
uint64_t fail_count() noexcept
Return number of failed measurement attempts.
int64_t last_update_realtime_us() noexcept
Return realtime timestamp of last measurement attempt.
int64_t utc_time_us() noexcept
Return current UTC time in microseconds based on offset.
ts_ms_t now() noexcept
Get the current UTC timestamp in milliseconds.
int64_t now_realtime_us()
Get current real time in microseconds using a platform-specific method.
detail::FakeNtpRunner RunnerAlias
NtpTimeServiceT< RunnerAlias > g_ntp_time_service
Main namespace for the Time Shield library.
Header file with time-related utility functions.