6.7 KiB
NTP Time
1. Назначение
Асинхронный клиент интернет-NTP поверх UDP/IPv4. Не меняет часы ОС: хранит поправку offset_us = local_time - reference_time, а ntp_time_get_us() возвращает local_time - offset_us. Положительная поправка означает, что локальные часы спешат. Поправку также может установить ntp_node_time; RTT и таймеры ETCP используют монотонное время независимо от неё.
2. Как пользоваться
Вызвать ntp_time_init() в uasync-потоке ядра после создания instance->config и instance->ua. Исходное состояние нулевое либо после destroy; активный повторный init возвращает -1, сохраняя прежнее состояние. Обычный init сбрасывает прежнюю поправку и тестовые адреса, копирует список серверов и ставит таймер с задержкой 0. Первый цикл выполняется при обработке uasync, не внутри init.
Цикл начинает с server_current, обходит каждый сервер не более одного раза и заканчивается при первом корректном ответе. Имена разрешаются асинхронно через A-запросы DNS; используется первый полученный IPv4-адрес. После разрешения адреса — до трёх UDP-запросов с ожиданием по 2 с. Каждая отправка имеет новый timestamp; ответ должен содержать timestamp последней отправки в originate. Немедленная ошибка DNS/сокета/отправки/регистрации прекращает попытку этого сервера и переводит к следующему без рекурсии. Ошибки DNS из callback не сбрасывают остаток обхода.
После успеха следующий цикл начинается с сервера, следующего за ответившим; после полного отказа исходный индекс сохраняется. Между завершением цикла и следующим запуском — resync_interval_sec (по умолчанию 3600 с). При активном опросе допустим интервал 1..INT_MAX/10000 секунд: таймеры принимают int в единицах 0,1 мс. Ошибка создания первого таймера возвращается из init; ошибка создания очередного таймера логируется и прекращает автоматические повторы до переинициализации.
Успех устанавливает synced, offset_us, last_sync_tb и вызывает ntp_node_sync_peers(). Полный отказ серверов сохраняет последнюю поправку. reachable отражает успех последнего завершённого интернет-NTP-цикла; изначально он оптимистично равен 1 даже при отключённом опросе. Его изменение обновляет адреса узла через topo_node_update_my_addresses(); это косвенный признак для классификации сокетов, а не гарантия доступа в интернет.
Тестовые подмены устанавливаются после init, до первого poll:
ntp_time_set_test_addr(ntp, ip, port)— IPv4-литерал и порт единственного сервера цикла, без DNS и перехода к конфигурационным серверам.port=0отключает подмену. Конфигурационный список должен оставаться непустым.ntp_time_set_test_dns(ntp, ip, dns_port, ntp_port)— IPv4 DNS-сервер и порт NTP для конфигурационного списка (ntp_port=0означает 123).test_addrимеет приоритет.dns_port=0отключает подмену DNS.
Нюансы:
ntp_enabled=0или пустой список отключают только интернет-опрос; коррекция от пиров остаётся возможной.- До первой коррекции getters возвращают локальное время;
syncedозначает наличие поправки, а не её свежесть. - Нет фильтрации серии измерений или гарантии точного времени; сетевые задержки влияют на оценку.
destroyвызывается в uasync-потоке вне callbacks модуля, до освобождения ua. Отменяет DNS, сокет и таймеры, освобождает серверы и отключает опрос, сохраняяsynced,offset_us,last_sync_tb,reachable.
3. API
Структуры:
struct NTP_TIME— состояние коррекции и интернет-опроса; поля и контракты функций описаны вntp_time.h.
Функции:
ntp_time_init(instance)— 0 при успехе (также при отключённом опросе), -1 при ошибке; новые ресурсы при ошибке освобождаются.ntp_time_destroy(instance)— отменяет опрос, сохраняет поправку; NULL и повторный вызов допустимы.ntp_time_set_test_addr(ntp, ip, port)— задать NTP-сервер напрямую (без DNS) для тестовntp_time_get_us(instance)— скорректированное время в микросекундах (если synced), иначеgettimeofday()ntp_time_get_seconds(instance)— скорректированное время в секундах (time_t)ntp_time_is_synced(instance)— ненулевое значение при наличии поправки от NTP/пира, для NULL — 0.- Getters для NULL возвращают локальное время; секунды вычисляются целочисленным делением микросекунд с приведением к
time_t.