mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-04 04:35:06 -05:00
Compare commits
120 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42a85f685e | ||
|
|
feca2399e4 | ||
|
|
d34e611ec8 | ||
|
|
02098ed830 | ||
|
|
aa4228bf1b | ||
|
|
b296441708 | ||
|
|
b827475378 | ||
|
|
78a6698ae1 | ||
|
|
e7b6feb34b | ||
|
|
84be834385 | ||
|
|
e83d808dfd | ||
|
|
35a68d5b59 | ||
|
|
3c593137b0 | ||
|
|
deaf0ffed3 | ||
|
|
af145e871e | ||
|
|
fbca570d0b | ||
|
|
448ef779c2 | ||
|
|
499a69e611 | ||
|
|
58c2915878 | ||
|
|
eda4b111d3 | ||
|
|
c6dd749687 | ||
|
|
d2a96f5fbc | ||
|
|
499f513d40 | ||
|
|
8b1f68b1b4 | ||
|
|
8e4c776900 | ||
|
|
d0eb9427c2 | ||
|
|
7d100b89fc | ||
|
|
a4bd7f1800 | ||
|
|
5308e0a25f | ||
|
|
da862158bf | ||
|
|
7b98443a13 | ||
|
|
4da9f74d24 | ||
|
|
e41042e258 | ||
|
|
5581466c63 | ||
|
|
e79a6c2116 | ||
|
|
666ece122e | ||
|
|
2c7ab98370 | ||
|
|
f0f18a02a7 | ||
|
|
c5d8af0285 | ||
|
|
0ce15a8472 | ||
|
|
da60629201 | ||
|
|
2343e7a89c | ||
|
|
45f27f4f5e | ||
|
|
0bc112f8b4 | ||
|
|
bfc2fa645c | ||
|
|
11111804fd | ||
|
|
87ec67247e | ||
|
|
0df8328ceb | ||
|
|
b563048ee2 | ||
|
|
e8096330be | ||
|
|
b1647dbcb7 | ||
|
|
4ddadd5622 | ||
|
|
3e854006c7 | ||
|
|
2c4c235147 | ||
|
|
6863e43269 | ||
|
|
de8708f331 | ||
|
|
d0b2486036 | ||
|
|
5384a93645 | ||
|
|
4bbc768652 | ||
|
|
fead915b45 | ||
|
|
5422e49026 | ||
|
|
77a1f27a1d | ||
|
|
b45d864f73 | ||
|
|
f35c81c871 | ||
|
|
a349b2803c | ||
|
|
f5d1b8fb74 | ||
|
|
a0fe71eef1 | ||
|
|
154b39cf7a | ||
|
|
6f54210db2 | ||
|
|
f6539449c5 | ||
|
|
b8d546a0d1 | ||
|
|
04e6474b75 | ||
|
|
eb51c500e8 | ||
|
|
6f8fba9a3f | ||
|
|
750afc30f2 | ||
|
|
e0e6ec0d84 | ||
|
|
c9f50fc686 | ||
|
|
83c26b458b | ||
|
|
b711873f45 | ||
|
|
c68ca40ce4 | ||
|
|
51fe80ad95 | ||
|
|
7ffee73524 | ||
|
|
f40b0024bd | ||
|
|
a06c9909a6 | ||
|
|
aee42fada8 | ||
|
|
3e93068c43 | ||
|
|
36291b707b | ||
|
|
6dad2c24bf | ||
|
|
27cbf20d23 | ||
|
|
5c571bbbe7 | ||
|
|
33d65c8614 | ||
|
|
d87db7cdb8 | ||
|
|
45fa4750da | ||
|
|
8472fd8133 | ||
|
|
5ab645e310 | ||
|
|
8ccda538d3 | ||
|
|
b06d74ab73 | ||
|
|
d0964ffa83 | ||
|
|
3d08815efb | ||
|
|
a83f0d3cdc | ||
|
|
702db726d3 | ||
|
|
ed5c43204b | ||
|
|
f91bdd604d | ||
|
|
3a1dbb1354 | ||
|
|
4b511143b8 | ||
|
|
93076e7e1c | ||
|
|
1c51feb3c5 | ||
|
|
c2773dbc2f | ||
|
|
4534db84c4 | ||
|
|
be8215e181 | ||
|
|
ae82bbbace | ||
|
|
2b6ea41062 | ||
|
|
d9f745fe70 | ||
|
|
9aac179367 | ||
|
|
b896bb5a78 | ||
|
|
64c2fd9888 | ||
|
|
2668a12e4e | ||
|
|
e1645966ec | ||
|
|
4f1fc1ee78 | ||
|
|
d70df3daab |
32
NEWS
32
NEWS
@@ -1,17 +1,45 @@
|
|||||||
|
New in version 3.3
|
||||||
|
==================
|
||||||
|
|
||||||
|
Enhancements
|
||||||
|
------------
|
||||||
|
* Add burst option to server/pool directive
|
||||||
|
* Add stratum and tai options to refclock directive
|
||||||
|
* Add support for Nettle crypto library
|
||||||
|
* Add workaround for missing kernel receive timestamps on Linux
|
||||||
|
* Wait for late hardware transmit timestamps
|
||||||
|
* Improve source selection with unreachable sources
|
||||||
|
* Improve protection against replay attacks on symmetric mode
|
||||||
|
* Allow PHC refclock to use socket in /var/run/chrony
|
||||||
|
* Add shutdown command to stop chronyd
|
||||||
|
* Simplify format of response to manual list command
|
||||||
|
* Improve handling of unknown responses in chronyc
|
||||||
|
|
||||||
|
Bug fixes
|
||||||
|
---------
|
||||||
|
* Respond to NTPv1 client requests with zero mode
|
||||||
|
* Fix -x option to not require CAP_SYS_TIME under non-root user
|
||||||
|
* Fix chronyc to not get stuck in infinite loop after clock step
|
||||||
|
|
||||||
New in version 3.2
|
New in version 3.2
|
||||||
==================
|
==================
|
||||||
|
|
||||||
Enhancements
|
Enhancements
|
||||||
------------
|
------------
|
||||||
* Improve stability with NTP sources and reference clocks
|
* Improve stability with NTP sources and reference clocks
|
||||||
|
* Improve stability with hardware timestamping
|
||||||
* Improve support for NTP interleaved modes
|
* Improve support for NTP interleaved modes
|
||||||
* Control frequency of system clock on macOS 10.13 and later
|
* Control frequency of system clock on macOS 10.13 and later
|
||||||
* Set TAI-UTC offset of system clock with leapsectz directive
|
* Set TAI-UTC offset of system clock with leapsectz directive
|
||||||
* Add support for new HW timestamping options added in Linux 4.13
|
* Minimise data in client requests to improve privacy
|
||||||
* Add rxfilter option to hwtimestamp directive
|
* Allow transmit-only hardware timestamping
|
||||||
|
* Add support for new timestamping options introduced in Linux 4.13
|
||||||
|
* Add root delay, root dispersion and maximum error to tracking log
|
||||||
|
* Add mindelay and asymmetry options to server/peer/pool directive
|
||||||
* Add extpps option to PHC refclock to timestamp external PPS signal
|
* Add extpps option to PHC refclock to timestamp external PPS signal
|
||||||
* Add pps option to refclock directive to treat any refclock as PPS
|
* Add pps option to refclock directive to treat any refclock as PPS
|
||||||
* Add width option to refclock directive to filter wrong pulse edges
|
* Add width option to refclock directive to filter wrong pulse edges
|
||||||
|
* Add rxfilter option to hwtimestamp directive
|
||||||
* Add -x option to disable control of system clock
|
* Add -x option to disable control of system clock
|
||||||
* Add -l option to log to specified file instead of syslog
|
* Add -l option to log to specified file instead of syslog
|
||||||
* Allow multiple command-line options to be specified together
|
* Allow multiple command-line options to be specified together
|
||||||
|
|||||||
47
README
47
README
@@ -4,7 +4,7 @@ What is chrony?
|
|||||||
===============
|
===============
|
||||||
|
|
||||||
chrony is a versatile implementation of the Network Time Protocol (NTP).
|
chrony is a versatile implementation of the Network Time Protocol (NTP).
|
||||||
It can synchronize the system clock with NTP servers, reference clocks
|
It can synchronise the system clock with NTP servers, reference clocks
|
||||||
(e.g. GPS receiver), and manual input using wristwatch and keyboard.
|
(e.g. GPS receiver), and manual input using wristwatch and keyboard.
|
||||||
It can also operate as an NTPv4 (RFC 5905) server and peer to provide
|
It can also operate as an NTPv4 (RFC 5905) server and peer to provide
|
||||||
a time service to other computers in the network.
|
a time service to other computers in the network.
|
||||||
@@ -37,20 +37,16 @@ How do I set it up?
|
|||||||
===================
|
===================
|
||||||
|
|
||||||
The file INSTALL gives instructions. On supported systems the
|
The file INSTALL gives instructions. On supported systems the
|
||||||
compilation process should be automatic.
|
compilation process should be automatic. You will need a C compiler,
|
||||||
|
e.g. gcc or clang.
|
||||||
You will need an ANSI C compiler -- gcc is recommended.
|
|
||||||
|
|
||||||
The manual (in texinfo and text formats) describes how to set the
|
|
||||||
software up for the less straightforward cases.
|
|
||||||
|
|
||||||
What documentation is there?
|
What documentation is there?
|
||||||
============================
|
============================
|
||||||
|
|
||||||
A manual is supplied in Texinfo format (chrony.texi) and
|
The distribution includes manual pages and a document containing
|
||||||
ready-formatted plain text (chrony.txt) in the distribution.
|
Frequently Asked Questions (FAQ).
|
||||||
|
|
||||||
There is also information available on the chrony web pages, accessible
|
The documentation is also available on the chrony web pages, accessible
|
||||||
through the URL
|
through the URL
|
||||||
|
|
||||||
https://chrony.tuxfamily.org/
|
https://chrony.tuxfamily.org/
|
||||||
@@ -126,7 +122,7 @@ Andrew Bishop <amb@gedanken.demon.co.uk>
|
|||||||
Improvements to 'sources' and 'sourcestats' output from chronyc
|
Improvements to 'sources' and 'sourcestats' output from chronyc
|
||||||
Improvements to documentation
|
Improvements to documentation
|
||||||
Investigation of required dosynctodr behaviour for various Solaris
|
Investigation of required dosynctodr behaviour for various Solaris
|
||||||
versions.
|
versions
|
||||||
|
|
||||||
Stephan I. Boettcher <stephan@nevis1.columbia.edu>
|
Stephan I. Boettcher <stephan@nevis1.columbia.edu>
|
||||||
Entries in contrib directory
|
Entries in contrib directory
|
||||||
@@ -140,27 +136,27 @@ Bryan Christianson <bryan@whatroute.net>
|
|||||||
Entries in contrib directory
|
Entries in contrib directory
|
||||||
|
|
||||||
Juliusz Chroboczek <jch@pps.jussieu.fr>
|
Juliusz Chroboczek <jch@pps.jussieu.fr>
|
||||||
Fix install rule in Makefile if chronyd file is in use.
|
Patch to fix install rule in Makefile if chronyd file is in use
|
||||||
|
|
||||||
|
Christian Ehrhardt <christian.ehrhardt@canonical.com>
|
||||||
|
Patch to generate a warning message when CAP_SYS_TIME is missing
|
||||||
|
|
||||||
Paul Elliott <pelliott@io.com>
|
Paul Elliott <pelliott@io.com>
|
||||||
DNSchrony (in contrib directory), a tool for handling NTP servers
|
Entries in contrib directory
|
||||||
with variable IP addresses.
|
|
||||||
|
|
||||||
Mike Fleetwood <mike@rockover.demon.co.uk>
|
Mike Fleetwood <mike@rockover.demon.co.uk>
|
||||||
Fixes for compiler warnings
|
Fixes for compiler warnings
|
||||||
|
|
||||||
Alexander Gretencord <arutha@gmx.de>
|
Alexander Gretencord <arutha@gmx.de>
|
||||||
Changes to installation directory system to make it easier for
|
Changes to installation directory system to make it easier for
|
||||||
package builders.
|
package builders
|
||||||
|
|
||||||
Andrew Griffiths <agriffit@redhat.com>
|
Andrew Griffiths <agriffit@redhat.com>
|
||||||
Patch to add support for seccomp filter
|
Patch to add support for seccomp filter
|
||||||
|
|
||||||
Walter Haidinger <walter.haidinger@gmx.at>
|
Walter Haidinger <walter.haidinger@gmx.at>
|
||||||
Providing me with login access to a Linux installation where v1.12
|
Access to a Linux installation where v1.12 wouldn't compile
|
||||||
wouldn't compile, so I could develop the fixes for v1.13. Also, for
|
Disc space for an independent backup of the sources
|
||||||
providing the disc space so I can keep an independent backup of the
|
|
||||||
sources.
|
|
||||||
|
|
||||||
Juergen Hannken-Illjes <hannken@eis.cs.tu-bs.de>
|
Juergen Hannken-Illjes <hannken@eis.cs.tu-bs.de>
|
||||||
Port to NetBSD
|
Port to NetBSD
|
||||||
@@ -170,7 +166,7 @@ John Hasler <john@dhh.gt.org>
|
|||||||
Changes to support 64 bit machines (i.e. those where
|
Changes to support 64 bit machines (i.e. those where
|
||||||
sizeof(unsigned long) > 4)
|
sizeof(unsigned long) > 4)
|
||||||
Bug fix to initstepslew directive
|
Bug fix to initstepslew directive
|
||||||
Fix to remove potential buffer overrun errors.
|
Fix to remove potential buffer overrun errors
|
||||||
Memory locking and real-time scheduler support
|
Memory locking and real-time scheduler support
|
||||||
Fix fault where chronyd enters an endless loop
|
Fix fault where chronyd enters an endless loop
|
||||||
|
|
||||||
@@ -198,7 +194,7 @@ Victor Moroz <vim@prv.adlum.ru>
|
|||||||
Patch to support Linux with HZ!=100
|
Patch to support Linux with HZ!=100
|
||||||
|
|
||||||
Kalle Olavi Niemitalo <tosi@stekt.oulu.fi>
|
Kalle Olavi Niemitalo <tosi@stekt.oulu.fi>
|
||||||
acquisitionport support
|
Patch to add acquisitionport directive
|
||||||
|
|
||||||
Frank Otto <sandwichmacher@web.de>
|
Frank Otto <sandwichmacher@web.de>
|
||||||
Handling arbitrary HZ values
|
Handling arbitrary HZ values
|
||||||
@@ -206,12 +202,18 @@ Frank Otto <sandwichmacher@web.de>
|
|||||||
Denny Page <dennypage@me.com>
|
Denny Page <dennypage@me.com>
|
||||||
Advice on support for hardware timestamping
|
Advice on support for hardware timestamping
|
||||||
|
|
||||||
|
Chris Perl <cperl@janestreet.com>
|
||||||
|
Patches to improve support for refclocks keeping time in TAI
|
||||||
|
|
||||||
Gautier PHILIPPON <gautier.philippon@ensimag.grenoble-inp.fr>
|
Gautier PHILIPPON <gautier.philippon@ensimag.grenoble-inp.fr>
|
||||||
Patch to add refresh command to chronyc
|
Patch to add refresh command to chronyc
|
||||||
|
|
||||||
Andreas Piesk <apiesk@virbus.de>
|
Andreas Piesk <apiesk@virbus.de>
|
||||||
Patch to make chronyc use the readline library if available
|
Patch to make chronyc use the readline library if available
|
||||||
|
|
||||||
|
Andreas Steinmetz <ast@domdv.de>
|
||||||
|
Patch to make stratum of refclocks configurable
|
||||||
|
|
||||||
Timo Teras <timo.teras@iki.fi>
|
Timo Teras <timo.teras@iki.fi>
|
||||||
Patch to reply correctly on multihomed hosts
|
Patch to reply correctly on multihomed hosts
|
||||||
|
|
||||||
@@ -228,8 +230,7 @@ Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
|
|||||||
Many robustness and security improvements
|
Many robustness and security improvements
|
||||||
|
|
||||||
Ulrich Windl <ulrich.windl@rz.uni-regensburg.de> for the
|
Ulrich Windl <ulrich.windl@rz.uni-regensburg.de> for the
|
||||||
Providing me with information about the Linux 2.2 kernel
|
Information about the Linux 2.2 kernel functionality compared to 2.0
|
||||||
functionality compared to 2.0.
|
|
||||||
|
|
||||||
Doug Woodward <dougw@whistler.com>
|
Doug Woodward <dougw@whistler.com>
|
||||||
Advice on configuring for Solaris 2.8 on x86
|
Advice on configuring for Solaris 2.8 on x86
|
||||||
|
|||||||
7
array.c
7
array.c
@@ -66,8 +66,6 @@ ARR_DestroyInstance(ARR_Instance array)
|
|||||||
static void
|
static void
|
||||||
realloc_array(ARR_Instance array, unsigned int min_size)
|
realloc_array(ARR_Instance array, unsigned int min_size)
|
||||||
{
|
{
|
||||||
size_t data_size;
|
|
||||||
|
|
||||||
assert(min_size <= 2 * min_size);
|
assert(min_size <= 2 * min_size);
|
||||||
if (array->allocated >= min_size && array->allocated <= 2 * min_size)
|
if (array->allocated >= min_size && array->allocated <= 2 * min_size)
|
||||||
return;
|
return;
|
||||||
@@ -79,10 +77,7 @@ realloc_array(ARR_Instance array, unsigned int min_size)
|
|||||||
array->allocated = min_size;
|
array->allocated = min_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
data_size = (size_t)array->elem_size * array->allocated;
|
array->data = Realloc2(array->data, array->allocated, array->elem_size);
|
||||||
assert(data_size / array->elem_size == array->allocated);
|
|
||||||
|
|
||||||
array->data = Realloc(array->data, data_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
|
|||||||
18
candm.h
18
candm.h
@@ -97,7 +97,10 @@
|
|||||||
#define REQ_NTP_DATA 57
|
#define REQ_NTP_DATA 57
|
||||||
#define REQ_ADD_SERVER2 58
|
#define REQ_ADD_SERVER2 58
|
||||||
#define REQ_ADD_PEER2 59
|
#define REQ_ADD_PEER2 59
|
||||||
#define N_REQUEST_TYPES 60
|
#define REQ_ADD_SERVER3 60
|
||||||
|
#define REQ_ADD_PEER3 61
|
||||||
|
#define REQ_SHUTDOWN 62
|
||||||
|
#define N_REQUEST_TYPES 63
|
||||||
|
|
||||||
/* Structure used to exchange timespecs independent of time_t size */
|
/* Structure used to exchange timespecs independent of time_t size */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -250,6 +253,7 @@ typedef struct {
|
|||||||
#define REQ_ADDSRC_TRUST 0x20
|
#define REQ_ADDSRC_TRUST 0x20
|
||||||
#define REQ_ADDSRC_REQUIRE 0x40
|
#define REQ_ADDSRC_REQUIRE 0x40
|
||||||
#define REQ_ADDSRC_INTERLEAVED 0x80
|
#define REQ_ADDSRC_INTERLEAVED 0x80
|
||||||
|
#define REQ_ADDSRC_BURST 0x100
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
IPAddr ip_addr;
|
IPAddr ip_addr;
|
||||||
@@ -267,8 +271,11 @@ typedef struct {
|
|||||||
Float max_delay;
|
Float max_delay;
|
||||||
Float max_delay_ratio;
|
Float max_delay_ratio;
|
||||||
Float max_delay_dev_ratio;
|
Float max_delay_dev_ratio;
|
||||||
|
Float min_delay;
|
||||||
|
Float asymmetry;
|
||||||
Float offset;
|
Float offset;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
|
uint32_t reserved[4];
|
||||||
int32_t EOR;
|
int32_t EOR;
|
||||||
} REQ_NTP_Source;
|
} REQ_NTP_Source;
|
||||||
|
|
||||||
@@ -362,9 +369,9 @@ typedef struct {
|
|||||||
domain socket.
|
domain socket.
|
||||||
|
|
||||||
Version 6 (no authentication) : changed format of client accesses by index
|
Version 6 (no authentication) : changed format of client accesses by index
|
||||||
(using new request/reply types) and manual timestamp, new fields and flags
|
(using new request/reply types) and manual timestamp, added new fields and
|
||||||
in NTP source request and report, new commands: ntpdata, refresh,
|
flags to NTP source request and report, made length of manual list constant,
|
||||||
serverstats
|
added new commands: ntpdata, refresh, serverstats, shutdown
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PROTO_VERSION_NUMBER 6
|
#define PROTO_VERSION_NUMBER 6
|
||||||
@@ -463,7 +470,8 @@ typedef struct {
|
|||||||
#define RPY_CLIENT_ACCESSES_BY_INDEX2 15
|
#define RPY_CLIENT_ACCESSES_BY_INDEX2 15
|
||||||
#define RPY_NTP_DATA 16
|
#define RPY_NTP_DATA 16
|
||||||
#define RPY_MANUAL_TIMESTAMP2 17
|
#define RPY_MANUAL_TIMESTAMP2 17
|
||||||
#define N_REPLY_TYPES 18
|
#define RPY_MANUAL_LIST2 18
|
||||||
|
#define N_REPLY_TYPES 19
|
||||||
|
|
||||||
/* Status codes */
|
/* Status codes */
|
||||||
#define STT_SUCCESS 0
|
#define STT_SUCCESS 0
|
||||||
|
|||||||
112
client.c
112
client.c
@@ -4,7 +4,7 @@
|
|||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) Richard P. Curnow 1997-2003
|
* Copyright (C) Richard P. Curnow 1997-2003
|
||||||
* Copyright (C) Lonnie Abelbeck 2016
|
* Copyright (C) Lonnie Abelbeck 2016
|
||||||
* Copyright (C) Miroslav Lichvar 2009-2016
|
* Copyright (C) Miroslav Lichvar 2009-2017
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of version 2 of the GNU General Public License as
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
@@ -1101,16 +1101,21 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
|
|||||||
msg->data.ntp_source.max_delay_ratio = UTI_FloatHostToNetwork(data.params.max_delay_ratio);
|
msg->data.ntp_source.max_delay_ratio = UTI_FloatHostToNetwork(data.params.max_delay_ratio);
|
||||||
msg->data.ntp_source.max_delay_dev_ratio =
|
msg->data.ntp_source.max_delay_dev_ratio =
|
||||||
UTI_FloatHostToNetwork(data.params.max_delay_dev_ratio);
|
UTI_FloatHostToNetwork(data.params.max_delay_dev_ratio);
|
||||||
|
msg->data.ntp_source.min_delay = UTI_FloatHostToNetwork(data.params.min_delay);
|
||||||
|
msg->data.ntp_source.asymmetry = UTI_FloatHostToNetwork(data.params.asymmetry);
|
||||||
msg->data.ntp_source.offset = UTI_FloatHostToNetwork(data.params.offset);
|
msg->data.ntp_source.offset = UTI_FloatHostToNetwork(data.params.offset);
|
||||||
msg->data.ntp_source.flags = htonl(
|
msg->data.ntp_source.flags = htonl(
|
||||||
(data.params.online ? REQ_ADDSRC_ONLINE : 0) |
|
(data.params.online ? REQ_ADDSRC_ONLINE : 0) |
|
||||||
(data.params.auto_offline ? REQ_ADDSRC_AUTOOFFLINE : 0) |
|
(data.params.auto_offline ? REQ_ADDSRC_AUTOOFFLINE : 0) |
|
||||||
(data.params.iburst ? REQ_ADDSRC_IBURST : 0) |
|
(data.params.iburst ? REQ_ADDSRC_IBURST : 0) |
|
||||||
(data.params.interleaved ? REQ_ADDSRC_INTERLEAVED : 0) |
|
(data.params.interleaved ? REQ_ADDSRC_INTERLEAVED : 0) |
|
||||||
|
(data.params.burst ? REQ_ADDSRC_BURST : 0) |
|
||||||
(data.params.sel_options & SRC_SELECT_PREFER ? REQ_ADDSRC_PREFER : 0) |
|
(data.params.sel_options & SRC_SELECT_PREFER ? REQ_ADDSRC_PREFER : 0) |
|
||||||
(data.params.sel_options & SRC_SELECT_NOSELECT ? REQ_ADDSRC_NOSELECT : 0) |
|
(data.params.sel_options & SRC_SELECT_NOSELECT ? REQ_ADDSRC_NOSELECT : 0) |
|
||||||
(data.params.sel_options & SRC_SELECT_TRUST ? REQ_ADDSRC_TRUST : 0) |
|
(data.params.sel_options & SRC_SELECT_TRUST ? REQ_ADDSRC_TRUST : 0) |
|
||||||
(data.params.sel_options & SRC_SELECT_REQUIRE ? REQ_ADDSRC_REQUIRE : 0));
|
(data.params.sel_options & SRC_SELECT_REQUIRE ? REQ_ADDSRC_REQUIRE : 0));
|
||||||
|
memset(msg->data.ntp_source.reserved, 0, sizeof (msg->data.ntp_source.reserved));
|
||||||
|
|
||||||
result = 1;
|
result = 1;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -1124,7 +1129,7 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
|
|||||||
static int
|
static int
|
||||||
process_cmd_add_server(CMD_Request *msg, char *line)
|
process_cmd_add_server(CMD_Request *msg, char *line)
|
||||||
{
|
{
|
||||||
msg->command = htons(REQ_ADD_SERVER2);
|
msg->command = htons(REQ_ADD_SERVER3);
|
||||||
return process_cmd_add_server_or_peer(msg, line);
|
return process_cmd_add_server_or_peer(msg, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1133,7 +1138,7 @@ process_cmd_add_server(CMD_Request *msg, char *line)
|
|||||||
static int
|
static int
|
||||||
process_cmd_add_peer(CMD_Request *msg, char *line)
|
process_cmd_add_peer(CMD_Request *msg, char *line)
|
||||||
{
|
{
|
||||||
msg->command = htons(REQ_ADD_PEER2);
|
msg->command = htons(REQ_ADD_PEER3);
|
||||||
return process_cmd_add_server_or_peer(msg, line);
|
return process_cmd_add_server_or_peer(msg, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1241,6 +1246,7 @@ give_help(void)
|
|||||||
"cyclelogs\0Close and re-open log files\0"
|
"cyclelogs\0Close and re-open log files\0"
|
||||||
"dump\0Dump all measurements to save files\0"
|
"dump\0Dump all measurements to save files\0"
|
||||||
"rekey\0Re-read keys from key file\0"
|
"rekey\0Re-read keys from key file\0"
|
||||||
|
"shutdown\0Stop daemon\0"
|
||||||
"\0\0"
|
"\0\0"
|
||||||
"Client commands:\0\0"
|
"Client commands:\0\0"
|
||||||
"dns -n|+n\0Disable/enable resolving IP addresses to hostnames\0"
|
"dns -n|+n\0Disable/enable resolving IP addresses to hostnames\0"
|
||||||
@@ -1275,9 +1281,9 @@ command_name_generator(const char *text, int state)
|
|||||||
"maxdelay", "maxdelaydevratio", "maxdelayratio", "maxpoll",
|
"maxdelay", "maxdelaydevratio", "maxdelayratio", "maxpoll",
|
||||||
"maxupdateskew", "minpoll", "minstratum", "ntpdata", "offline", "online",
|
"maxupdateskew", "minpoll", "minstratum", "ntpdata", "offline", "online",
|
||||||
"polltarget", "quit", "refresh", "rekey", "reselect", "reselectdist",
|
"polltarget", "quit", "refresh", "rekey", "reselect", "reselectdist",
|
||||||
"retries", "rtcdata", "serverstats", "settime", "smoothing", "smoothtime",
|
"retries", "rtcdata", "serverstats", "settime", "shutdown", "smoothing",
|
||||||
"sources", "sources -v", "sourcestats", "sourcestats -v", "timeout",
|
"smoothtime", "sources", "sources -v", "sourcestats", "sourcestats -v",
|
||||||
"tracking", "trimrtc", "waitsync", "writertc",
|
"timeout", "tracking", "trimrtc", "waitsync", "writertc",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
static int list_index, len;
|
static int list_index, len;
|
||||||
@@ -1320,18 +1326,16 @@ static int proto_version = PROTO_VERSION_NUMBER;
|
|||||||
static int
|
static int
|
||||||
submit_request(CMD_Request *request, CMD_Reply *reply)
|
submit_request(CMD_Request *request, CMD_Reply *reply)
|
||||||
{
|
{
|
||||||
int bad_length, bad_sequence, bad_header;
|
|
||||||
int select_status;
|
int select_status;
|
||||||
int recv_status;
|
int recv_status;
|
||||||
int read_length;
|
int read_length;
|
||||||
int expected_length;
|
|
||||||
int command_length;
|
int command_length;
|
||||||
int padding_length;
|
int padding_length;
|
||||||
struct timespec ts_now, ts_start;
|
struct timespec ts_now, ts_start;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
int n_attempts, new_attempt;
|
int n_attempts, new_attempt;
|
||||||
double timeout;
|
double timeout;
|
||||||
fd_set rdfd, wrfd, exfd;
|
fd_set rdfd;
|
||||||
|
|
||||||
request->pkt_type = PKT_TYPE_CMD_REQUEST;
|
request->pkt_type = PKT_TYPE_CMD_REQUEST;
|
||||||
request->res1 = 0;
|
request->res1 = 0;
|
||||||
@@ -1343,15 +1347,15 @@ submit_request(CMD_Request *request, CMD_Reply *reply)
|
|||||||
new_attempt = 1;
|
new_attempt = 1;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
if (gettimeofday(&tv, NULL))
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (new_attempt) {
|
if (new_attempt) {
|
||||||
new_attempt = 0;
|
new_attempt = 0;
|
||||||
|
|
||||||
if (n_attempts > max_retries)
|
if (n_attempts > max_retries)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (gettimeofday(&tv, NULL))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
UTI_TimevalToTimespec(&tv, &ts_start);
|
UTI_TimevalToTimespec(&tv, &ts_start);
|
||||||
|
|
||||||
UTI_GetRandomBytes(&request->sequence, sizeof (request->sequence));
|
UTI_GetRandomBytes(&request->sequence, sizeof (request->sequence));
|
||||||
@@ -1379,9 +1383,6 @@ submit_request(CMD_Request *request, CMD_Reply *reply)
|
|||||||
DEBUG_LOG("Sent %d bytes", command_length);
|
DEBUG_LOG("Sent %d bytes", command_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gettimeofday(&tv, NULL))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
UTI_TimevalToTimespec(&tv, &ts_now);
|
UTI_TimevalToTimespec(&tv, &ts_now);
|
||||||
|
|
||||||
/* Check if the clock wasn't stepped back */
|
/* Check if the clock wasn't stepped back */
|
||||||
@@ -1390,22 +1391,27 @@ submit_request(CMD_Request *request, CMD_Reply *reply)
|
|||||||
|
|
||||||
timeout = initial_timeout / 1000.0 * (1U << (n_attempts - 1)) -
|
timeout = initial_timeout / 1000.0 * (1U << (n_attempts - 1)) -
|
||||||
UTI_DiffTimespecsToDouble(&ts_now, &ts_start);
|
UTI_DiffTimespecsToDouble(&ts_now, &ts_start);
|
||||||
UTI_DoubleToTimeval(timeout, &tv);
|
|
||||||
DEBUG_LOG("Timeout %f seconds", timeout);
|
DEBUG_LOG("Timeout %f seconds", timeout);
|
||||||
|
|
||||||
FD_ZERO(&rdfd);
|
/* Avoid calling select() with an invalid timeout */
|
||||||
FD_ZERO(&wrfd);
|
if (timeout <= 0.0) {
|
||||||
FD_ZERO(&exfd);
|
new_attempt = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
UTI_DoubleToTimeval(timeout, &tv);
|
||||||
|
|
||||||
|
FD_ZERO(&rdfd);
|
||||||
FD_SET(sock_fd, &rdfd);
|
FD_SET(sock_fd, &rdfd);
|
||||||
|
|
||||||
if (quit)
|
if (quit)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
select_status = select(sock_fd + 1, &rdfd, &wrfd, &exfd, &tv);
|
select_status = select(sock_fd + 1, &rdfd, NULL, NULL, &tv);
|
||||||
|
|
||||||
if (select_status < 0) {
|
if (select_status < 0) {
|
||||||
DEBUG_LOG("select failed : %s", strerror(errno));
|
DEBUG_LOG("select failed : %s", strerror(errno));
|
||||||
|
return 0;
|
||||||
} else if (select_status == 0) {
|
} else if (select_status == 0) {
|
||||||
/* Timeout must have elapsed, try a resend? */
|
/* Timeout must have elapsed, try a resend? */
|
||||||
new_attempt = 1;
|
new_attempt = 1;
|
||||||
@@ -1421,34 +1427,18 @@ submit_request(CMD_Request *request, CMD_Reply *reply)
|
|||||||
DEBUG_LOG("Received %d bytes", recv_status);
|
DEBUG_LOG("Received %d bytes", recv_status);
|
||||||
|
|
||||||
read_length = recv_status;
|
read_length = recv_status;
|
||||||
if (read_length >= offsetof(CMD_Reply, data)) {
|
|
||||||
expected_length = PKL_ReplyLength(reply);
|
|
||||||
} else {
|
|
||||||
expected_length = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bad_length = (read_length < expected_length ||
|
/* Check if the header is valid */
|
||||||
expected_length < offsetof(CMD_Reply, data));
|
if (read_length < offsetof(CMD_Reply, data) ||
|
||||||
|
(reply->version != proto_version &&
|
||||||
if (!bad_length) {
|
!(reply->version >= PROTO_VERSION_MISMATCH_COMPAT_CLIENT &&
|
||||||
bad_sequence = reply->sequence != request->sequence;
|
ntohs(reply->status) == STT_BADPKTVERSION)) ||
|
||||||
} else {
|
reply->pkt_type != PKT_TYPE_CMD_REPLY ||
|
||||||
bad_sequence = 0;
|
reply->res1 != 0 ||
|
||||||
}
|
reply->res2 != 0 ||
|
||||||
|
reply->command != request->command ||
|
||||||
if (bad_length || bad_sequence) {
|
reply->sequence != request->sequence) {
|
||||||
continue;
|
DEBUG_LOG("Invalid reply");
|
||||||
}
|
|
||||||
|
|
||||||
bad_header = ((reply->version != proto_version &&
|
|
||||||
!(reply->version >= PROTO_VERSION_MISMATCH_COMPAT_CLIENT &&
|
|
||||||
ntohs(reply->status) == STT_BADPKTVERSION)) ||
|
|
||||||
(reply->pkt_type != PKT_TYPE_CMD_REPLY) ||
|
|
||||||
(reply->res1 != 0) ||
|
|
||||||
(reply->res2 != 0) ||
|
|
||||||
(reply->command != request->command));
|
|
||||||
|
|
||||||
if (bad_header) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1467,6 +1457,15 @@ submit_request(CMD_Request *request, CMD_Reply *reply)
|
|||||||
#error unknown compatibility with PROTO_VERSION - 1
|
#error unknown compatibility with PROTO_VERSION - 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Check that the packet contains all data it is supposed to have.
|
||||||
|
Unknown responses will always pass this test as their expected
|
||||||
|
length is zero. */
|
||||||
|
if (read_length < PKL_ReplyLength(reply)) {
|
||||||
|
DEBUG_LOG("Reply too short");
|
||||||
|
new_attempt = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Good packet received, print out results */
|
/* Good packet received, print out results */
|
||||||
DEBUG_LOG("Reply cmd=%d reply=%d stat=%d",
|
DEBUG_LOG("Reply cmd=%d reply=%d stat=%d",
|
||||||
ntohs(reply->command), ntohs(reply->reply), ntohs(reply->status));
|
ntohs(reply->command), ntohs(reply->reply), ntohs(reply->status));
|
||||||
@@ -1573,6 +1572,9 @@ request_reply(CMD_Request *request, CMD_Reply *reply, int requested_reply, int v
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make sure an unknown response was not requested */
|
||||||
|
assert(PKL_ReplyLength(reply));
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2536,7 +2538,7 @@ process_cmd_manual_list(const char *line)
|
|||||||
struct timespec when;
|
struct timespec when;
|
||||||
|
|
||||||
request.command = htons(REQ_MANUAL_LIST);
|
request.command = htons(REQ_MANUAL_LIST);
|
||||||
if (!request_reply(&request, &reply, RPY_MANUAL_LIST, 0))
|
if (!request_reply(&request, &reply, RPY_MANUAL_LIST2, 0))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
n_samples = ntohl(reply.data.manual_list.n_samples);
|
n_samples = ntohl(reply.data.manual_list.n_samples);
|
||||||
@@ -2544,7 +2546,7 @@ process_cmd_manual_list(const char *line)
|
|||||||
|
|
||||||
print_header("# Date Time(UTC) Slewed Original Residual");
|
print_header("# Date Time(UTC) Slewed Original Residual");
|
||||||
|
|
||||||
for (i = 0; i < n_samples; i++) {
|
for (i = 0; i < n_samples && i < MAX_MANUAL_LIST_SAMPLES; i++) {
|
||||||
sample = &reply.data.manual_list.samples[i];
|
sample = &reply.data.manual_list.samples[i];
|
||||||
UTI_TimespecNetworkToHost(&sample->when, &when);
|
UTI_TimespecNetworkToHost(&sample->when, &when);
|
||||||
|
|
||||||
@@ -2705,6 +2707,14 @@ process_cmd_refresh(CMD_Request *msg, char *line)
|
|||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
|
static void
|
||||||
|
process_cmd_shutdown(CMD_Request *msg, char *line)
|
||||||
|
{
|
||||||
|
msg->command = htons(REQ_SHUTDOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
process_cmd_waitsync(char *line)
|
process_cmd_waitsync(char *line)
|
||||||
{
|
{
|
||||||
@@ -3000,6 +3010,8 @@ process_line(char *line)
|
|||||||
} else if (!strcmp(command, "settime")) {
|
} else if (!strcmp(command, "settime")) {
|
||||||
do_normal_submit = 0;
|
do_normal_submit = 0;
|
||||||
ret = process_cmd_settime(line);
|
ret = process_cmd_settime(line);
|
||||||
|
} else if (!strcmp(command, "shutdown")) {
|
||||||
|
process_cmd_shutdown(&tx_message, line);
|
||||||
} else if (!strcmp(command, "smoothing")) {
|
} else if (!strcmp(command, "smoothing")) {
|
||||||
do_normal_submit = 0;
|
do_normal_submit = 0;
|
||||||
ret = process_cmd_smoothing(line);
|
ret = process_cmd_smoothing(line);
|
||||||
@@ -3143,7 +3155,7 @@ main(int argc, char **argv)
|
|||||||
optind = 1;
|
optind = 1;
|
||||||
|
|
||||||
/* Parse short command-line options */
|
/* Parse short command-line options */
|
||||||
while ((opt = getopt(argc, argv, "46acdf:h:mnp:v")) != -1) {
|
while ((opt = getopt(argc, argv, "+46acdf:h:mnp:v")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case '4':
|
case '4':
|
||||||
case '6':
|
case '6':
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) Richard P. Curnow 1997-2003
|
* Copyright (C) Richard P. Curnow 1997-2003
|
||||||
* Copyright (C) Miroslav Lichvar 2009, 2015-2016
|
* Copyright (C) Miroslav Lichvar 2009, 2015-2017
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of version 2 of the GNU General Public License as
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
|
|||||||
39
cmdmon.c
39
cmdmon.c
@@ -136,6 +136,9 @@ static const char permissions[] = {
|
|||||||
PERMIT_AUTH, /* NTP_DATA */
|
PERMIT_AUTH, /* NTP_DATA */
|
||||||
PERMIT_AUTH, /* ADD_SERVER2 */
|
PERMIT_AUTH, /* ADD_SERVER2 */
|
||||||
PERMIT_AUTH, /* ADD_PEER2 */
|
PERMIT_AUTH, /* ADD_PEER2 */
|
||||||
|
PERMIT_AUTH, /* ADD_SERVER3 */
|
||||||
|
PERMIT_AUTH, /* ADD_PEER3 */
|
||||||
|
PERMIT_AUTH, /* SHUTDOWN */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
@@ -276,7 +279,6 @@ do_size_checks(void)
|
|||||||
for (i = 1; i < N_REPLY_TYPES; i++) {
|
for (i = 1; i < N_REPLY_TYPES; i++) {
|
||||||
reply.reply = htons(i);
|
reply.reply = htons(i);
|
||||||
reply.status = STT_SUCCESS;
|
reply.status = STT_SUCCESS;
|
||||||
reply.data.manual_list.n_samples = htonl(MAX_MANUAL_LIST_SAMPLES);
|
|
||||||
reply_length = PKL_ReplyLength(&reply);
|
reply_length = PKL_ReplyLength(&reply);
|
||||||
if ((reply_length && reply_length < offsetof(CMD_Reply, data)) ||
|
if ((reply_length && reply_length < offsetof(CMD_Reply, data)) ||
|
||||||
reply_length > sizeof (CMD_Reply))
|
reply_length > sizeof (CMD_Reply))
|
||||||
@@ -791,12 +793,15 @@ handle_add_source(NTP_Source_Type type, CMD_Request *rx_message, CMD_Reply *tx_m
|
|||||||
UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay_ratio);
|
UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay_ratio);
|
||||||
params.max_delay_dev_ratio =
|
params.max_delay_dev_ratio =
|
||||||
UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay_dev_ratio);
|
UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay_dev_ratio);
|
||||||
|
params.min_delay = UTI_FloatNetworkToHost(rx_message->data.ntp_source.min_delay);
|
||||||
|
params.asymmetry = UTI_FloatNetworkToHost(rx_message->data.ntp_source.asymmetry);
|
||||||
params.offset = UTI_FloatNetworkToHost(rx_message->data.ntp_source.offset);
|
params.offset = UTI_FloatNetworkToHost(rx_message->data.ntp_source.offset);
|
||||||
|
|
||||||
params.online = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_ONLINE ? 1 : 0;
|
params.online = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_ONLINE ? 1 : 0;
|
||||||
params.auto_offline = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_AUTOOFFLINE ? 1 : 0;
|
params.auto_offline = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_AUTOOFFLINE ? 1 : 0;
|
||||||
params.iburst = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_IBURST ? 1 : 0;
|
params.iburst = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_IBURST ? 1 : 0;
|
||||||
params.interleaved = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_INTERLEAVED ? 1 : 0;
|
params.interleaved = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_INTERLEAVED ? 1 : 0;
|
||||||
|
params.burst = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_BURST ? 1 : 0;
|
||||||
params.sel_options =
|
params.sel_options =
|
||||||
(ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_PREFER ? SRC_SELECT_PREFER : 0) |
|
(ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_PREFER ? SRC_SELECT_PREFER : 0) |
|
||||||
(ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_NOSELECT ? SRC_SELECT_NOSELECT : 0) |
|
(ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_NOSELECT ? SRC_SELECT_NOSELECT : 0) |
|
||||||
@@ -1064,9 +1069,6 @@ handle_client_accesses_by_index(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|||||||
tx_message->reply = htons(RPY_CLIENT_ACCESSES_BY_INDEX2);
|
tx_message->reply = htons(RPY_CLIENT_ACCESSES_BY_INDEX2);
|
||||||
tx_message->data.client_accesses_by_index.n_indices = htonl(n_indices);
|
tx_message->data.client_accesses_by_index.n_indices = htonl(n_indices);
|
||||||
|
|
||||||
memset(tx_message->data.client_accesses_by_index.clients, 0,
|
|
||||||
sizeof (tx_message->data.client_accesses_by_index.clients));
|
|
||||||
|
|
||||||
for (i = req_first_index, j = 0; i < (uint32_t)n_indices && j < req_n_clients; i++) {
|
for (i = req_first_index, j = 0; i < (uint32_t)n_indices && j < req_n_clients; i++) {
|
||||||
if (!CLG_GetClientAccessReportByIndex(i, &report, &now))
|
if (!CLG_GetClientAccessReportByIndex(i, &report, &now))
|
||||||
continue;
|
continue;
|
||||||
@@ -1099,10 +1101,11 @@ handle_manual_list(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|||||||
RPY_ManualListSample *sample;
|
RPY_ManualListSample *sample;
|
||||||
RPT_ManualSamplesReport report[MAX_MANUAL_LIST_SAMPLES];
|
RPT_ManualSamplesReport report[MAX_MANUAL_LIST_SAMPLES];
|
||||||
|
|
||||||
tx_message->reply = htons(RPY_MANUAL_LIST);
|
tx_message->reply = htons(RPY_MANUAL_LIST2);
|
||||||
|
|
||||||
MNL_ReportSamples(report, MAX_MANUAL_LIST_SAMPLES, &n_samples);
|
MNL_ReportSamples(report, MAX_MANUAL_LIST_SAMPLES, &n_samples);
|
||||||
tx_message->data.manual_list.n_samples = htonl(n_samples);
|
tx_message->data.manual_list.n_samples = htonl(n_samples);
|
||||||
|
|
||||||
for (i=0; i<n_samples; i++) {
|
for (i=0; i<n_samples; i++) {
|
||||||
sample = &tx_message->data.manual_list.samples[i];
|
sample = &tx_message->data.manual_list.samples[i];
|
||||||
UTI_TimespecHostToNetwork(&report[i].when, &sample->when);
|
UTI_TimespecHostToNetwork(&report[i].when, &sample->when);
|
||||||
@@ -1234,6 +1237,15 @@ handle_ntp_data(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|||||||
memset(tx_message->data.ntp_data.reserved, 0xff, sizeof (tx_message->data.ntp_data.reserved));
|
memset(tx_message->data.ntp_data.reserved, 0xff, sizeof (tx_message->data.ntp_data.reserved));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_shutdown(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||||
|
{
|
||||||
|
LOG(LOGS_INFO, "Received shutdown command");
|
||||||
|
SCH_QuitProgram();
|
||||||
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
/* Read a packet and process it */
|
/* Read a packet and process it */
|
||||||
|
|
||||||
@@ -1325,19 +1337,14 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
|||||||
expected_length = PKL_CommandLength(&rx_message);
|
expected_length = PKL_CommandLength(&rx_message);
|
||||||
rx_command = ntohs(rx_message.command);
|
rx_command = ntohs(rx_message.command);
|
||||||
|
|
||||||
|
memset(&tx_message, 0, sizeof (tx_message));
|
||||||
|
|
||||||
tx_message.version = PROTO_VERSION_NUMBER;
|
tx_message.version = PROTO_VERSION_NUMBER;
|
||||||
tx_message.pkt_type = PKT_TYPE_CMD_REPLY;
|
tx_message.pkt_type = PKT_TYPE_CMD_REPLY;
|
||||||
tx_message.res1 = 0;
|
|
||||||
tx_message.res2 = 0;
|
|
||||||
tx_message.command = rx_message.command;
|
tx_message.command = rx_message.command;
|
||||||
tx_message.reply = htons(RPY_NULL);
|
tx_message.reply = htons(RPY_NULL);
|
||||||
tx_message.status = htons(STT_SUCCESS);
|
tx_message.status = htons(STT_SUCCESS);
|
||||||
tx_message.pad1 = 0;
|
|
||||||
tx_message.pad2 = 0;
|
|
||||||
tx_message.pad3 = 0;
|
|
||||||
tx_message.sequence = rx_message.sequence;
|
tx_message.sequence = rx_message.sequence;
|
||||||
tx_message.pad4 = 0;
|
|
||||||
tx_message.pad5 = 0;
|
|
||||||
|
|
||||||
if (rx_message.version != PROTO_VERSION_NUMBER) {
|
if (rx_message.version != PROTO_VERSION_NUMBER) {
|
||||||
DEBUG_LOG("Command packet has invalid version (%d != %d)",
|
DEBUG_LOG("Command packet has invalid version (%d != %d)",
|
||||||
@@ -1525,11 +1532,11 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
|||||||
handle_cmdaccheck(&rx_message, &tx_message);
|
handle_cmdaccheck(&rx_message, &tx_message);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case REQ_ADD_SERVER2:
|
case REQ_ADD_SERVER3:
|
||||||
handle_add_source(NTP_SERVER, &rx_message, &tx_message);
|
handle_add_source(NTP_SERVER, &rx_message, &tx_message);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case REQ_ADD_PEER2:
|
case REQ_ADD_PEER3:
|
||||||
handle_add_source(NTP_PEER, &rx_message, &tx_message);
|
handle_add_source(NTP_PEER, &rx_message, &tx_message);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1625,6 +1632,10 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
|||||||
handle_ntp_data(&rx_message, &tx_message);
|
handle_ntp_data(&rx_message, &tx_message);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case REQ_SHUTDOWN:
|
||||||
|
handle_shutdown(&rx_message, &tx_message);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DEBUG_LOG("Unhandled command %d", rx_command);
|
DEBUG_LOG("Unhandled command %d", rx_command);
|
||||||
tx_message.status = htons(STT_FAILED);
|
tx_message.status = htons(STT_FAILED);
|
||||||
|
|||||||
11
cmdparse.c
11
cmdparse.c
@@ -51,6 +51,7 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
|
|||||||
src->params.online = 1;
|
src->params.online = 1;
|
||||||
src->params.auto_offline = 0;
|
src->params.auto_offline = 0;
|
||||||
src->params.presend_minpoll = SRC_DEFAULT_PRESEND_MINPOLL;
|
src->params.presend_minpoll = SRC_DEFAULT_PRESEND_MINPOLL;
|
||||||
|
src->params.burst = 0;
|
||||||
src->params.iburst = 0;
|
src->params.iburst = 0;
|
||||||
src->params.min_stratum = SRC_DEFAULT_MINSTRATUM;
|
src->params.min_stratum = SRC_DEFAULT_MINSTRATUM;
|
||||||
src->params.poll_target = SRC_DEFAULT_POLLTARGET;
|
src->params.poll_target = SRC_DEFAULT_POLLTARGET;
|
||||||
@@ -64,6 +65,8 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
|
|||||||
src->params.max_delay = SRC_DEFAULT_MAXDELAY;
|
src->params.max_delay = SRC_DEFAULT_MAXDELAY;
|
||||||
src->params.max_delay_ratio = SRC_DEFAULT_MAXDELAYRATIO;
|
src->params.max_delay_ratio = SRC_DEFAULT_MAXDELAYRATIO;
|
||||||
src->params.max_delay_dev_ratio = SRC_DEFAULT_MAXDELAYDEVRATIO;
|
src->params.max_delay_dev_ratio = SRC_DEFAULT_MAXDELAYDEVRATIO;
|
||||||
|
src->params.min_delay = 0.0;
|
||||||
|
src->params.asymmetry = SRC_DEFAULT_ASYMMETRY;
|
||||||
src->params.offset = 0.0;
|
src->params.offset = 0.0;
|
||||||
|
|
||||||
hostname = line;
|
hostname = line;
|
||||||
@@ -82,6 +85,8 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
|
|||||||
|
|
||||||
if (!strcasecmp(cmd, "auto_offline")) {
|
if (!strcasecmp(cmd, "auto_offline")) {
|
||||||
src->params.auto_offline = 1;
|
src->params.auto_offline = 1;
|
||||||
|
} else if (!strcasecmp(cmd, "burst")) {
|
||||||
|
src->params.burst = 1;
|
||||||
} else if (!strcasecmp(cmd, "iburst")) {
|
} else if (!strcasecmp(cmd, "iburst")) {
|
||||||
src->params.iburst = 1;
|
src->params.iburst = 1;
|
||||||
} else if (!strcasecmp(cmd, "offline")) {
|
} else if (!strcasecmp(cmd, "offline")) {
|
||||||
@@ -98,6 +103,9 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
|
|||||||
if (sscanf(line, "%"SCNu32"%n", &src->params.authkey, &n) != 1 ||
|
if (sscanf(line, "%"SCNu32"%n", &src->params.authkey, &n) != 1 ||
|
||||||
src->params.authkey == INACTIVE_AUTHKEY)
|
src->params.authkey == INACTIVE_AUTHKEY)
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (!strcasecmp(cmd, "asymmetry")) {
|
||||||
|
if (sscanf(line, "%lf%n", &src->params.asymmetry, &n) != 1)
|
||||||
|
return 0;
|
||||||
} else if (!strcasecmp(cmd, "maxdelay")) {
|
} else if (!strcasecmp(cmd, "maxdelay")) {
|
||||||
if (sscanf(line, "%lf%n", &src->params.max_delay, &n) != 1)
|
if (sscanf(line, "%lf%n", &src->params.max_delay, &n) != 1)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -116,6 +124,9 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
|
|||||||
} else if (!strcasecmp(cmd, "maxsources")) {
|
} else if (!strcasecmp(cmd, "maxsources")) {
|
||||||
if (sscanf(line, "%d%n", &src->params.max_sources, &n) != 1)
|
if (sscanf(line, "%d%n", &src->params.max_sources, &n) != 1)
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (!strcasecmp(cmd, "mindelay")) {
|
||||||
|
if (sscanf(line, "%lf%n", &src->params.min_delay, &n) != 1)
|
||||||
|
return 0;
|
||||||
} else if (!strcasecmp(cmd, "minpoll")) {
|
} else if (!strcasecmp(cmd, "minpoll")) {
|
||||||
if (sscanf(line, "%d%n", &src->params.minpoll, &n) != 1)
|
if (sscanf(line, "%d%n", &src->params.minpoll, &n) != 1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
21
conf.c
21
conf.c
@@ -681,7 +681,7 @@ static void
|
|||||||
parse_refclock(char *line)
|
parse_refclock(char *line)
|
||||||
{
|
{
|
||||||
int n, poll, dpoll, filter_length, pps_rate, min_samples, max_samples, sel_options;
|
int n, poll, dpoll, filter_length, pps_rate, min_samples, max_samples, sel_options;
|
||||||
int max_lock_age, pps_forced;
|
int max_lock_age, pps_forced, stratum, tai;
|
||||||
uint32_t ref_id, lock_ref_id;
|
uint32_t ref_id, lock_ref_id;
|
||||||
double offset, delay, precision, max_dispersion, pulse_width;
|
double offset, delay, precision, max_dispersion, pulse_width;
|
||||||
char *p, *cmd, *name, *param;
|
char *p, *cmd, *name, *param;
|
||||||
@@ -704,6 +704,8 @@ parse_refclock(char *line)
|
|||||||
ref_id = 0;
|
ref_id = 0;
|
||||||
max_lock_age = 2;
|
max_lock_age = 2;
|
||||||
lock_ref_id = 0;
|
lock_ref_id = 0;
|
||||||
|
stratum = 0;
|
||||||
|
tai = 0;
|
||||||
|
|
||||||
if (!*line) {
|
if (!*line) {
|
||||||
command_parse_error();
|
command_parse_error();
|
||||||
@@ -774,6 +776,13 @@ parse_refclock(char *line)
|
|||||||
} else if (!strcasecmp(cmd, "maxdispersion")) {
|
} else if (!strcasecmp(cmd, "maxdispersion")) {
|
||||||
if (sscanf(line, "%lf%n", &max_dispersion, &n) != 1)
|
if (sscanf(line, "%lf%n", &max_dispersion, &n) != 1)
|
||||||
break;
|
break;
|
||||||
|
} else if (!strcasecmp(cmd, "stratum")) {
|
||||||
|
if (sscanf(line, "%d%n", &stratum, &n) != 1 ||
|
||||||
|
stratum >= NTP_MAX_STRATUM || stratum < 0)
|
||||||
|
break;
|
||||||
|
} else if (!strcasecmp(cmd, "tai")) {
|
||||||
|
n = 0;
|
||||||
|
tai = 1;
|
||||||
} else if (!strcasecmp(cmd, "width")) {
|
} else if (!strcasecmp(cmd, "width")) {
|
||||||
if (sscanf(line, "%lf%n", &pulse_width, &n) != 1)
|
if (sscanf(line, "%lf%n", &pulse_width, &n) != 1)
|
||||||
break;
|
break;
|
||||||
@@ -811,6 +820,8 @@ parse_refclock(char *line)
|
|||||||
refclock->min_samples = min_samples;
|
refclock->min_samples = min_samples;
|
||||||
refclock->max_samples = max_samples;
|
refclock->max_samples = max_samples;
|
||||||
refclock->sel_options = sel_options;
|
refclock->sel_options = sel_options;
|
||||||
|
refclock->stratum = stratum;
|
||||||
|
refclock->tai = tai;
|
||||||
refclock->offset = offset;
|
refclock->offset = offset;
|
||||||
refclock->delay = delay;
|
refclock->delay = delay;
|
||||||
refclock->precision = precision;
|
refclock->precision = precision;
|
||||||
@@ -1281,7 +1292,7 @@ parse_hwtimestamp(char *line)
|
|||||||
iface->name = Strdup(p);
|
iface->name = Strdup(p);
|
||||||
iface->minpoll = 0;
|
iface->minpoll = 0;
|
||||||
iface->nocrossts = 0;
|
iface->nocrossts = 0;
|
||||||
iface->rxfilter = CNF_HWTS_RXFILTER_NTP;
|
iface->rxfilter = CNF_HWTS_RXFILTER_ANY;
|
||||||
iface->precision = 100.0e-9;
|
iface->precision = 100.0e-9;
|
||||||
iface->tx_comp = 0.0;
|
iface->tx_comp = 0.0;
|
||||||
iface->rx_comp = 0.0;
|
iface->rx_comp = 0.0;
|
||||||
@@ -1335,7 +1346,11 @@ parse_include(char *line)
|
|||||||
|
|
||||||
check_number_of_args(line, 1);
|
check_number_of_args(line, 1);
|
||||||
|
|
||||||
if ((r = glob(line, GLOB_ERR | GLOB_NOMAGIC, NULL, &gl)) != 0) {
|
if ((r = glob(line,
|
||||||
|
#ifdef GLOB_NOMAGIC
|
||||||
|
GLOB_NOMAGIC |
|
||||||
|
#endif
|
||||||
|
GLOB_ERR, NULL, &gl)) != 0) {
|
||||||
if (r != GLOB_NOMATCH)
|
if (r != GLOB_NOMATCH)
|
||||||
LOG_FATAL("Could not search for files matching %s", line);
|
LOG_FATAL("Could not search for files matching %s", line);
|
||||||
|
|
||||||
|
|||||||
11
conf.h
11
conf.h
@@ -118,15 +118,18 @@ extern char *CNF_GetHwclockFile(void);
|
|||||||
extern int CNF_GetInitSources(void);
|
extern int CNF_GetInitSources(void);
|
||||||
extern double CNF_GetInitStepThreshold(void);
|
extern double CNF_GetInitStepThreshold(void);
|
||||||
|
|
||||||
#define CNF_HWTS_RXFILTER_NONE 0
|
typedef enum {
|
||||||
#define CNF_HWTS_RXFILTER_NTP 1
|
CNF_HWTS_RXFILTER_ANY,
|
||||||
#define CNF_HWTS_RXFILTER_ALL 2
|
CNF_HWTS_RXFILTER_NONE,
|
||||||
|
CNF_HWTS_RXFILTER_NTP,
|
||||||
|
CNF_HWTS_RXFILTER_ALL,
|
||||||
|
} CNF_HwTs_RxFilter;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *name;
|
char *name;
|
||||||
int minpoll;
|
int minpoll;
|
||||||
int nocrossts;
|
int nocrossts;
|
||||||
int rxfilter;
|
CNF_HwTs_RxFilter rxfilter;
|
||||||
double precision;
|
double precision;
|
||||||
double tx_comp;
|
double tx_comp;
|
||||||
double rx_comp;
|
double rx_comp;
|
||||||
|
|||||||
29
configure
vendored
29
configure
vendored
@@ -85,6 +85,7 @@ For better control, use the options below.
|
|||||||
--with-readline-library=DIR Specify where readline lib directory is
|
--with-readline-library=DIR Specify where readline lib directory is
|
||||||
--with-ncurses-library=DIR Specify where ncurses lib directory is
|
--with-ncurses-library=DIR Specify where ncurses lib directory is
|
||||||
--disable-sechash Disable support for hashes other than MD5
|
--disable-sechash Disable support for hashes other than MD5
|
||||||
|
--without-nettle Don't use nettle even if it is available
|
||||||
--without-nss Don't use NSS even if it is available
|
--without-nss Don't use NSS even if it is available
|
||||||
--without-tomcrypt Don't use libtomcrypt even if it is available
|
--without-tomcrypt Don't use libtomcrypt even if it is available
|
||||||
--disable-cmdmon Disable command and monitoring support
|
--disable-cmdmon Disable command and monitoring support
|
||||||
@@ -198,6 +199,7 @@ feat_readline=1
|
|||||||
try_readline=1
|
try_readline=1
|
||||||
try_editline=1
|
try_editline=1
|
||||||
feat_sechash=1
|
feat_sechash=1
|
||||||
|
try_nettle=1
|
||||||
try_nss=1
|
try_nss=1
|
||||||
try_tomcrypt=1
|
try_tomcrypt=1
|
||||||
feat_rtc=1
|
feat_rtc=1
|
||||||
@@ -360,6 +362,9 @@ do
|
|||||||
--disable-sechash )
|
--disable-sechash )
|
||||||
feat_sechash=0
|
feat_sechash=0
|
||||||
;;
|
;;
|
||||||
|
--without-nettle )
|
||||||
|
try_nettle=0
|
||||||
|
;;
|
||||||
--without-nss )
|
--without-nss )
|
||||||
try_nss=0
|
try_nss=0
|
||||||
;;
|
;;
|
||||||
@@ -550,7 +555,11 @@ then
|
|||||||
split_seconds=$ntp_era_split
|
split_seconds=$ntp_era_split
|
||||||
split_days=0
|
split_days=0
|
||||||
else
|
else
|
||||||
split_seconds=`date '+%s'`
|
if [ "x$SOURCE_DATE_EPOCH" != "x" ]; then
|
||||||
|
split_seconds=$SOURCE_DATE_EPOCH
|
||||||
|
else
|
||||||
|
split_seconds=`date '+%s'`
|
||||||
|
fi
|
||||||
if [ "x$split_seconds" = "x" ]; then
|
if [ "x$split_seconds" = "x" ]; then
|
||||||
echo "error: could not get current time, --with-ntp-era option is needed"
|
echo "error: could not get current time, --with-ntp-era option is needed"
|
||||||
exit 1
|
exit 1
|
||||||
@@ -696,6 +705,7 @@ then
|
|||||||
struct scm_ts_pktinfo pktinfo;
|
struct scm_ts_pktinfo pktinfo;
|
||||||
pktinfo.if_index = pktinfo.pkt_length = 0;
|
pktinfo.if_index = pktinfo.pkt_length = 0;
|
||||||
return pktinfo.if_index + pktinfo.pkt_length + HWTSTAMP_FILTER_NTP_ALL +
|
return pktinfo.if_index + pktinfo.pkt_length + HWTSTAMP_FILTER_NTP_ALL +
|
||||||
|
SCM_TIMESTAMPING_PKTINFO +
|
||||||
SOF_TIMESTAMPING_OPT_PKTINFO + SOF_TIMESTAMPING_OPT_TX_SWHW;'; then
|
SOF_TIMESTAMPING_OPT_PKTINFO + SOF_TIMESTAMPING_OPT_TX_SWHW;'; then
|
||||||
add_def HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP 1
|
add_def HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP 1
|
||||||
add_def HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO 1
|
add_def HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO 1
|
||||||
@@ -852,7 +862,22 @@ fi
|
|||||||
HASH_OBJ="hash_intmd5.o"
|
HASH_OBJ="hash_intmd5.o"
|
||||||
HASH_LINK=""
|
HASH_LINK=""
|
||||||
|
|
||||||
if [ $feat_sechash = "1" ] && [ $try_nss = "1" ]; then
|
if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_nettle = "1" ]; then
|
||||||
|
test_cflags="`pkg_config --cflags nettle`"
|
||||||
|
test_link="`pkg_config --libs nettle`"
|
||||||
|
if test_code 'nettle' 'nettle/nettle-meta.h nettle/sha2.h' \
|
||||||
|
"$test_cflags" "$test_link" \
|
||||||
|
'return nettle_hashes[0]->context_size;'
|
||||||
|
then
|
||||||
|
HASH_OBJ="hash_nettle.o"
|
||||||
|
HASH_LINK="$test_link"
|
||||||
|
LIBS="$LIBS $HASH_LINK"
|
||||||
|
MYCPPFLAGS="$MYCPPFLAGS $test_cflags"
|
||||||
|
add_def FEAT_SECHASH
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_nss = "1" ]; then
|
||||||
test_cflags="`pkg_config --cflags nss`"
|
test_cflags="`pkg_config --cflags nss`"
|
||||||
test_link="`pkg_config --libs-only-L nss` -lfreebl3"
|
test_link="`pkg_config --libs-only-L nss` -lfreebl3"
|
||||||
if test_code 'NSS' 'nss.h hasht.h nsslowhash.h' \
|
if test_code 'NSS' 'nss.h hasht.h nsslowhash.h' \
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright (C) Richard P. Curnow 1997-2003
|
// Copyright (C) Richard P. Curnow 1997-2003
|
||||||
// Copyright (C) Stephen Wadeley 2016
|
// Copyright (C) Stephen Wadeley 2016
|
||||||
|
// Copyright (C) Bryan Christianson 2017
|
||||||
// Copyright (C) Miroslav Lichvar 2009-2017
|
// Copyright (C) Miroslav Lichvar 2009-2017
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or modify
|
// This program is free software; you can redistribute it and/or modify
|
||||||
@@ -65,33 +66,40 @@ server, or its IP address. The *server* directive supports the following
|
|||||||
options:
|
options:
|
||||||
+
|
+
|
||||||
*minpoll* _poll_:::
|
*minpoll* _poll_:::
|
||||||
Although *chronyd* will trim the rate at which it samples the server during
|
This option specifies the minimum interval between requests sent to the server
|
||||||
normal operation, the user might want to constrain the minimum polling interval.
|
as a power of 2 in seconds. For example, *minpoll 5* would mean that the
|
||||||
This is always defined as a power of 2, so *minpoll 5* would mean that the
|
polling interval should not drop below 32 seconds. The default is 6 (64
|
||||||
polling interval cannot drop below 32 seconds. The default is 6 (64 seconds),
|
seconds), the minimum is -4 (1/16th of a second), and the maximum is 24 (6
|
||||||
the minimum is -4 (1/16th of a second), and the maximum is 24 (6 months). Note
|
months). Note that intervals shorter than 6 (64 seconds) should generally not
|
||||||
that intervals shorter than 6 (64 seconds) should generally not be used with
|
be used with public servers on the Internet, because it might be considered
|
||||||
public servers on the Internet, because it might be considered abuse.
|
abuse.
|
||||||
*maxpoll* _poll_:::
|
*maxpoll* _poll_:::
|
||||||
In a similar way, the user might want to constrain the maximum polling interval.
|
This option specifies the maximum interval between requests sent to the server
|
||||||
Again this is specified as a power of 2, *maxpoll 9* indicates that the polling
|
as a power of 2 in seconds. For example, *maxpoll 9* indicates that the polling
|
||||||
interval must stay at or below 512 seconds. The default is 10 (1024 seconds),
|
interval should stay at or below 9 (512 seconds). The default is 10 (1024
|
||||||
the minimum is 0 (1 second), and the maximum is 24 (6 months).
|
seconds), the minimum is 0 (1 second), and the maximum is 24 (6 months).
|
||||||
*iburst*:::
|
*iburst*:::
|
||||||
If this option is set, the interval between the first four polls will be 2
|
With this option, the interval between the first four requests sent to the
|
||||||
seconds instead of _minpoll_. This is useful to quickly get the first update of
|
server will be 2 seconds instead of the interval specified by the *minpoll*
|
||||||
the clock after *chronyd* is started.
|
option, which allows *chronyd* to make the first update of the clock shortly
|
||||||
*key* _id_:::
|
after start.
|
||||||
|
*burst*:::
|
||||||
|
With this option, *chronyd* will shorten the interval between up to four
|
||||||
|
requests to 2 seconds when it cannot get a good measurement from the server.
|
||||||
|
The number of requests in the burst is limited by the current polling interval
|
||||||
|
to keep the average interval at or above the minimum interval, i.e. the current
|
||||||
|
interval needs to be at least two times longer than the minimum interval in
|
||||||
|
order to allow a burst with two requests.
|
||||||
|
*key* _ID_:::
|
||||||
The NTP protocol supports the inclusion of checksums in the packets, to prevent
|
The NTP protocol supports the inclusion of checksums in the packets, to prevent
|
||||||
computers having their system time upset by rogue packets being sent to them.
|
computers having their system time upset by rogue packets being sent to them.
|
||||||
The checksums are generated as a function of a password, using the
|
The checksums are generated as a function of a password, using the
|
||||||
cryptographic hash function set in the key file, which is specified by the
|
cryptographic hash function set in the key file, which is specified by the
|
||||||
<<keyfile,*keyfile*>> directive.
|
<<keyfile,*keyfile*>> directive.
|
||||||
+
|
+
|
||||||
If the key option is present, *chronyd* will attempt to use authenticated
|
The *key* option specifies which key (with an ID in the range 1 through 2^32-1)
|
||||||
packets when communicating with this server. The key number used will be the
|
should *chronyd* use to authenticate requests sent to the server and verify its
|
||||||
single argument to the key option (an unsigned integer in the range 1 through
|
responses. The server must have the same key for this number configured,
|
||||||
2^32-1). The server must have the same password for this key number configured,
|
|
||||||
otherwise no relationship between the computers will be possible.
|
otherwise no relationship between the computers will be possible.
|
||||||
*maxdelay* _delay_:::
|
*maxdelay* _delay_:::
|
||||||
*chronyd* uses the network round-trip delay to the server to determine how
|
*chronyd* uses the network round-trip delay to the server to determine how
|
||||||
@@ -112,16 +120,28 @@ option. For example, *maxdelay 0.3* would indicate that measurements with a
|
|||||||
round-trip delay of 0.3 seconds or more should be ignored. The default value is
|
round-trip delay of 0.3 seconds or more should be ignored. The default value is
|
||||||
3 seconds and the maximum value is 1000 seconds.
|
3 seconds and the maximum value is 1000 seconds.
|
||||||
*maxdelayratio* _ratio_:::
|
*maxdelayratio* _ratio_:::
|
||||||
This option is similar to the maxdelay option above. *chronyd* keeps a record
|
This option is similar to the *maxdelay* option above. *chronyd* keeps a record
|
||||||
of the minimum round-trip delay amongst the previous measurements that it has
|
of the minimum round-trip delay amongst the previous measurements that it has
|
||||||
buffered. If a measurement has a round trip delay that is greater than the
|
buffered. If a measurement has a round trip delay that is greater than the
|
||||||
maxdelayratio times the minimum delay, it will be rejected. This option works
|
maxdelayratio times the minimum delay, it will be rejected.
|
||||||
only in the *server* directive when not in the interleaved mode.
|
|
||||||
*maxdelaydevratio* _ratio_:::
|
*maxdelaydevratio* _ratio_:::
|
||||||
If a measurement has a ratio of the increase in the round-trip delay from the
|
If a measurement has a ratio of the increase in the round-trip delay from the
|
||||||
minimum delay amongst the previous measurements to the standard deviation of
|
minimum delay amongst the previous measurements to the standard deviation of
|
||||||
the previous measurements that is greater than the specified ratio, it will be
|
the previous measurements that is greater than the specified ratio, it will be
|
||||||
rejected. The default is 10.0.
|
rejected. The default is 10.0.
|
||||||
|
*mindelay* _delay_:::
|
||||||
|
This option specifies a fixed minimum round-trip delay to be used instead of
|
||||||
|
the minimum amongst the previous measurements. This can be useful in networks
|
||||||
|
with static configuration to improve the stability of corrections for
|
||||||
|
asymmetric jitter, weighting of the measurements, and the *maxdelayratio* and
|
||||||
|
*maxdelaydevratio* tests. The value should be set accurately in order to have a
|
||||||
|
positive effect on the synchronisation.
|
||||||
|
*asymmetry* _ratio_:::
|
||||||
|
This option specifies the asymmetry of the network jitter on the path to the
|
||||||
|
source, which is used to correct the measured offset according to the delay.
|
||||||
|
The asymmetry can be between -0.5 and +0.5. A negative value means the delay of
|
||||||
|
packets sent to the source is more variable than the delay of packets sent from
|
||||||
|
the source back. By default, *chronyd* estimates the asymmetry automatically.
|
||||||
*offset* _offset_:::
|
*offset* _offset_:::
|
||||||
This option specifies a correction (in seconds) which will be applied to
|
This option specifies a correction (in seconds) which will be applied to
|
||||||
offsets measured with this source. It's particularly useful to compensate for a
|
offsets measured with this source. It's particularly useful to compensate for a
|
||||||
@@ -141,14 +161,15 @@ option can be specified. *chronyd* will not try to poll the server until it is
|
|||||||
enabled to do so (by using the <<chronyc.adoc#online,*online*>> command in
|
enabled to do so (by using the <<chronyc.adoc#online,*online*>> command in
|
||||||
*chronyc*).
|
*chronyc*).
|
||||||
*auto_offline*:::
|
*auto_offline*:::
|
||||||
If this option is set, the server will be assumed to have gone offline when 2
|
With this option, the server will be assumed to have gone offline when two
|
||||||
requests have been sent to it without receiving a response. This option avoids
|
requests have been sent to it without receiving a response. This option avoids
|
||||||
the need to run the <<chronyc.adoc#offline,*offline*>> command from *chronyc*
|
the need to run the <<chronyc.adoc#offline,*offline*>> command from *chronyc*
|
||||||
when disconnecting the network link. (It will still be necessary to use the
|
when disconnecting the network link, if it is safe to assume that the requests
|
||||||
<<chronyc.adoc#online,*online*>> command when the link has been established, to
|
and responses will not be dropped in the network, e.g. in a trusted local
|
||||||
enable measurements to start.)
|
network. (It will still be necessary to use the <<chronyc.adoc#online,*online*>>
|
||||||
|
command when the link has been established, to enable measurements to start.)
|
||||||
*prefer*:::
|
*prefer*:::
|
||||||
Prefer this source over sources without prefer option.
|
Prefer this source over sources without the *prefer* option.
|
||||||
*noselect*:::
|
*noselect*:::
|
||||||
Never select this source. This is particularly useful for monitoring.
|
Never select this source. This is particularly useful for monitoring.
|
||||||
*trust*:::
|
*trust*:::
|
||||||
@@ -178,10 +199,9 @@ and the state might be dropped when there are too many clients (e.g.
|
|||||||
by other clients that have the same IP address (e.g. computers behind NAT or
|
by other clients that have the same IP address (e.g. computers behind NAT or
|
||||||
someone sending requests with a spoofed source address).
|
someone sending requests with a spoofed source address).
|
||||||
+
|
+
|
||||||
With longer polling intervals, it is recommended to combine the *xleave* option
|
The *xleave* option can be combined with the *presend* option in order to
|
||||||
with the *presend* option in order to shorten the interval in which the server
|
shorten the interval in which the server has to keep the state to be able to
|
||||||
has to keep the state to be able to respond in the interleaved mode. The
|
respond in the interleaved mode.
|
||||||
shorter interval also improves accuracy of the measured offset and delay.
|
|
||||||
*polltarget* _target_:::
|
*polltarget* _target_:::
|
||||||
Target number of measurements to use for the regression algorithm which
|
Target number of measurements to use for the regression algorithm which
|
||||||
*chronyd* will try to maintain by adjusting the polling interval between
|
*chronyd* will try to maintain by adjusting the polling interval between
|
||||||
@@ -488,7 +508,7 @@ This option specifies the width of the pulses (in seconds). It is used to
|
|||||||
filter PPS samples when the driver provides samples for both rising and falling
|
filter PPS samples when the driver provides samples for both rising and falling
|
||||||
edges. Note that it reduces the maximum allowed error of the time source which
|
edges. Note that it reduces the maximum allowed error of the time source which
|
||||||
completes the PPS samples. If the duty cycle is configurable, 50% should be
|
completes the PPS samples. If the duty cycle is configurable, 50% should be
|
||||||
prefered in order to maximise the allowed error.
|
preferred in order to maximise the allowed error.
|
||||||
*pps*:::
|
*pps*:::
|
||||||
This options forces *chronyd* to treat any refclock (e.g. SHM or PHC) as a PPS
|
This options forces *chronyd* to treat any refclock (e.g. SHM or PHC) as a PPS
|
||||||
refclock. This can be useful when the refclock provides time with a variable
|
refclock. This can be useful when the refclock provides time with a variable
|
||||||
@@ -504,6 +524,9 @@ is included in the maximum assumed error which is used in the source selection
|
|||||||
algorithm. Increasing the delay is useful to avoid having no majority in the
|
algorithm. Increasing the delay is useful to avoid having no majority in the
|
||||||
source selection or to make it prefer other sources. The default is 1e-9 (1
|
source selection or to make it prefer other sources. The default is 1e-9 (1
|
||||||
nanosecond).
|
nanosecond).
|
||||||
|
*stratum* _stratum_:::
|
||||||
|
This option sets the NTP stratum of the refclock. This can be useful when the
|
||||||
|
refclock provides time with a stratum other than 0. The default is 0.
|
||||||
*precision* _precision_:::
|
*precision* _precision_:::
|
||||||
This option sets the precision of the reference clock (in seconds). The default
|
This option sets the precision of the reference clock (in seconds). The default
|
||||||
value is the estimated precision of the system clock.
|
value is the estimated precision of the system clock.
|
||||||
@@ -534,6 +557,12 @@ but not very precise, reference clock to be safely combined with
|
|||||||
unauthenticated NTP sources in order to improve the accuracy of the clock. They
|
unauthenticated NTP sources in order to improve the accuracy of the clock. They
|
||||||
can be selected and used for synchronisation only if they agree with the
|
can be selected and used for synchronisation only if they agree with the
|
||||||
trusted and required source.
|
trusted and required source.
|
||||||
|
*tai*:::
|
||||||
|
This option indicates that the reference clock keeps time in TAI instead of UTC
|
||||||
|
and that *chronyd* should correct its offset by the current TAI-UTC offset. The
|
||||||
|
<<leapsectz,*leapsectz*>> directive must be used with this option and the
|
||||||
|
database must be kept up to date in order for this correction to work as
|
||||||
|
expected. This option does not make sense with PPS refclocks.
|
||||||
*minsamples* _samples_:::
|
*minsamples* _samples_:::
|
||||||
Set the minimum number of samples kept for this source. This overrides the
|
Set the minimum number of samples kept for this source. This overrides the
|
||||||
<<minsamples,*minsamples*>> directive.
|
<<minsamples,*minsamples*>> directive.
|
||||||
@@ -850,6 +879,11 @@ It is also useful when the system clock is required to have correct TAI-UTC
|
|||||||
offset. Note that the offset is set only when leap seconds are handled by the
|
offset. Note that the offset is set only when leap seconds are handled by the
|
||||||
kernel, i.e. <<leapsecmode,*leapsecmode*>> is set to *system*.
|
kernel, i.e. <<leapsecmode,*leapsecmode*>> is set to *system*.
|
||||||
+
|
+
|
||||||
|
The specified timezone is not used as an exclusive source of information about
|
||||||
|
leap seconds. If a majority of time sources announce on the last day of June or
|
||||||
|
December that a leap second should be inserted or deleted, it will be accepted
|
||||||
|
even if it is not included in the timezone.
|
||||||
|
+
|
||||||
An example of the directive is:
|
An example of the directive is:
|
||||||
+
|
+
|
||||||
----
|
----
|
||||||
@@ -1611,7 +1645,7 @@ from the example line above):
|
|||||||
. The root dispersion (_EPSILON_ in RFC 5905). [7.446e-03]
|
. The root dispersion (_EPSILON_ in RFC 5905). [7.446e-03]
|
||||||
. Reference ID of the server's source as a hexadecimal number. [CB00717B]
|
. Reference ID of the server's source as a hexadecimal number. [CB00717B]
|
||||||
. NTP mode of the received packet (_1_=active peer, _2_=passive peer,
|
. NTP mode of the received packet (_1_=active peer, _2_=passive peer,
|
||||||
_3_=server, _B_=basic, _I_=interleaved). [4B]
|
_4_=server, _B_=basic, _I_=interleaved). [4B]
|
||||||
. Source of the local transmit timestamp
|
. Source of the local transmit timestamp
|
||||||
(_D_=daemon, _K_=kernel, _H_=hardware). [D]
|
(_D_=daemon, _K_=kernel, _H_=hardware). [D]
|
||||||
. Source of the local receive timestamp
|
. Source of the local receive timestamp
|
||||||
@@ -1665,11 +1699,11 @@ from the example line above):
|
|||||||
to be discarded. The number of runs for the data that is being retained is
|
to be discarded. The number of runs for the data that is being retained is
|
||||||
tabulated. Values of approximately half the number of samples are expected.
|
tabulated. Values of approximately half the number of samples are expected.
|
||||||
[8]
|
[8]
|
||||||
. The estimated asymmetry of network jitter on the path to the source which was
|
. The estimated or configured asymmetry of network jitter on the path to the
|
||||||
used to correct the measured offsets. The asymmetry can be between -0.5 and
|
source which was used to correct the measured offsets. The asymmetry can be
|
||||||
0.5. A negative value means the delay of packets sent to the source is
|
between -0.5 and +0.5. A negative value means the delay of packets sent to
|
||||||
more variable than the delay of packets sent from the source back. [0.00,
|
the source is more variable than the delay of packets sent from the source
|
||||||
i.e. no correction for asymmetry]
|
back. [0.00, i.e. no correction for asymmetry]
|
||||||
+
|
+
|
||||||
*tracking*:::
|
*tracking*:::
|
||||||
This option logs changes to the estimate of the system's gain or loss rate, and
|
This option logs changes to the estimate of the system's gain or loss rate, and
|
||||||
@@ -1678,33 +1712,42 @@ actually appears as a single line in the file) from the log file is shown
|
|||||||
below.
|
below.
|
||||||
+
|
+
|
||||||
----
|
----
|
||||||
2015-02-23 05:40:50 203.0.113.15 3 340.529 1.606 1.046e-03 N \
|
2017-08-22 13:22:36 203.0.113.15 2 -3.541 0.075 -8.621e-06 N \
|
||||||
4 6.849e-03 -4.670e-04
|
2 2.940e-03 -2.084e-04 1.534e-02 3.472e-04 8.304e-03
|
||||||
----
|
----
|
||||||
+
|
+
|
||||||
The columns are as follows (the quantities in square brackets are the
|
The columns are as follows (the quantities in square brackets are the
|
||||||
values from the example line above) :
|
values from the example line above) :
|
||||||
+
|
+
|
||||||
. Date [2015-02-03]
|
. Date [2017-08-22]
|
||||||
. Hour:Minute:Second. Note that the date-time pair is expressed in UTC, not the
|
. Hour:Minute:Second. Note that the date-time pair is expressed in UTC, not the
|
||||||
local time zone. [05:40:50]
|
local time zone. [13:22:36]
|
||||||
. The IP address of the server or peer to which the local system is synchronised.
|
. The IP address of the server or peer to which the local system is synchronised.
|
||||||
[203.0.113.15]
|
[203.0.113.15]
|
||||||
. The stratum of the local system. [3]
|
. The stratum of the local system. [2]
|
||||||
. The local system frequency (in ppm, positive means the local system runs fast
|
. The local system frequency (in ppm, positive means the local system runs fast
|
||||||
of UTC). [340.529]
|
of UTC). [-3.541]
|
||||||
. The error bounds on the frequency (in ppm). [1.606]
|
. The error bounds on the frequency (in ppm). [0.075]
|
||||||
. The estimated local offset at the epoch (which is rapidly corrected by
|
. The estimated local offset at the epoch, which is normally corrected by
|
||||||
slewing the local clock. (In seconds, positive indicates the local system
|
slewing the local clock (in seconds, positive indicates the clock is fast of
|
||||||
is fast of UTC). [1.046e-3]
|
UTC). [-8.621e-06]
|
||||||
. Leap status (_N_ means normal, _+_ means that the last minute of this month
|
. Leap status (_N_ means normal, _+_ means that the last minute of this month
|
||||||
has 61 seconds, _-_ means that the last minute of the month has 59 seconds,
|
has 61 seconds, _-_ means that the last minute of the month has 59 seconds,
|
||||||
_?_ means the clock is not currently synchronised.) [N]
|
_?_ means the clock is not currently synchronised.) [N]
|
||||||
. The number of combined sources. [4]
|
. The number of combined sources. [2]
|
||||||
. The estimated standard deviation of the combined offset (in seconds).
|
. The estimated standard deviation of the combined offset (in seconds).
|
||||||
[6.849e-03]
|
[2.940e-03]
|
||||||
. The remaining offset correction from the previous update (in seconds,
|
. The remaining offset correction from the previous update (in seconds,
|
||||||
positive means the system clock is slow of UTC). [-4.670e-04]
|
positive means the system clock is slow of UTC). [-2.084e-04]
|
||||||
|
. The total of the network path delays to the reference clock to which
|
||||||
|
the local clock is ultimately synchronised (in seconds). [1.534e-02]
|
||||||
|
. The total dispersion accumulated through all the servers back to the
|
||||||
|
reference clock to which the local clock is ultimately synchronised
|
||||||
|
(in seconds). [3.472e-04]
|
||||||
|
. The maximum estimated error of the system clock in the interval since the
|
||||||
|
previous update (in seconds). It includes the offset, remaining offset
|
||||||
|
correction, root delay, and dispersion from the previous update with the
|
||||||
|
dispersion which accumulated in the interval. [8.304e-03]
|
||||||
+
|
+
|
||||||
*rtc*:::
|
*rtc*:::
|
||||||
This option logs information about the system's real-time clock. An example
|
This option logs information about the system's real-time clock. An example
|
||||||
@@ -1865,20 +1908,18 @@ be enabled by the *xleave* option in the <<server,*server*>> or the
|
|||||||
This directive is supported on Linux 3.19 and newer. The NIC must support HW
|
This directive is supported on Linux 3.19 and newer. The NIC must support HW
|
||||||
timestamping, which can be verified with the *ethtool -T* command. The list of
|
timestamping, which can be verified with the *ethtool -T* command. The list of
|
||||||
capabilities should include _SOF_TIMESTAMPING_RAW_HARDWARE_,
|
capabilities should include _SOF_TIMESTAMPING_RAW_HARDWARE_,
|
||||||
_SOF_TIMESTAMPING_TX_HARDWARE_, _SOF_TIMESTAMPING_RX_HARDWARE_, and the filter
|
_SOF_TIMESTAMPING_TX_HARDWARE_, and _SOF_TIMESTAMPING_RX_HARDWARE_. Receive
|
||||||
modes should include _HWTSTAMP_FILTER_ALL_ or _HWTSTAMP_FILTER_NTP_ALL_. When
|
filter _HWTSTAMP_FILTER_ALL_, or _HWTSTAMP_FILTER_NTP_ALL_, is necessary for
|
||||||
*chronyd* is running, no other process (e.g. a PTP daemon) should be working
|
timestamping of received packets. Timestamping of packets received from bridged
|
||||||
with the NIC clock.
|
and bonded interfaces is supported on Linux 4.13 and newer. When *chronyd* is
|
||||||
|
running, no other process (e.g. a PTP daemon) should be working with the NIC
|
||||||
|
clock.
|
||||||
+
|
+
|
||||||
If the kernel supports software timestamping, it will be enabled for all
|
If the kernel supports software timestamping, it will be enabled for all
|
||||||
interfaces. With both hardware and software timestamping there are some
|
interfaces. The source of timestamps (i.e. hardware, kernel, or daemon) is
|
||||||
limitations on which timestamps can be actually used, e.g. transmit
|
indicated in the _measurements.log_ file if enabled by the <<log,*log
|
||||||
timestamping does not currently work with IPv6 packets using IP options and
|
measurements*>> directive, and the <<chronyc.adoc#ntpdata,*ntpdata*>> report in
|
||||||
hardware timestamping of packets received from bridges, bonds, and other
|
*chronyc*.
|
||||||
virtual interfaces, works only on Linux 4.13 and newer. The source of
|
|
||||||
timestamps (i.e. hardware, kernel, or daemon) is indicated in the
|
|
||||||
_measurements.log_ file if enabled by the <<log,*log measurements*>> directive,
|
|
||||||
and the <<chronyc.adoc#ntpdata,*ntpdata*>> report in *chronyc*.
|
|
||||||
+
|
+
|
||||||
If the specified interface is _*_, *chronyd* will try to enable HW timestamping
|
If the specified interface is _*_, *chronyd* will try to enable HW timestamping
|
||||||
on all available interfaces.
|
on all available interfaces.
|
||||||
@@ -1907,15 +1948,21 @@ is 0.
|
|||||||
Some hardware can precisely cross timestamp the NIC clock with the system
|
Some hardware can precisely cross timestamp the NIC clock with the system
|
||||||
clock. This option disables the use of the cross timestamping.
|
clock. This option disables the use of the cross timestamping.
|
||||||
*rxfilter* _filter_:::
|
*rxfilter* _filter_:::
|
||||||
This option selects the receive timestamping filter. Possible values are:
|
This option selects the receive timestamping filter. The _filter_ can be one of
|
||||||
_all_, _ntp_, and _none_. The default value is _ntp_, which enables
|
the following:
|
||||||
timestamping of NTP packets (_HWTSTAMP_FILTER_NTP_ALL_) if it is supported, or
|
_all_::::
|
||||||
timestamping of all packets (_HWTSTAMP_FILTER_ALL_). Setting *rxfilter* to
|
Enables timestamping of all received packets.
|
||||||
_all_ forces timestamping of all packets, which can be useful when the NIC
|
_ntp_::::
|
||||||
supports both filters and NTP packets are received from or on a non-standard
|
Enables timestamping of received NTP packets.
|
||||||
UDP port (e.g. specified by the *port* directive). Setting *rxfilter* to _none_
|
_none_::::
|
||||||
disables receive HW timestamping and allows transmit HW timestamping to be
|
Disables timestamping of received packets.
|
||||||
enabled when the NIC supports only PTP-specific receive filters.
|
:::
|
||||||
|
The most specific filter for timestamping NTP packets which is supported by the
|
||||||
|
NIC is selected by default. Some NICs can timestamp only PTP packets, which
|
||||||
|
limits the selection to the _none_ filter. Forcing timestamping of all packets
|
||||||
|
with the _all_ filter when the NIC supports both _all_ and _ntp_ filters can be
|
||||||
|
useful when packets are received from or on a non-standard UDP port (e.g.
|
||||||
|
specified by the *port* directive).
|
||||||
::
|
::
|
||||||
+
|
+
|
||||||
Examples of the directive are:
|
Examples of the directive are:
|
||||||
@@ -1960,12 +2007,18 @@ format of the file is shown below:
|
|||||||
+
|
+
|
||||||
Each line consists of an ID, name of an authentication hash function (optional),
|
Each line consists of an ID, name of an authentication hash function (optional),
|
||||||
and a password. The ID can be any unsigned integer in the range 1 through
|
and a password. The ID can be any unsigned integer in the range 1 through
|
||||||
2^32-1. The default hash function is *MD5*. Depending on how *chronyd*
|
2^32-1. The default hash function is *MD5*, which is always supported.
|
||||||
was compiled, other supported functions might be *SHA1*, *SHA256*, *SHA384*,
|
+
|
||||||
*SHA512*, *RMD128*, *RMD160*, *RMD256*, *RMD320*, *TIGER*, and *WHIRLPOOL*. The
|
If *chronyd* was built with enabled support for hashing using a crypto library
|
||||||
password can be specified as a string of characters not containing white space
|
(nettle, nss, or libtomcrypt), the following functions are available: *MD5*,
|
||||||
with an optional *ASCII:* prefix, or as a hexadecimal number with the *HEX:*
|
*SHA1*, *SHA256*, *SHA384*, *SHA512*. Depending on which library and version is
|
||||||
prefix. The maximum length of the line is 2047 characters.
|
*chronyd* using, some or all of the following functions may also be available:
|
||||||
|
*SHA3-224*, *SHA3-256*, *SHA3-384*, *SHA3-512*, *RMD128*, *RMD160*, *RMD256*,
|
||||||
|
*RMD320*, *TIGER*, *WHIRLPOOL*.
|
||||||
|
+
|
||||||
|
The password can be specified as a string of characters not containing white
|
||||||
|
space with an optional *ASCII:* prefix, or as a hexadecimal number with the
|
||||||
|
*HEX:* prefix. The maximum length of the line is 2047 characters.
|
||||||
+
|
+
|
||||||
The password is used with the hash function to generate and verify a message
|
The password is used with the hash function to generate and verify a message
|
||||||
authentication code (MAC) in NTP packets. It is recommended to use SHA1, or
|
authentication code (MAC) in NTP packets. It is recommended to use SHA1, or
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright (C) Richard P. Curnow 1997-2003
|
// Copyright (C) Richard P. Curnow 1997-2003
|
||||||
// Copyright (C) Stephen Wadeley 2016
|
// Copyright (C) Stephen Wadeley 2016
|
||||||
// Copyright (C) Miroslav Lichvar 2009-2016
|
// Copyright (C) Miroslav Lichvar 2009-2017
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or modify
|
// This program is free software; you can redistribute it and/or modify
|
||||||
// it under the terms of version 2 of the GNU General Public License as
|
// it under the terms of version 2 of the GNU General Public License as
|
||||||
@@ -216,7 +216,7 @@ An absolute bound on the computer's clock accuracy (assuming the stratum-1
|
|||||||
computer is correct) is given by:
|
computer is correct) is given by:
|
||||||
+
|
+
|
||||||
----
|
----
|
||||||
clock_error <= root_dispersion + (0.5 * |root_delay|)
|
clock_error <= |system_time_offset| + root_dispersion + (0.5 * root_delay)
|
||||||
----
|
----
|
||||||
*Update interval*:::
|
*Update interval*:::
|
||||||
This is the interval between the last two clock updates.
|
This is the interval between the last two clock updates.
|
||||||
@@ -1128,6 +1128,10 @@ running.
|
|||||||
The *rekey* command causes *chronyd* to re-read the key file specified in the
|
The *rekey* command causes *chronyd* to re-read the key file specified in the
|
||||||
configuration file by the <<chrony.conf.adoc#keyfile,*keyfile*>> directive.
|
configuration file by the <<chrony.conf.adoc#keyfile,*keyfile*>> directive.
|
||||||
|
|
||||||
|
[[rekey]]*shutdown*::
|
||||||
|
The *shutdown* command causes *chronyd* to exit. This is equivalent to sending
|
||||||
|
the process the SIGTERM signal.
|
||||||
|
|
||||||
=== Client commands
|
=== Client commands
|
||||||
|
|
||||||
[[dns]]*dns* _option_::
|
[[dns]]*dns* _option_::
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// This file is part of chrony
|
// This file is part of chrony
|
||||||
//
|
//
|
||||||
// Copyright (C) Richard P. Curnow 1997-2003
|
// Copyright (C) Richard P. Curnow 1997-2003
|
||||||
// Copyright (C) Miroslav Lichvar 2009-2016
|
// Copyright (C) Miroslav Lichvar 2009-2017
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or modify
|
// This program is free software; you can redistribute it and/or modify
|
||||||
// it under the terms of version 2 of the GNU General Public License as
|
// it under the terms of version 2 of the GNU General Public License as
|
||||||
@@ -135,7 +135,7 @@ range of privileged system calls on behalf of the parent.
|
|||||||
*-F* _level_::
|
*-F* _level_::
|
||||||
This option configures a system call filter when *chronyd* is compiled with
|
This option configures a system call filter when *chronyd* is compiled with
|
||||||
support for the Linux secure computing (seccomp) facility. In level 1 the
|
support for the Linux secure computing (seccomp) facility. In level 1 the
|
||||||
process is killed when a forbidden system call is made, in level -1 the SYSSIG
|
process is killed when a forbidden system call is made, in level -1 the SIGSYS
|
||||||
signal is thrown instead and in level 0 the filter is disabled (default 0).
|
signal is thrown instead and in level 0 the filter is disabled (default 0).
|
||||||
+
|
+
|
||||||
It's recommended to enable the filter only when it's known to work on the
|
It's recommended to enable the filter only when it's known to work on the
|
||||||
@@ -157,11 +157,13 @@ This option will lock *chronyd* into RAM so that it will never be paged out.
|
|||||||
This mode is only supported on Linux.
|
This mode is only supported on Linux.
|
||||||
|
|
||||||
*-x*::
|
*-x*::
|
||||||
This option disables the control of the system clock. *chronyd* will not make
|
This option disables the control of the system clock. *chronyd* will not try to
|
||||||
any adjustments of the clock, but it will still track its offset and frequency
|
make any adjustments of the clock. It will assume the clock is free running and
|
||||||
relative to the estimated true time, and be able to operate as an NTP server.
|
still track its offset and frequency relative to the estimated true time. This
|
||||||
This allows *chronyd* to run without the capability to adjust or set the system
|
option allows *chronyd* to run without the capability to adjust or set the
|
||||||
clock (e.g. in some containers).
|
system clock (e.g. in some containers) in order to operate as an NTP server. It
|
||||||
|
is not recommended to run *chronyd* (with or without *-x*) when another process
|
||||||
|
is controlling the system clock.
|
||||||
|
|
||||||
*-v*::
|
*-v*::
|
||||||
With this option *chronyd* will print version number to the terminal and exit.
|
With this option *chronyd* will print version number to the terminal and exit.
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ directive can be used for names that resolve to multiple addresses. For good
|
|||||||
reliability the client should have at least three servers. The `iburst` option
|
reliability the client should have at least three servers. The `iburst` option
|
||||||
speeds up the initial synchronisation.
|
speeds up the initial synchronisation.
|
||||||
|
|
||||||
To stabilize the initial synchronisation on the next start, the estimated drift
|
To stabilise the initial synchronisation on the next start, the estimated drift
|
||||||
of the system clock is saved to a file specified by the `driftfile` directive.
|
of the system clock is saved to a file specified by the `driftfile` directive.
|
||||||
|
|
||||||
If the system clock can be far from the true time after boot for any reason,
|
If the system clock can be far from the true time after boot for any reason,
|
||||||
@@ -59,7 +59,7 @@ slewing, which would take a very long time. The `makestep` directive does
|
|||||||
that.
|
that.
|
||||||
|
|
||||||
In order to keep the real-time clock (RTC) close to the true time, so the
|
In order to keep the real-time clock (RTC) close to the true time, so the
|
||||||
system time is reasonably close to the true time when it's initialized on the
|
system time is reasonably close to the true time when it's initialised on the
|
||||||
next boot from the RTC, the `rtcsync` directive enables a mode in which the
|
next boot from the RTC, the `rtcsync` directive enables a mode in which the
|
||||||
system time is periodically copied to the RTC. It is supported on Linux and
|
system time is periodically copied to the RTC. It is supported on Linux and
|
||||||
macOS.
|
macOS.
|
||||||
@@ -347,14 +347,14 @@ Only by the source code. See _cmdmon.c_ (`chronyd` side) and _client.c_
|
|||||||
=== What is the real-time clock (RTC)?
|
=== What is the real-time clock (RTC)?
|
||||||
|
|
||||||
This is the clock which keeps the time even when your computer is turned off.
|
This is the clock which keeps the time even when your computer is turned off.
|
||||||
It is used to initialize the system clock on boot. It normally doesn't drift
|
It is used to initialise the system clock on boot. It normally doesn't drift
|
||||||
more than few seconds per day.
|
more than few seconds per day.
|
||||||
|
|
||||||
There are two approaches how `chronyd` can work with it. One is to use the
|
There are two approaches how `chronyd` can work with it. One is to use the
|
||||||
`rtcsync` directive, which tells `chronyd` to enable a kernel mode which sets
|
`rtcsync` directive, which tells `chronyd` to enable a kernel mode which sets
|
||||||
the RTC from the system clock every 11 minutes. `chronyd` itself won't touch
|
the RTC from the system clock every 11 minutes. `chronyd` itself won't touch
|
||||||
the RTC. If the computer is not turned off for a long time, the RTC should
|
the RTC. If the computer is not turned off for a long time, the RTC should
|
||||||
still be close to the true time when the system clock will be initialized from
|
still be close to the true time when the system clock will be initialised from
|
||||||
it on the next boot.
|
it on the next boot.
|
||||||
|
|
||||||
The other option is to use the `rtcfile` directive, which tells `chronyd` to
|
The other option is to use the `rtcfile` directive, which tells `chronyd` to
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ rtcsync
|
|||||||
# Specify file containing keys for NTP authentication.
|
# Specify file containing keys for NTP authentication.
|
||||||
#keyfile /etc/chrony.keys
|
#keyfile /etc/chrony.keys
|
||||||
|
|
||||||
|
# Get TAI-UTC offset and leap seconds from the system tz database.
|
||||||
|
#leapsectz right/UTC
|
||||||
|
|
||||||
# Specify directory for log files.
|
# Specify directory for log files.
|
||||||
logdir /var/log/chrony
|
logdir /var/log/chrony
|
||||||
|
|
||||||
|
|||||||
@@ -97,6 +97,12 @@ driftfile /var/lib/chrony/drift
|
|||||||
|
|
||||||
! pidfile /var/run/chronyd.pid
|
! pidfile /var/run/chronyd.pid
|
||||||
|
|
||||||
|
# If the system timezone database is kept up to date and includes the
|
||||||
|
# right/UTC timezone, chronyd can use it to determine the current
|
||||||
|
# TAI-UTC offset and when will the next leap second occur.
|
||||||
|
|
||||||
|
! leapsectz right/UTC
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
### INITIAL CLOCK CORRECTION
|
### INITIAL CLOCK CORRECTION
|
||||||
# This option is useful to quickly correct the clock on start if it's
|
# This option is useful to quickly correct the clock on start if it's
|
||||||
|
|||||||
@@ -1,17 +1,37 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# This is a NetworkManager dispatcher script for chronyd to set its NTP sources
|
# This is a NetworkManager dispatcher script for chronyd to set its NTP sources
|
||||||
# online/offline when a default route is configured/removed on the system.
|
# online or offline when a network interface is configured or removed
|
||||||
|
|
||||||
export LC_ALL=C
|
export LC_ALL=C
|
||||||
|
|
||||||
if [ "$2" = "up" ]; then
|
[ "$2" != "up" ] && [ "$2" != "down" ] && exit 0
|
||||||
/sbin/ip route list dev "$1" | grep -q '^default' &&
|
|
||||||
/usr/bin/chronyc online > /dev/null 2>&1
|
# Check if there is a default route
|
||||||
|
|
||||||
|
if /sbin/ip route list 2> /dev/null | grep -q '^default'; then
|
||||||
|
chronyc online > /dev/null 2>&1
|
||||||
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$2" = "down" ]; then
|
sources=$(chronyc -c -n sources 2> /dev/null)
|
||||||
/sbin/ip route list | grep -q '^default' ||
|
|
||||||
/usr/bin/chronyc offline > /dev/null 2>&1
|
[ $? -ne 0 ] && exit 0
|
||||||
fi
|
|
||||||
|
# Check each configured source if it has a route
|
||||||
|
|
||||||
|
echo "$sources" | while IFS=, read mode state address rest; do
|
||||||
|
[ "$mode" != '^' ] && [ "$mode" != '=' ] && continue
|
||||||
|
|
||||||
|
/sbin/ip route get "$address" > /dev/null 2>&1 && command="online" || command="offline"
|
||||||
|
|
||||||
|
# Set priority of sources so that the selected source is set as
|
||||||
|
# last if offline to avoid unnecessary reselection
|
||||||
|
[ "$state" != '*' ] && priority=1 || priority=2
|
||||||
|
|
||||||
|
echo "$priority $command $address"
|
||||||
|
|
||||||
|
done | sort | while read priority command address; do
|
||||||
|
echo "$command $address"
|
||||||
|
done | chronyc > /dev/null 2>&1
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
120
hash_nettle.c
Normal file
120
hash_nettle.c
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||||
|
|
||||||
|
**********************************************************************
|
||||||
|
* Copyright (C) Miroslav Lichvar 2018
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
|
||||||
|
Routines implementing crypto hashing using the nettle library.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "sysincl.h"
|
||||||
|
|
||||||
|
#include <nettle/nettle-meta.h>
|
||||||
|
|
||||||
|
#include "hash.h"
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
struct hash {
|
||||||
|
const char *name;
|
||||||
|
const char *int_name;
|
||||||
|
const struct nettle_hash *nettle_hash;
|
||||||
|
void *context;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct hash hashes[] = {
|
||||||
|
{ "MD5", "md5", NULL, NULL },
|
||||||
|
{ "RMD160", "ripemd160", NULL, NULL },
|
||||||
|
{ "SHA1", "sha1", NULL, NULL },
|
||||||
|
{ "SHA256", "sha256", NULL, NULL },
|
||||||
|
{ "SHA384", "sha384", NULL, NULL },
|
||||||
|
{ "SHA512", "sha512", NULL, NULL },
|
||||||
|
{ "SHA3-224", "sha3_224", NULL, NULL },
|
||||||
|
{ "SHA3-256", "sha3_256", NULL, NULL },
|
||||||
|
{ "SHA3-384", "sha3_384", NULL, NULL },
|
||||||
|
{ "SHA3-512", "sha3_512", NULL, NULL },
|
||||||
|
{ NULL, NULL, NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
HSH_GetHashId(const char *name)
|
||||||
|
{
|
||||||
|
int id, nid;
|
||||||
|
|
||||||
|
for (id = 0; hashes[id].name; id++) {
|
||||||
|
if (!strcmp(name, hashes[id].name))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hashes[id].name)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (hashes[id].context)
|
||||||
|
return id;
|
||||||
|
|
||||||
|
for (nid = 0; nettle_hashes[nid]; nid++) {
|
||||||
|
if (!strcmp(hashes[id].int_name, nettle_hashes[nid]->name))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nettle_hashes[nid] || !nettle_hashes[nid]->context_size || !nettle_hashes[nid]->init)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
hashes[id].nettle_hash = nettle_hashes[nid];
|
||||||
|
hashes[id].context = Malloc(hashes[id].nettle_hash->context_size);
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
|
||||||
|
const unsigned char *in2, unsigned int in2_len,
|
||||||
|
unsigned char *out, unsigned int out_len)
|
||||||
|
{
|
||||||
|
const struct nettle_hash *hash;
|
||||||
|
void *context;
|
||||||
|
|
||||||
|
hash = hashes[id].nettle_hash;
|
||||||
|
context = hashes[id].context;
|
||||||
|
|
||||||
|
if (out_len > hash->digest_size)
|
||||||
|
out_len = hash->digest_size;
|
||||||
|
|
||||||
|
hash->init(context);
|
||||||
|
hash->update(context, in1_len, in1);
|
||||||
|
if (in2)
|
||||||
|
hash->update(context, in2_len, in2);
|
||||||
|
hash->digest(context, out_len, out);
|
||||||
|
|
||||||
|
return out_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
HSH_Finalise(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; hashes[i].name; i++) {
|
||||||
|
if (hashes[i].context)
|
||||||
|
Free(hashes[i].context);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -62,6 +62,12 @@ static const struct hash hashes[] = {
|
|||||||
#ifdef LTC_SHA512
|
#ifdef LTC_SHA512
|
||||||
{ "SHA512", "sha512", &sha512_desc },
|
{ "SHA512", "sha512", &sha512_desc },
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef LTC_SHA3
|
||||||
|
{ "SHA3-224", "sha3-224", &sha3_224_desc },
|
||||||
|
{ "SHA3-256", "sha3-256", &sha3_256_desc },
|
||||||
|
{ "SHA3-384", "sha3-384", &sha3_384_desc },
|
||||||
|
{ "SHA3-512", "sha3-512", &sha3_512_desc },
|
||||||
|
#endif
|
||||||
#ifdef LTC_TIGER
|
#ifdef LTC_TIGER
|
||||||
{ "TIGER", "tiger", &tiger_desc },
|
{ "TIGER", "tiger", &tiger_desc },
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
24
hwclock.c
24
hwclock.c
@@ -2,7 +2,7 @@
|
|||||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||||
|
|
||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) Miroslav Lichvar 2016
|
* Copyright (C) Miroslav Lichvar 2016-2017
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of version 2 of the GNU General Public License as
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
@@ -39,6 +39,9 @@
|
|||||||
/* Maximum number of samples per clock */
|
/* Maximum number of samples per clock */
|
||||||
#define MAX_SAMPLES 16
|
#define MAX_SAMPLES 16
|
||||||
|
|
||||||
|
/* Maximum acceptable frequency offset of the clock */
|
||||||
|
#define MAX_FREQ_OFFSET (2.0 / 3.0)
|
||||||
|
|
||||||
struct HCL_Instance_Record {
|
struct HCL_Instance_Record {
|
||||||
/* HW and local reference timestamp */
|
/* HW and local reference timestamp */
|
||||||
struct timespec hw_ref;
|
struct timespec hw_ref;
|
||||||
@@ -174,16 +177,17 @@ HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
|
|||||||
/* Drop unneeded samples */
|
/* Drop unneeded samples */
|
||||||
clock->n_samples -= best_start;
|
clock->n_samples -= best_start;
|
||||||
|
|
||||||
/* If the fit doesn't cross the error interval of the last sample, throw away
|
/* If the fit doesn't cross the error interval of the last sample,
|
||||||
all previous samples and keep only the frequency estimate */
|
or the frequency is not sane, drop all samples and start again */
|
||||||
if (fabs(clock->offset) > err) {
|
if (fabs(clock->offset) > err ||
|
||||||
DEBUG_LOG("HW clock reset offset=%e", clock->offset);
|
fabs(clock->frequency - 1.0) > MAX_FREQ_OFFSET) {
|
||||||
clock->offset = 0.0;
|
DEBUG_LOG("HW clock reset");
|
||||||
clock->n_samples = 1;
|
clock->n_samples = 0;
|
||||||
|
clock->valid_coefs = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_LOG("HW clock samples=%d offset=%e freq=%.9e raw_freq=%.9e err=%e ref_diff=%e",
|
DEBUG_LOG("HW clock samples=%d offset=%e freq=%e raw_freq=%e err=%e ref_diff=%e",
|
||||||
clock->n_samples, clock->offset, clock->frequency, raw_freq, err,
|
clock->n_samples, clock->offset, clock->frequency - 1.0, raw_freq - 1.0, err,
|
||||||
UTI_DiffTimespecsToDouble(&clock->hw_ref, &clock->local_ref));
|
UTI_DiffTimespecsToDouble(&clock->hw_ref, &clock->local_ref));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,7 +202,7 @@ HCL_CookTime(HCL_Instance clock, struct timespec *raw, struct timespec *cooked,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
elapsed = UTI_DiffTimespecsToDouble(raw, &clock->hw_ref);
|
elapsed = UTI_DiffTimespecsToDouble(raw, &clock->hw_ref);
|
||||||
offset = clock->offset + elapsed / clock->frequency;
|
offset = elapsed / clock->frequency - clock->offset;
|
||||||
UTI_AddDoubleToTimespec(&clock->local_ref, offset, cooked);
|
UTI_AddDoubleToTimespec(&clock->local_ref, offset, cooked);
|
||||||
|
|
||||||
/* Fow now, just return the error of the last sample */
|
/* Fow now, just return the error of the last sample */
|
||||||
|
|||||||
33
logging.c
33
logging.c
@@ -79,11 +79,11 @@ LOG_Initialise(void)
|
|||||||
void
|
void
|
||||||
LOG_Finalise(void)
|
LOG_Finalise(void)
|
||||||
{
|
{
|
||||||
if (system_log) {
|
if (system_log)
|
||||||
closelog();
|
closelog();
|
||||||
} else {
|
|
||||||
|
if (file_log)
|
||||||
fclose(file_log);
|
fclose(file_log);
|
||||||
}
|
|
||||||
|
|
||||||
LOG_CycleLogFiles();
|
LOG_CycleLogFiles();
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ static void log_message(int fatal, LOG_Severity severity, const char *message)
|
|||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
syslog(priority, fatal ? "Fatal error : %s" : "%s", message);
|
syslog(priority, fatal ? "Fatal error : %s" : "%s", message);
|
||||||
} else {
|
} else if (file_log) {
|
||||||
fprintf(file_log, fatal ? "Fatal error : %s\n" : "%s\n", message);
|
fprintf(file_log, fatal ? "Fatal error : %s\n" : "%s\n", message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,7 +134,7 @@ void LOG_Message(LOG_Severity severity,
|
|||||||
time_t t;
|
time_t t;
|
||||||
struct tm stm;
|
struct tm stm;
|
||||||
|
|
||||||
if (!system_log) {
|
if (!system_log && file_log) {
|
||||||
/* Don't clutter up syslog with timestamps and internal debugging info */
|
/* Don't clutter up syslog with timestamps and internal debugging info */
|
||||||
time(&t);
|
time(&t);
|
||||||
stm = *gmtime(&t);
|
stm = *gmtime(&t);
|
||||||
@@ -160,16 +160,14 @@ void LOG_Message(LOG_Severity severity,
|
|||||||
case LOGS_FATAL:
|
case LOGS_FATAL:
|
||||||
log_message(1, severity, buf);
|
log_message(1, severity, buf);
|
||||||
|
|
||||||
/* With syslog, send the message also to the grandparent
|
/* Send the message also to the foreground process if it is
|
||||||
process or write it to stderr if not detached */
|
still running, or stderr if it is still open */
|
||||||
if (system_log) {
|
if (parent_fd > 0) {
|
||||||
if (parent_fd > 0) {
|
if (write(parent_fd, buf, strlen(buf) + 1) < 0)
|
||||||
if (write(parent_fd, buf, strlen(buf) + 1) < 0)
|
; /* Not much we can do here */
|
||||||
; /* Not much we can do here */
|
} else if (system_log && parent_fd == 0) {
|
||||||
} else if (parent_fd == 0) {
|
system_log = 0;
|
||||||
system_log = 0;
|
log_message(1, severity, buf);
|
||||||
log_message(1, severity, buf);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -188,6 +186,9 @@ LOG_OpenFileLog(const char *log_file)
|
|||||||
if (!f)
|
if (!f)
|
||||||
LOG_FATAL("Could not open log file %s", log_file);
|
LOG_FATAL("Could not open log file %s", log_file);
|
||||||
|
|
||||||
|
/* Enable line buffering */
|
||||||
|
setvbuf(f, NULL, _IOLBF, BUFSIZ);
|
||||||
|
|
||||||
file_log = f;
|
file_log = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,6 +218,8 @@ void
|
|||||||
LOG_SetParentFd(int fd)
|
LOG_SetParentFd(int fd)
|
||||||
{
|
{
|
||||||
parent_fd = fd;
|
parent_fd = fd;
|
||||||
|
if (file_log == stderr)
|
||||||
|
file_log = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ extern void LOG_OpenFileLog(const char *log_file);
|
|||||||
/* Log messages to syslog instead of stderr */
|
/* Log messages to syslog instead of stderr */
|
||||||
extern void LOG_OpenSystemLog(void);
|
extern void LOG_OpenSystemLog(void);
|
||||||
|
|
||||||
/* Send fatal message also to the foreground process */
|
/* Stop using stderr and send fatal message to the foreground process */
|
||||||
extern void LOG_SetParentFd(int fd);
|
extern void LOG_SetParentFd(int fd);
|
||||||
|
|
||||||
/* Close the pipe to the foreground process so it can exit */
|
/* Close the pipe to the foreground process so it can exit */
|
||||||
|
|||||||
38
main.c
38
main.c
@@ -4,7 +4,7 @@
|
|||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) Richard P. Curnow 1997-2003
|
* Copyright (C) Richard P. Curnow 1997-2003
|
||||||
* Copyright (C) John G. Hasler 2009
|
* Copyright (C) John G. Hasler 2009
|
||||||
* Copyright (C) Miroslav Lichvar 2012-2016
|
* Copyright (C) Miroslav Lichvar 2012-2017
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of version 2 of the GNU General Public License as
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
@@ -292,6 +292,8 @@ write_pidfile(void)
|
|||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
|
#define DEV_NULL "/dev/null"
|
||||||
|
|
||||||
static void
|
static void
|
||||||
go_daemon(void)
|
go_daemon(void)
|
||||||
{
|
{
|
||||||
@@ -352,6 +354,13 @@ go_daemon(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
LOG_SetParentFd(pipefd[1]);
|
LOG_SetParentFd(pipefd[1]);
|
||||||
|
|
||||||
|
/* Open /dev/null as new stdin/out/err */
|
||||||
|
errno = 0;
|
||||||
|
if (open(DEV_NULL, O_RDONLY) != STDIN_FILENO ||
|
||||||
|
open(DEV_NULL, O_WRONLY) != STDOUT_FILENO ||
|
||||||
|
open(DEV_NULL, O_RDWR) != STDERR_FILENO)
|
||||||
|
LOG_FATAL("Could not open %s : %s", DEV_NULL, strerror(errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -448,8 +457,13 @@ int main
|
|||||||
sched_priority = parse_int_arg(optarg);
|
sched_priority = parse_int_arg(optarg);
|
||||||
break;
|
break;
|
||||||
case 'q':
|
case 'q':
|
||||||
|
ref_mode = REF_ModeUpdateOnce;
|
||||||
|
nofork = 1;
|
||||||
|
client_only = 0;
|
||||||
|
system_log = 0;
|
||||||
|
break;
|
||||||
case 'Q':
|
case 'Q':
|
||||||
ref_mode = opt == 'q' ? REF_ModeUpdateOnce : REF_ModePrintOnce;
|
ref_mode = REF_ModePrintOnce;
|
||||||
nofork = 1;
|
nofork = 1;
|
||||||
client_only = 1;
|
client_only = 1;
|
||||||
clock_control = 0;
|
clock_control = 0;
|
||||||
@@ -519,6 +533,16 @@ int main
|
|||||||
/* Write our pidfile to prevent other chronyds running */
|
/* Write our pidfile to prevent other chronyds running */
|
||||||
write_pidfile();
|
write_pidfile();
|
||||||
|
|
||||||
|
if (!user)
|
||||||
|
user = CNF_GetUser();
|
||||||
|
|
||||||
|
pw = getpwnam(user);
|
||||||
|
if (!pw)
|
||||||
|
LOG_FATAL("Could not get user/group ID of %s", user);
|
||||||
|
|
||||||
|
/* Create directories for sockets, log files, and dump files */
|
||||||
|
CNF_CreateDirs(pw->pw_uid, pw->pw_gid);
|
||||||
|
|
||||||
PRV_Initialise();
|
PRV_Initialise();
|
||||||
LCL_Initialise();
|
LCL_Initialise();
|
||||||
SCH_Initialise();
|
SCH_Initialise();
|
||||||
@@ -546,16 +570,6 @@ int main
|
|||||||
SYS_LockMemory();
|
SYS_LockMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
user = CNF_GetUser();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((pw = getpwnam(user)) == NULL)
|
|
||||||
LOG_FATAL("Could not get %s uid/gid", user);
|
|
||||||
|
|
||||||
/* Create all directories before dropping root */
|
|
||||||
CNF_CreateDirs(pw->pw_uid, pw->pw_gid);
|
|
||||||
|
|
||||||
/* Drop root privileges if the specified user has a non-zero UID */
|
/* Drop root privileges if the specified user has a non-zero UID */
|
||||||
if (!geteuid() && (pw->pw_uid || pw->pw_gid))
|
if (!geteuid() && (pw->pw_uid || pw->pw_gid))
|
||||||
SYS_DropRoot(pw->pw_uid, pw->pw_gid);
|
SYS_DropRoot(pw->pw_uid, pw->pw_gid);
|
||||||
|
|||||||
28
memory.c
28
memory.c
@@ -2,7 +2,7 @@
|
|||||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||||
|
|
||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) Miroslav Lichvar 2014
|
* Copyright (C) Miroslav Lichvar 2014, 2017
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of version 2 of the GNU General Public License as
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
@@ -54,6 +54,32 @@ Realloc(void *ptr, size_t size)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
get_array_size(size_t nmemb, size_t size)
|
||||||
|
{
|
||||||
|
size_t array_size;
|
||||||
|
|
||||||
|
array_size = nmemb * size;
|
||||||
|
|
||||||
|
/* Check for overflow */
|
||||||
|
if (nmemb > 0 && array_size / nmemb != size)
|
||||||
|
LOG_FATAL("Could not allocate memory");
|
||||||
|
|
||||||
|
return array_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
Malloc2(size_t nmemb, size_t size)
|
||||||
|
{
|
||||||
|
return Malloc(get_array_size(nmemb, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
Realloc2(void *ptr, size_t nmemb, size_t size)
|
||||||
|
{
|
||||||
|
return Realloc(ptr, get_array_size(nmemb, size));
|
||||||
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
Strdup(const char *s)
|
Strdup(const char *s)
|
||||||
{
|
{
|
||||||
|
|||||||
6
memory.h
6
memory.h
@@ -30,12 +30,14 @@
|
|||||||
/* Wrappers checking for errors */
|
/* Wrappers checking for errors */
|
||||||
extern void *Malloc(size_t size);
|
extern void *Malloc(size_t size);
|
||||||
extern void *Realloc(void *ptr, size_t size);
|
extern void *Realloc(void *ptr, size_t size);
|
||||||
|
extern void *Malloc2(size_t nmemb, size_t size);
|
||||||
|
extern void *Realloc2(void *ptr, size_t nmemb, size_t size);
|
||||||
extern char *Strdup(const char *s);
|
extern char *Strdup(const char *s);
|
||||||
|
|
||||||
/* Convenient macros */
|
/* Convenient macros */
|
||||||
#define MallocNew(T) ((T *) Malloc(sizeof(T)))
|
#define MallocNew(T) ((T *) Malloc(sizeof(T)))
|
||||||
#define MallocArray(T, n) ((T *) Malloc((n) * sizeof(T)))
|
#define MallocArray(T, n) ((T *) Malloc2(n, sizeof(T)))
|
||||||
#define ReallocArray(T,n,x) ((T *) Realloc((void *)(x), (n)*sizeof(T)))
|
#define ReallocArray(T, n, x) ((T *) Realloc2((void *)(x), n, sizeof(T)))
|
||||||
#define Free(x) free(x)
|
#define Free(x) free(x)
|
||||||
|
|
||||||
#endif /* GOT_MEMORY_H */
|
#endif /* GOT_MEMORY_H */
|
||||||
|
|||||||
14
nameserv.c
14
nameserv.c
@@ -53,7 +53,19 @@ DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
|
|||||||
max_addrs = MIN(max_addrs, DNS_MAX_ADDRESSES);
|
max_addrs = MIN(max_addrs, DNS_MAX_ADDRESSES);
|
||||||
|
|
||||||
memset(&hints, 0, sizeof (hints));
|
memset(&hints, 0, sizeof (hints));
|
||||||
hints.ai_family = AF_UNSPEC;
|
|
||||||
|
switch (address_family) {
|
||||||
|
case IPADDR_INET4:
|
||||||
|
hints.ai_family = AF_INET;
|
||||||
|
break;
|
||||||
|
#ifdef FEAT_IPV6
|
||||||
|
case IPADDR_INET6:
|
||||||
|
hints.ai_family = AF_INET6;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
}
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
|
||||||
result = getaddrinfo(name, NULL, &hints, &res);
|
result = getaddrinfo(name, NULL, &hints, &res);
|
||||||
|
|||||||
308
ntp_core.c
308
ntp_core.c
@@ -88,6 +88,7 @@ struct NCR_Instance_Record {
|
|||||||
SCH_TimeoutID tx_timeout_id; /* Timeout ID for next transmission */
|
SCH_TimeoutID tx_timeout_id; /* Timeout ID for next transmission */
|
||||||
int tx_suspended; /* Boolean indicating we can't transmit yet */
|
int tx_suspended; /* Boolean indicating we can't transmit yet */
|
||||||
|
|
||||||
|
int auto_burst; /* If 1, initiate a burst on each poll */
|
||||||
int auto_offline; /* If 1, automatically go offline if server/peer
|
int auto_offline; /* If 1, automatically go offline if server/peer
|
||||||
isn't responding */
|
isn't responding */
|
||||||
|
|
||||||
@@ -149,14 +150,11 @@ struct NCR_Instance_Record {
|
|||||||
be used for synchronisation */
|
be used for synchronisation */
|
||||||
int valid_timestamps;
|
int valid_timestamps;
|
||||||
|
|
||||||
/* Flag indicating the timestamps below were updated since last request */
|
/* Receive and transmit timestamps from the last valid response */
|
||||||
int updated_timestamps;
|
|
||||||
|
|
||||||
/* Receive and transmit timestamps from the last received packet */
|
|
||||||
NTP_int64 remote_ntp_rx;
|
NTP_int64 remote_ntp_rx;
|
||||||
NTP_int64 remote_ntp_tx;
|
NTP_int64 remote_ntp_tx;
|
||||||
|
|
||||||
/* Local timestamp when the last packet was received from the
|
/* Local timestamp when the last valid response was received from the
|
||||||
source. We have to be prepared to tinker with this if the local
|
source. We have to be prepared to tinker with this if the local
|
||||||
clock has its frequency adjusted before we repond. The value we
|
clock has its frequency adjusted before we repond. The value we
|
||||||
store here is what our own local time was when the same arrived.
|
store here is what our own local time was when the same arrived.
|
||||||
@@ -178,8 +176,19 @@ struct NCR_Instance_Record {
|
|||||||
NTP_int64 local_ntp_tx;
|
NTP_int64 local_ntp_tx;
|
||||||
NTP_Local_Timestamp local_tx;
|
NTP_Local_Timestamp local_tx;
|
||||||
|
|
||||||
/* Previous local transmit timestamp for the interleaved mode */
|
/* Previous values of some variables needed in interleaved mode */
|
||||||
NTP_Local_Timestamp prev_local_tx;
|
NTP_Local_Timestamp prev_local_tx;
|
||||||
|
int prev_local_poll;
|
||||||
|
unsigned int prev_tx_count;
|
||||||
|
|
||||||
|
/* Flag indicating the two timestamps below were updated since the
|
||||||
|
last transmission */
|
||||||
|
int updated_init_timestamps;
|
||||||
|
|
||||||
|
/* Timestamps used for (re)starting the symmetric protocol, when we
|
||||||
|
need to respond to a packet which is not a valid response */
|
||||||
|
NTP_int64 init_remote_ntp_tx;
|
||||||
|
NTP_Local_Timestamp init_local_rx;
|
||||||
|
|
||||||
/* The instance record in the main source management module. This
|
/* The instance record in the main source management module. This
|
||||||
performs the statistical analysis on the samples we generate */
|
performs the statistical analysis on the samples we generate */
|
||||||
@@ -228,6 +237,10 @@ static ARR_Instance broadcasts;
|
|||||||
#define IBURST_GOOD_SAMPLES 4
|
#define IBURST_GOOD_SAMPLES 4
|
||||||
#define IBURST_TOTAL_SAMPLES SOURCE_REACH_BITS
|
#define IBURST_TOTAL_SAMPLES SOURCE_REACH_BITS
|
||||||
|
|
||||||
|
/* Number of samples in automatic burst */
|
||||||
|
#define BURST_GOOD_SAMPLES 1
|
||||||
|
#define MAX_BURST_TOTAL_SAMPLES 4
|
||||||
|
|
||||||
/* Time to wait after sending packet to 'warm up' link */
|
/* Time to wait after sending packet to 'warm up' link */
|
||||||
#define WARM_UP_DELAY 2.0
|
#define WARM_UP_DELAY 2.0
|
||||||
|
|
||||||
@@ -425,7 +438,8 @@ restart_timeout(NCR_Instance inst, double delay)
|
|||||||
/* Start new timer for transmission */
|
/* Start new timer for transmission */
|
||||||
inst->tx_timeout_id = SCH_AddTimeoutInClass(delay, get_separation(inst->local_poll),
|
inst->tx_timeout_id = SCH_AddTimeoutInClass(delay, get_separation(inst->local_poll),
|
||||||
SAMPLING_RANDOMNESS,
|
SAMPLING_RANDOMNESS,
|
||||||
SCH_NtpSamplingClass,
|
inst->mode == MODE_CLIENT ?
|
||||||
|
SCH_NtpClientClass : SCH_NtpPeerClass,
|
||||||
transmit_timeout, (void *)inst);
|
transmit_timeout, (void *)inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,6 +562,7 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
|
|||||||
result->max_delay_ratio = CLAMP(0.0, params->max_delay_ratio, MAX_MAXDELAYRATIO);
|
result->max_delay_ratio = CLAMP(0.0, params->max_delay_ratio, MAX_MAXDELAYRATIO);
|
||||||
result->max_delay_dev_ratio = CLAMP(0.0, params->max_delay_dev_ratio, MAX_MAXDELAYDEVRATIO);
|
result->max_delay_dev_ratio = CLAMP(0.0, params->max_delay_dev_ratio, MAX_MAXDELAYDEVRATIO);
|
||||||
result->offset_correction = params->offset;
|
result->offset_correction = params->offset;
|
||||||
|
result->auto_burst = params->burst;
|
||||||
result->auto_offline = params->auto_offline;
|
result->auto_offline = params->auto_offline;
|
||||||
result->poll_target = params->poll_target;
|
result->poll_target = params->poll_target;
|
||||||
|
|
||||||
@@ -582,7 +597,8 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
|
|||||||
result->source = SRC_CreateNewInstance(UTI_IPToRefid(&remote_addr->ip_addr),
|
result->source = SRC_CreateNewInstance(UTI_IPToRefid(&remote_addr->ip_addr),
|
||||||
SRC_NTP, params->sel_options,
|
SRC_NTP, params->sel_options,
|
||||||
&result->remote_addr.ip_addr,
|
&result->remote_addr.ip_addr,
|
||||||
params->min_samples, params->max_samples);
|
params->min_samples, params->max_samples,
|
||||||
|
params->min_delay, params->asymmetry);
|
||||||
|
|
||||||
result->rx_timeout_id = 0;
|
result->rx_timeout_id = 0;
|
||||||
result->tx_timeout_id = 0;
|
result->tx_timeout_id = 0;
|
||||||
@@ -648,13 +664,19 @@ NCR_ResetInstance(NCR_Instance instance)
|
|||||||
|
|
||||||
instance->valid_rx = 0;
|
instance->valid_rx = 0;
|
||||||
instance->valid_timestamps = 0;
|
instance->valid_timestamps = 0;
|
||||||
instance->updated_timestamps = 0;
|
|
||||||
UTI_ZeroNtp64(&instance->remote_ntp_rx);
|
UTI_ZeroNtp64(&instance->remote_ntp_rx);
|
||||||
UTI_ZeroNtp64(&instance->remote_ntp_tx);
|
UTI_ZeroNtp64(&instance->remote_ntp_tx);
|
||||||
UTI_ZeroNtp64(&instance->local_ntp_rx);
|
UTI_ZeroNtp64(&instance->local_ntp_rx);
|
||||||
UTI_ZeroNtp64(&instance->local_ntp_tx);
|
UTI_ZeroNtp64(&instance->local_ntp_tx);
|
||||||
zero_local_timestamp(&instance->local_rx);
|
zero_local_timestamp(&instance->local_rx);
|
||||||
|
|
||||||
zero_local_timestamp(&instance->prev_local_tx);
|
zero_local_timestamp(&instance->prev_local_tx);
|
||||||
|
instance->prev_local_poll = 0;
|
||||||
|
instance->prev_tx_count = 0;
|
||||||
|
|
||||||
|
instance->updated_init_timestamps = 0;
|
||||||
|
UTI_ZeroNtp64(&instance->init_remote_ntp_tx);
|
||||||
|
zero_local_timestamp(&instance->init_local_rx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
@@ -883,8 +905,10 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
|||||||
NTP_Local_Timestamp *local_rx, /* The RX time of the received packet */
|
NTP_Local_Timestamp *local_rx, /* The RX time of the received packet */
|
||||||
NTP_Local_Timestamp *local_tx, /* The TX time of the previous packet
|
NTP_Local_Timestamp *local_tx, /* The TX time of the previous packet
|
||||||
RESULT : TX time of this packet */
|
RESULT : TX time of this packet */
|
||||||
NTP_int64 *local_ntp_rx, /* RESULT : receive timestamp from this packet */
|
NTP_int64 *local_ntp_rx, /* The receive timestamp from the previous packet
|
||||||
NTP_int64 *local_ntp_tx, /* RESULT : transmit timestamp from this packet */
|
RESULT : receive timestamp from this packet */
|
||||||
|
NTP_int64 *local_ntp_tx, /* The transmit timestamp from the previous packet
|
||||||
|
RESULT : transmit timestamp from this packet */
|
||||||
NTP_Remote_Address *where_to, /* Where to address the reponse to */
|
NTP_Remote_Address *where_to, /* Where to address the reponse to */
|
||||||
NTP_Local_Address *from /* From what address to send it */
|
NTP_Local_Address *from /* From what address to send it */
|
||||||
)
|
)
|
||||||
@@ -907,8 +931,8 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
|||||||
version = NTP_VERSION;
|
version = NTP_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allow interleaved mode only if there was a prior transmission */
|
/* Check if the packet can be formed in the interleaved mode */
|
||||||
if (interleaved && (!local_tx || UTI_IsZeroTimespec(&local_tx->ts)))
|
if (interleaved && (!remote_ntp_rx || !local_tx || UTI_IsZeroTimespec(&local_tx->ts)))
|
||||||
interleaved = 0;
|
interleaved = 0;
|
||||||
|
|
||||||
smooth_time = 0;
|
smooth_time = 0;
|
||||||
@@ -976,17 +1000,31 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
|||||||
|
|
||||||
UTI_TimespecToNtp64(&our_ref_time, &message.reference_ts, NULL);
|
UTI_TimespecToNtp64(&our_ref_time, &message.reference_ts, NULL);
|
||||||
|
|
||||||
/* Originate - this comes from the last packet the source sent us */
|
/* Don't reveal timestamps which are not necessary for the protocol */
|
||||||
message.originate_ts = interleaved ? *remote_ntp_rx : *remote_ntp_tx;
|
|
||||||
|
|
||||||
/* Prepare random bits which will be added to the receive timestamp */
|
if (my_mode != MODE_CLIENT || interleaved) {
|
||||||
UTI_GetNtp64Fuzz(&ts_fuzz, precision);
|
/* Originate - this comes from the last packet the source sent us */
|
||||||
|
message.originate_ts = interleaved ? *remote_ntp_rx : *remote_ntp_tx;
|
||||||
|
|
||||||
/* Receive - this is when we received the last packet from the source.
|
do {
|
||||||
This timestamp will have been adjusted so that it will now look to
|
/* Prepare random bits which will be added to the receive timestamp */
|
||||||
the source like we have been running on our latest estimate of
|
UTI_GetNtp64Fuzz(&ts_fuzz, precision);
|
||||||
frequency all along */
|
|
||||||
UTI_TimespecToNtp64(&local_receive, &message.receive_ts, &ts_fuzz);
|
/* Receive - this is when we received the last packet from the source.
|
||||||
|
This timestamp will have been adjusted so that it will now look to
|
||||||
|
the source like we have been running on our latest estimate of
|
||||||
|
frequency all along */
|
||||||
|
UTI_TimespecToNtp64(&local_receive, &message.receive_ts, &ts_fuzz);
|
||||||
|
|
||||||
|
/* Do not send a packet with a non-zero receive timestamp equal to the
|
||||||
|
originate timestamp or previous receive timestamp */
|
||||||
|
} while (!UTI_IsZeroNtp64(&message.receive_ts) &&
|
||||||
|
UTI_IsEqualAnyNtp64(&message.receive_ts, &message.originate_ts,
|
||||||
|
local_ntp_rx, NULL));
|
||||||
|
} else {
|
||||||
|
UTI_ZeroNtp64(&message.originate_ts);
|
||||||
|
UTI_ZeroNtp64(&message.receive_ts);
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
/* Prepare random bits which will be added to the transmit timestamp */
|
/* Prepare random bits which will be added to the transmit timestamp */
|
||||||
@@ -1041,10 +1079,16 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
|||||||
&message.transmit_ts, &ts_fuzz);
|
&message.transmit_ts, &ts_fuzz);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Avoid sending messages with non-zero transmit timestamp equal to the
|
/* Do not send a packet with a non-zero transmit timestamp which is
|
||||||
receive timestamp to allow reliable detection of the interleaved mode */
|
equal to any of the following timestamps:
|
||||||
} while (!UTI_CompareNtp64(&message.transmit_ts, &message.receive_ts) &&
|
- receive (to allow reliable detection of the interleaved mode)
|
||||||
!UTI_IsZeroNtp64(&message.transmit_ts));
|
- originate (to prevent the packet from being its own valid response
|
||||||
|
in the symmetric mode)
|
||||||
|
- previous transmit (to invalidate responses to the previous packet)
|
||||||
|
(the precision must be at least -30 to prevent an infinite loop!) */
|
||||||
|
} while (!UTI_IsZeroNtp64(&message.transmit_ts) &&
|
||||||
|
UTI_IsEqualAnyNtp64(&message.transmit_ts, &message.receive_ts,
|
||||||
|
&message.originate_ts, local_ntp_tx));
|
||||||
|
|
||||||
ret = NIO_SendPacket(&message, where_to, from, length, local_tx != NULL);
|
ret = NIO_SendPacket(&message, where_to, from, length, local_tx != NULL);
|
||||||
|
|
||||||
@@ -1070,7 +1114,7 @@ transmit_timeout(void *arg)
|
|||||||
{
|
{
|
||||||
NCR_Instance inst = (NCR_Instance) arg;
|
NCR_Instance inst = (NCR_Instance) arg;
|
||||||
NTP_Local_Address local_addr;
|
NTP_Local_Address local_addr;
|
||||||
int sent;
|
int interleaved, initial, sent;
|
||||||
|
|
||||||
inst->tx_timeout_id = 0;
|
inst->tx_timeout_id = 0;
|
||||||
|
|
||||||
@@ -1079,10 +1123,20 @@ transmit_timeout(void *arg)
|
|||||||
/* With online burst switch to online before last packet */
|
/* With online burst switch to online before last packet */
|
||||||
if (inst->burst_total_samples_to_go <= 1)
|
if (inst->burst_total_samples_to_go <= 1)
|
||||||
inst->opmode = MD_ONLINE;
|
inst->opmode = MD_ONLINE;
|
||||||
|
break;
|
||||||
case MD_BURST_WAS_OFFLINE:
|
case MD_BURST_WAS_OFFLINE:
|
||||||
if (inst->burst_total_samples_to_go <= 0)
|
if (inst->burst_total_samples_to_go <= 0)
|
||||||
take_offline(inst);
|
take_offline(inst);
|
||||||
break;
|
break;
|
||||||
|
case MD_ONLINE:
|
||||||
|
/* Start a new burst if the burst option is enabled and the average
|
||||||
|
polling interval including the burst will not fall below the
|
||||||
|
minimum polling interval */
|
||||||
|
if (inst->auto_burst && inst->local_poll > inst->minpoll && inst->local_poll > 1)
|
||||||
|
NCR_InitiateSampleBurst(inst, BURST_GOOD_SAMPLES,
|
||||||
|
MIN(1 << (inst->local_poll - inst->minpoll),
|
||||||
|
MAX_BURST_TOTAL_SAMPLES));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1110,29 +1164,53 @@ transmit_timeout(void *arg)
|
|||||||
local_addr.if_index = INVALID_IF_INDEX;
|
local_addr.if_index = INVALID_IF_INDEX;
|
||||||
local_addr.sock_fd = inst->local_addr.sock_fd;
|
local_addr.sock_fd = inst->local_addr.sock_fd;
|
||||||
|
|
||||||
|
/* In symmetric mode, don't send a packet in interleaved mode unless it
|
||||||
|
is the first response to the last valid request received from the peer
|
||||||
|
and there was just one response to the previous valid request. This
|
||||||
|
prevents the peer from matching the transmit timestamp with an older
|
||||||
|
response if it can't detect missed responses. In client mode, which has
|
||||||
|
at most one response per request, check how many responses are missing to
|
||||||
|
prevent the server from responding with a very old transmit timestamp. */
|
||||||
|
interleaved = inst->interleaved &&
|
||||||
|
((inst->mode == MODE_CLIENT &&
|
||||||
|
inst->tx_count < MAX_CLIENT_INTERLEAVED_TX) ||
|
||||||
|
(inst->mode == MODE_ACTIVE &&
|
||||||
|
inst->prev_tx_count == 1 && inst->tx_count == 0));
|
||||||
|
|
||||||
|
/* In symmetric mode, if no valid response was received since the previous
|
||||||
|
transmission, respond to the last received packet even if it failed some
|
||||||
|
specific NTP tests. This is necessary for starting and restarting the
|
||||||
|
protocol, e.g. when a packet was lost. */
|
||||||
|
initial = inst->mode == MODE_ACTIVE && !inst->valid_rx &&
|
||||||
|
!UTI_IsZeroNtp64(&inst->init_remote_ntp_tx);
|
||||||
|
|
||||||
|
/* Prepare for the response */
|
||||||
|
inst->valid_rx = 0;
|
||||||
|
inst->updated_init_timestamps = 0;
|
||||||
|
if (initial)
|
||||||
|
inst->valid_timestamps = 0;
|
||||||
|
|
||||||
/* Check whether we need to 'warm up' the link to the other end by
|
/* Check whether we need to 'warm up' the link to the other end by
|
||||||
sending an NTP exchange to ensure both ends' ARP caches are
|
sending an NTP exchange to ensure both ends' ARP caches are
|
||||||
primed or whether we need to send two packets first to ensure a
|
primed or whether we need to send two packets first to ensure a
|
||||||
server in the interleaved mode has a fresh timestamp for us. */
|
server in the interleaved mode has a fresh timestamp for us. */
|
||||||
if (inst->presend_minpoll <= inst->local_poll && !inst->presend_done &&
|
if (inst->presend_minpoll <= inst->local_poll && !inst->presend_done &&
|
||||||
!inst->burst_total_samples_to_go) {
|
!inst->burst_total_samples_to_go) {
|
||||||
inst->presend_done = inst->interleaved ? 2 : 1;
|
inst->presend_done = interleaved ? 2 : 1;
|
||||||
} else if (inst->presend_done > 0) {
|
} else if (inst->presend_done > 0) {
|
||||||
inst->presend_done--;
|
inst->presend_done--;
|
||||||
}
|
}
|
||||||
|
|
||||||
sent = transmit_packet(inst->mode, inst->interleaved, inst->local_poll,
|
/* Send the request (which may also be a response in the symmetric mode) */
|
||||||
inst->version,
|
sent = transmit_packet(inst->mode, interleaved, inst->local_poll, inst->version,
|
||||||
inst->auth_mode, inst->auth_key_id,
|
inst->auth_mode, inst->auth_key_id,
|
||||||
&inst->remote_ntp_rx, &inst->remote_ntp_tx,
|
initial ? NULL : &inst->remote_ntp_rx,
|
||||||
&inst->local_rx, &inst->local_tx,
|
initial ? &inst->init_remote_ntp_tx : &inst->remote_ntp_tx,
|
||||||
&inst->local_ntp_rx, &inst->local_ntp_tx,
|
initial ? &inst->init_local_rx : &inst->local_rx,
|
||||||
&inst->remote_addr,
|
&inst->local_tx, &inst->local_ntp_rx, &inst->local_ntp_tx,
|
||||||
&local_addr);
|
&inst->remote_addr, &local_addr);
|
||||||
|
|
||||||
++inst->tx_count;
|
++inst->tx_count;
|
||||||
inst->valid_rx = 0;
|
|
||||||
inst->updated_timestamps = 0;
|
|
||||||
if (sent)
|
if (sent)
|
||||||
inst->report.total_tx_count++;
|
inst->report.total_tx_count++;
|
||||||
|
|
||||||
@@ -1298,6 +1376,67 @@ check_packet_auth(NTP_Packet *pkt, int length,
|
|||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
|
static int
|
||||||
|
check_delay_ratio(NCR_Instance inst, SST_Stats stats,
|
||||||
|
struct timespec *sample_time, double delay)
|
||||||
|
{
|
||||||
|
double last_sample_ago, predicted_offset, min_delay, skew, std_dev;
|
||||||
|
double max_delay;
|
||||||
|
|
||||||
|
if (inst->max_delay_ratio < 1.0 ||
|
||||||
|
!SST_GetDelayTestData(stats, sample_time, &last_sample_ago,
|
||||||
|
&predicted_offset, &min_delay, &skew, &std_dev))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
max_delay = min_delay * inst->max_delay_ratio +
|
||||||
|
last_sample_ago * (skew + LCL_GetMaxClockError());
|
||||||
|
|
||||||
|
if (delay <= max_delay)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
DEBUG_LOG("maxdelayratio: delay=%e max_delay=%e", delay, max_delay);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
static int
|
||||||
|
check_delay_dev_ratio(NCR_Instance inst, SST_Stats stats,
|
||||||
|
struct timespec *sample_time, double offset, double delay)
|
||||||
|
{
|
||||||
|
double last_sample_ago, predicted_offset, min_delay, skew, std_dev;
|
||||||
|
double delta, max_delta, error_in_estimate;
|
||||||
|
|
||||||
|
if (!SST_GetDelayTestData(stats, sample_time, &last_sample_ago,
|
||||||
|
&predicted_offset, &min_delay, &skew, &std_dev))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Require that the ratio of the increase in delay from the minimum to the
|
||||||
|
standard deviation is less than max_delay_dev_ratio. In the allowed
|
||||||
|
increase in delay include also dispersion. */
|
||||||
|
|
||||||
|
max_delta = std_dev * inst->max_delay_dev_ratio +
|
||||||
|
last_sample_ago * (skew + LCL_GetMaxClockError());
|
||||||
|
delta = (delay - min_delay) / 2.0;
|
||||||
|
|
||||||
|
if (delta <= max_delta)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
error_in_estimate = offset + predicted_offset;
|
||||||
|
|
||||||
|
/* Before we decide to drop the sample, make sure the difference between
|
||||||
|
measured offset and predicted offset is not significantly larger than
|
||||||
|
the increase in delay */
|
||||||
|
if (fabs(error_in_estimate) - delta > max_delta)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
DEBUG_LOG("maxdelaydevratio: error=%e delay=%e delta=%e max_delta=%e",
|
||||||
|
error_in_estimate, delay, delta, max_delta);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
||||||
NTP_Local_Timestamp *rx_ts, NTP_Packet *message, int length)
|
NTP_Local_Timestamp *rx_ts, NTP_Packet *message, int length)
|
||||||
@@ -1354,6 +1493,7 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
|||||||
NTP_Local_Timestamp local_receive, local_transmit;
|
NTP_Local_Timestamp local_receive, local_transmit;
|
||||||
double remote_interval, local_interval, response_time;
|
double remote_interval, local_interval, response_time;
|
||||||
double delay_time, precision;
|
double delay_time, precision;
|
||||||
|
int updated_timestamps;
|
||||||
|
|
||||||
/* ==================== */
|
/* ==================== */
|
||||||
|
|
||||||
@@ -1371,7 +1511,8 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
|||||||
The test values are 1 when passed and 0 when failed. */
|
The test values are 1 when passed and 0 when failed. */
|
||||||
|
|
||||||
/* Test 1 checks for duplicate packet */
|
/* Test 1 checks for duplicate packet */
|
||||||
test1 = !!UTI_CompareNtp64(&message->transmit_ts, &inst->remote_ntp_tx);
|
test1 = UTI_CompareNtp64(&message->receive_ts, &inst->remote_ntp_rx) ||
|
||||||
|
UTI_CompareNtp64(&message->transmit_ts, &inst->remote_ntp_tx);
|
||||||
|
|
||||||
/* Test 2 checks for bogus packet in the basic and interleaved modes. This
|
/* Test 2 checks for bogus packet in the basic and interleaved modes. This
|
||||||
ensures the source is responding to the latest packet we sent to it. */
|
ensures the source is responding to the latest packet we sent to it. */
|
||||||
@@ -1424,7 +1565,8 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
|||||||
if (synced_packet && (!interleaved_packet || inst->valid_timestamps)) {
|
if (synced_packet && (!interleaved_packet || inst->valid_timestamps)) {
|
||||||
/* These are the timespec equivalents of the remote and local epochs */
|
/* These are the timespec equivalents of the remote and local epochs */
|
||||||
struct timespec remote_receive, remote_transmit, remote_request_receive;
|
struct timespec remote_receive, remote_transmit, remote_request_receive;
|
||||||
struct timespec local_average, remote_average;
|
struct timespec local_average, remote_average, prev_remote_transmit;
|
||||||
|
double prev_remote_poll_interval;
|
||||||
|
|
||||||
/* Select remote and local timestamps for the new sample */
|
/* Select remote and local timestamps for the new sample */
|
||||||
if (interleaved_packet) {
|
if (interleaved_packet) {
|
||||||
@@ -1444,10 +1586,12 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
|||||||
local_transmit = inst->local_tx;
|
local_transmit = inst->local_tx;
|
||||||
}
|
}
|
||||||
UTI_Ntp64ToTimespec(&message->transmit_ts, &remote_transmit);
|
UTI_Ntp64ToTimespec(&message->transmit_ts, &remote_transmit);
|
||||||
|
UTI_Ntp64ToTimespec(&inst->remote_ntp_tx, &prev_remote_transmit);
|
||||||
local_receive = inst->local_rx;
|
local_receive = inst->local_rx;
|
||||||
} else {
|
} else {
|
||||||
UTI_Ntp64ToTimespec(&message->receive_ts, &remote_receive);
|
UTI_Ntp64ToTimespec(&message->receive_ts, &remote_receive);
|
||||||
UTI_Ntp64ToTimespec(&message->transmit_ts, &remote_transmit);
|
UTI_Ntp64ToTimespec(&message->transmit_ts, &remote_transmit);
|
||||||
|
UTI_ZeroTimespec(&prev_remote_transmit);
|
||||||
remote_request_receive = remote_receive;
|
remote_request_receive = remote_receive;
|
||||||
local_receive = *rx_ts;
|
local_receive = *rx_ts;
|
||||||
local_transmit = inst->local_tx;
|
local_transmit = inst->local_tx;
|
||||||
@@ -1491,35 +1635,38 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
|||||||
dispersion = MAX(precision, MAX(local_transmit.err, local_receive.err)) +
|
dispersion = MAX(precision, MAX(local_transmit.err, local_receive.err)) +
|
||||||
skew * fabs(local_interval);
|
skew * fabs(local_interval);
|
||||||
|
|
||||||
|
/* If the source is an active peer, this is the minimum assumed interval
|
||||||
|
between previous two transmissions (if not constrained by minpoll) */
|
||||||
|
prev_remote_poll_interval = UTI_Log2ToDouble(MIN(inst->remote_poll,
|
||||||
|
inst->prev_local_poll));
|
||||||
|
|
||||||
/* Additional tests required to pass before accumulating the sample */
|
/* Additional tests required to pass before accumulating the sample */
|
||||||
|
|
||||||
/* Test A requires that the minimum estimate of the peer delay is not
|
/* Test A requires that the minimum estimate of the peer delay is not
|
||||||
larger than the configured maximum, in client mode that the server
|
larger than the configured maximum, in both client modes that the server
|
||||||
processing time is sane, in the interleaved client mode that the
|
processing time is sane, and in interleaved symmetric mode that the
|
||||||
timestamps are not too old, and in the interleaved symmetric mode
|
measured delay and intervals between remote timestamps don't indicate
|
||||||
that the delay is not longer than half of the remote polling interval
|
a missed response */
|
||||||
to detect missed packets */
|
|
||||||
testA = delay - dispersion <= inst->max_delay && precision <= inst->max_delay &&
|
testA = delay - dispersion <= inst->max_delay && precision <= inst->max_delay &&
|
||||||
!(inst->mode == MODE_CLIENT &&
|
!(inst->mode == MODE_CLIENT && response_time > MAX_SERVER_INTERVAL) &&
|
||||||
(response_time > MAX_SERVER_INTERVAL ||
|
|
||||||
(interleaved_packet && inst->tx_count > MAX_CLIENT_INTERLEAVED_TX + 1))) &&
|
|
||||||
!(inst->mode == MODE_ACTIVE && interleaved_packet &&
|
!(inst->mode == MODE_ACTIVE && interleaved_packet &&
|
||||||
delay > UTI_Log2ToDouble(message->poll - 1));
|
(delay > 0.5 * prev_remote_poll_interval ||
|
||||||
|
UTI_CompareNtp64(&message->receive_ts, &message->transmit_ts) <= 0 ||
|
||||||
|
(inst->remote_poll <= inst->prev_local_poll &&
|
||||||
|
UTI_DiffTimespecsToDouble(&remote_transmit, &prev_remote_transmit) >
|
||||||
|
1.5 * prev_remote_poll_interval)));
|
||||||
|
|
||||||
/* Test B requires in the basic client mode that the ratio of the round
|
/* Test B requires in client mode that the ratio of the round trip delay
|
||||||
trip delay to the minimum one currently in the stats data register is
|
to the minimum one currently in the stats data register is less than an
|
||||||
less than an administrator-defined value */
|
administrator-defined value */
|
||||||
testB = inst->max_delay_ratio <= 1.0 ||
|
testB = check_delay_ratio(inst, stats, &sample_time, delay);
|
||||||
!(inst->mode == MODE_CLIENT && !interleaved_packet &&
|
|
||||||
(delay - dispersion) / SST_MinRoundTripDelay(stats) > inst->max_delay_ratio);
|
|
||||||
|
|
||||||
/* Test C requires that the ratio of the increase in delay from the minimum
|
/* Test C requires that the ratio of the increase in delay from the minimum
|
||||||
one in the stats data register to the standard deviation of the offsets
|
one in the stats data register to the standard deviation of the offsets
|
||||||
in the register is less than an administrator-defined value or the
|
in the register is less than an administrator-defined value or the
|
||||||
difference between measured offset and predicted offset is larger than
|
difference between measured offset and predicted offset is larger than
|
||||||
the increase in delay */
|
the increase in delay */
|
||||||
testC = SST_IsGoodSample(stats, -offset, delay, inst->max_delay_dev_ratio,
|
testC = check_delay_dev_ratio(inst, stats, &sample_time, offset, delay);
|
||||||
LCL_GetMaxClockError(), &sample_time);
|
|
||||||
|
|
||||||
/* Test D requires that the remote peer is not synchronised to us to
|
/* Test D requires that the remote peer is not synchronised to us to
|
||||||
prevent a synchronisation loop */
|
prevent a synchronisation loop */
|
||||||
@@ -1550,21 +1697,34 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
|||||||
The authentication test (test5) is required to prevent DoS attacks using
|
The authentication test (test5) is required to prevent DoS attacks using
|
||||||
unauthenticated packets on authenticated symmetric associations. */
|
unauthenticated packets on authenticated symmetric associations. */
|
||||||
if ((inst->mode == MODE_CLIENT && valid_packet && !inst->valid_rx) ||
|
if ((inst->mode == MODE_CLIENT && valid_packet && !inst->valid_rx) ||
|
||||||
(inst->mode == MODE_ACTIVE && (valid_packet || !inst->valid_rx) &&
|
(inst->mode == MODE_ACTIVE && valid_packet &&
|
||||||
test5 && !UTI_IsZeroNtp64(&message->transmit_ts) &&
|
(!inst->valid_rx ||
|
||||||
(!inst->updated_timestamps || (valid_packet && !inst->valid_rx) ||
|
|
||||||
UTI_CompareNtp64(&inst->remote_ntp_tx, &message->transmit_ts) < 0))) {
|
UTI_CompareNtp64(&inst->remote_ntp_tx, &message->transmit_ts) < 0))) {
|
||||||
inst->remote_ntp_rx = message->receive_ts;
|
inst->remote_ntp_rx = message->receive_ts;
|
||||||
inst->remote_ntp_tx = message->transmit_ts;
|
inst->remote_ntp_tx = message->transmit_ts;
|
||||||
inst->local_rx = *rx_ts;
|
inst->local_rx = *rx_ts;
|
||||||
inst->valid_timestamps = synced_packet;
|
inst->valid_timestamps = synced_packet;
|
||||||
inst->updated_timestamps = 1;
|
|
||||||
|
UTI_ZeroNtp64(&inst->init_remote_ntp_tx);
|
||||||
|
zero_local_timestamp(&inst->init_local_rx);
|
||||||
|
inst->updated_init_timestamps = 0;
|
||||||
|
updated_timestamps = 2;
|
||||||
|
|
||||||
/* Don't use the same set of timestamps for the next sample */
|
/* Don't use the same set of timestamps for the next sample */
|
||||||
if (interleaved_packet)
|
if (interleaved_packet)
|
||||||
inst->prev_local_tx = inst->local_tx;
|
inst->prev_local_tx = inst->local_tx;
|
||||||
else
|
else
|
||||||
zero_local_timestamp(&inst->prev_local_tx);
|
zero_local_timestamp(&inst->prev_local_tx);
|
||||||
|
} else if (inst->mode == MODE_ACTIVE &&
|
||||||
|
test1 && !UTI_IsZeroNtp64(&message->transmit_ts) && test5 &&
|
||||||
|
(!inst->updated_init_timestamps ||
|
||||||
|
UTI_CompareNtp64(&inst->init_remote_ntp_tx, &message->transmit_ts) < 0)) {
|
||||||
|
inst->init_remote_ntp_tx = message->transmit_ts;
|
||||||
|
inst->init_local_rx = *rx_ts;
|
||||||
|
inst->updated_init_timestamps = 1;
|
||||||
|
updated_timestamps = 1;
|
||||||
|
} else {
|
||||||
|
updated_timestamps = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Accept at most one response per request. The NTP specification recommends
|
/* Accept at most one response per request. The NTP specification recommends
|
||||||
@@ -1600,17 +1760,21 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
|||||||
DEBUG_LOG("remote_interval=%.9f local_interval=%.9f response_time=%.9f txs=%c rxs=%c",
|
DEBUG_LOG("remote_interval=%.9f local_interval=%.9f response_time=%.9f txs=%c rxs=%c",
|
||||||
remote_interval, local_interval, response_time,
|
remote_interval, local_interval, response_time,
|
||||||
tss_chars[local_transmit.source], tss_chars[local_receive.source]);
|
tss_chars[local_transmit.source], tss_chars[local_receive.source]);
|
||||||
DEBUG_LOG("test123=%d%d%d test567=%d%d%d testABCD=%d%d%d%d kod_rate=%d interleaved=%d presend=%d valid=%d good=%d updated=%d",
|
DEBUG_LOG("test123=%d%d%d test567=%d%d%d testABCD=%d%d%d%d kod_rate=%d interleaved=%d"
|
||||||
|
" presend=%d valid=%d good=%d updated=%d",
|
||||||
test1, test2, test3, test5, test6, test7, testA, testB, testC, testD,
|
test1, test2, test3, test5, test6, test7, testA, testB, testC, testD,
|
||||||
kod_rate, interleaved_packet, inst->presend_done, valid_packet, good_packet,
|
kod_rate, interleaved_packet, inst->presend_done, valid_packet, good_packet,
|
||||||
!UTI_CompareTimespecs(&inst->local_rx.ts, &rx_ts->ts));
|
updated_timestamps);
|
||||||
|
|
||||||
if (valid_packet) {
|
if (valid_packet) {
|
||||||
inst->remote_poll = message->poll;
|
inst->remote_poll = message->poll;
|
||||||
inst->remote_stratum = message->stratum != NTP_INVALID_STRATUM ?
|
inst->remote_stratum = message->stratum != NTP_INVALID_STRATUM ?
|
||||||
message->stratum : NTP_MAX_STRATUM;
|
message->stratum : NTP_MAX_STRATUM;
|
||||||
|
|
||||||
|
inst->prev_local_poll = inst->local_poll;
|
||||||
|
inst->prev_tx_count = inst->tx_count;
|
||||||
inst->tx_count = 0;
|
inst->tx_count = 0;
|
||||||
|
|
||||||
SRC_UpdateReachability(inst->source, synced_packet);
|
SRC_UpdateReachability(inst->source, synced_packet);
|
||||||
|
|
||||||
if (good_packet) {
|
if (good_packet) {
|
||||||
@@ -1891,7 +2055,7 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
|
|||||||
NTP_Mode pkt_mode, my_mode;
|
NTP_Mode pkt_mode, my_mode;
|
||||||
NTP_int64 *local_ntp_rx, *local_ntp_tx;
|
NTP_int64 *local_ntp_rx, *local_ntp_tx;
|
||||||
NTP_Local_Timestamp local_tx, *tx_ts;
|
NTP_Local_Timestamp local_tx, *tx_ts;
|
||||||
int valid_auth, log_index, interleaved, poll;
|
int pkt_version, valid_auth, log_index, interleaved, poll;
|
||||||
AuthenticationMode auth_mode;
|
AuthenticationMode auth_mode;
|
||||||
uint32_t key_id;
|
uint32_t key_id;
|
||||||
|
|
||||||
@@ -1912,6 +2076,7 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
|
|||||||
}
|
}
|
||||||
|
|
||||||
pkt_mode = NTP_LVM_TO_MODE(message->lvm);
|
pkt_mode = NTP_LVM_TO_MODE(message->lvm);
|
||||||
|
pkt_version = NTP_LVM_TO_VERSION(message->lvm);
|
||||||
|
|
||||||
switch (pkt_mode) {
|
switch (pkt_mode) {
|
||||||
case MODE_ACTIVE:
|
case MODE_ACTIVE:
|
||||||
@@ -1922,6 +2087,15 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
|
|||||||
/* Reply with server packet */
|
/* Reply with server packet */
|
||||||
my_mode = MODE_SERVER;
|
my_mode = MODE_SERVER;
|
||||||
break;
|
break;
|
||||||
|
case MODE_UNDEFINED:
|
||||||
|
/* Check if it is an NTPv1 client request (NTPv1 packets have a reserved
|
||||||
|
field instead of the mode field and the actual mode is determined from
|
||||||
|
the port numbers). Don't ever respond with a mode 0 packet! */
|
||||||
|
if (pkt_version == 1 && remote_addr->port != NTP_PORT) {
|
||||||
|
my_mode = MODE_SERVER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Fall through */
|
||||||
default:
|
default:
|
||||||
/* Discard */
|
/* Discard */
|
||||||
DEBUG_LOG("NTP packet discarded pkt_mode=%d", pkt_mode);
|
DEBUG_LOG("NTP packet discarded pkt_mode=%d", pkt_mode);
|
||||||
@@ -1967,7 +2141,8 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
|
|||||||
if (log_index >= 0) {
|
if (log_index >= 0) {
|
||||||
CLG_GetNtpTimestamps(log_index, &local_ntp_rx, &local_ntp_tx);
|
CLG_GetNtpTimestamps(log_index, &local_ntp_rx, &local_ntp_tx);
|
||||||
interleaved = !UTI_IsZeroNtp64(local_ntp_rx) &&
|
interleaved = !UTI_IsZeroNtp64(local_ntp_rx) &&
|
||||||
!UTI_CompareNtp64(&message->originate_ts, local_ntp_rx);
|
!UTI_CompareNtp64(&message->originate_ts, local_ntp_rx) &&
|
||||||
|
UTI_CompareNtp64(&message->receive_ts, &message->transmit_ts);
|
||||||
|
|
||||||
if (interleaved) {
|
if (interleaved) {
|
||||||
UTI_Ntp64ToTimespec(local_ntp_tx, &local_tx.ts);
|
UTI_Ntp64ToTimespec(local_ntp_tx, &local_tx.ts);
|
||||||
@@ -1984,7 +2159,7 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
|
|||||||
poll = MAX(poll, message->poll);
|
poll = MAX(poll, message->poll);
|
||||||
|
|
||||||
/* Send a reply */
|
/* Send a reply */
|
||||||
transmit_packet(my_mode, interleaved, poll, NTP_LVM_TO_VERSION(message->lvm),
|
transmit_packet(my_mode, interleaved, poll, pkt_version,
|
||||||
auth_mode, key_id, &message->receive_ts, &message->transmit_ts,
|
auth_mode, key_id, &message->receive_ts, &message->transmit_ts,
|
||||||
rx_ts, tx_ts, local_ntp_rx, NULL, remote_addr, local_addr);
|
rx_ts, tx_ts, local_ntp_rx, NULL, remote_addr, local_addr);
|
||||||
|
|
||||||
@@ -2092,6 +2267,9 @@ NCR_SlewTimes(NCR_Instance inst, struct timespec *when, double dfreq, double dof
|
|||||||
if (!UTI_IsZeroTimespec(&inst->prev_local_tx.ts))
|
if (!UTI_IsZeroTimespec(&inst->prev_local_tx.ts))
|
||||||
UTI_AdjustTimespec(&inst->prev_local_tx.ts, when, &inst->prev_local_tx.ts, &delta, dfreq,
|
UTI_AdjustTimespec(&inst->prev_local_tx.ts, when, &inst->prev_local_tx.ts, &delta, dfreq,
|
||||||
doffset);
|
doffset);
|
||||||
|
if (!UTI_IsZeroTimespec(&inst->init_local_rx.ts))
|
||||||
|
UTI_AdjustTimespec(&inst->init_local_rx.ts, when, &inst->init_local_rx.ts, &delta, dfreq,
|
||||||
|
doffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|||||||
8
ntp_io.c
8
ntp_io.c
@@ -318,6 +318,9 @@ close_socket(int sock_fd)
|
|||||||
if (sock_fd == INVALID_SOCK_FD)
|
if (sock_fd == INVALID_SOCK_FD)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||||
|
NIO_Linux_NotifySocketClosing(sock_fd);
|
||||||
|
#endif
|
||||||
SCH_RemoveFileHandler(sock_fd);
|
SCH_RemoveFileHandler(sock_fd);
|
||||||
close(sock_fd);
|
close(sock_fd);
|
||||||
}
|
}
|
||||||
@@ -685,6 +688,11 @@ read_from_socket(int sock_fd, int event, void *anything)
|
|||||||
unsigned int i, n;
|
unsigned int i, n;
|
||||||
int status, flags = 0;
|
int status, flags = 0;
|
||||||
|
|
||||||
|
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||||
|
if (NIO_Linux_ProcessEvent(sock_fd, event))
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
hdr = ARR_GetElements(recv_headers);
|
hdr = ARR_GetElements(recv_headers);
|
||||||
n = ARR_GetSize(recv_headers);
|
n = ARR_GetSize(recv_headers);
|
||||||
assert(n >= 1);
|
assert(n >= 1);
|
||||||
|
|||||||
219
ntp_io_linux.c
219
ntp_io_linux.c
@@ -94,6 +94,27 @@ static int ts_tx_flags;
|
|||||||
/* Flag indicating the socket options can't be changed in control messages */
|
/* Flag indicating the socket options can't be changed in control messages */
|
||||||
static int permanent_ts_options;
|
static int permanent_ts_options;
|
||||||
|
|
||||||
|
/* When sending client requests to a close and fast server, it is possible that
|
||||||
|
a response will be received before the HW transmit timestamp of the request
|
||||||
|
itself. To avoid processing of the response without the HW timestamp, we
|
||||||
|
monitor events returned by select() and suspend reading of packets from the
|
||||||
|
receive queue for up to 200 microseconds. As the requests are normally
|
||||||
|
separated by at least 200 milliseconds, it is sufficient to monitor and
|
||||||
|
suspend one socket at a time. */
|
||||||
|
static int monitored_socket;
|
||||||
|
static int suspended_socket;
|
||||||
|
static SCH_TimeoutID resume_timeout_id;
|
||||||
|
|
||||||
|
#define RESUME_TIMEOUT 200.0e-6
|
||||||
|
|
||||||
|
/* Unbound socket keeping the kernel RX timestamping permanently enabled
|
||||||
|
in order to avoid a race condition between receiving a server response
|
||||||
|
and the kernel actually starting to timestamp received packets after
|
||||||
|
enabling the timestamping and sending a request */
|
||||||
|
static int dummy_rxts_socket;
|
||||||
|
|
||||||
|
#define INVALID_SOCK_FD -3
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -154,17 +175,25 @@ add_interface(CNF_HwTsInterface *conf_iface)
|
|||||||
ts_config.tx_type = HWTSTAMP_TX_ON;
|
ts_config.tx_type = HWTSTAMP_TX_ON;
|
||||||
|
|
||||||
switch (conf_iface->rxfilter) {
|
switch (conf_iface->rxfilter) {
|
||||||
|
case CNF_HWTS_RXFILTER_ANY:
|
||||||
|
#ifdef HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP
|
||||||
|
if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_NTP_ALL))
|
||||||
|
ts_config.rx_filter = HWTSTAMP_FILTER_NTP_ALL;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_ALL))
|
||||||
|
ts_config.rx_filter = HWTSTAMP_FILTER_ALL;
|
||||||
|
else
|
||||||
|
ts_config.rx_filter = HWTSTAMP_FILTER_NONE;
|
||||||
|
break;
|
||||||
case CNF_HWTS_RXFILTER_NONE:
|
case CNF_HWTS_RXFILTER_NONE:
|
||||||
ts_config.rx_filter = HWTSTAMP_FILTER_NONE;
|
ts_config.rx_filter = HWTSTAMP_FILTER_NONE;
|
||||||
break;
|
break;
|
||||||
case CNF_HWTS_RXFILTER_NTP:
|
|
||||||
#ifdef HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP
|
#ifdef HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP
|
||||||
if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_NTP_ALL)) {
|
case CNF_HWTS_RXFILTER_NTP:
|
||||||
ts_config.rx_filter = HWTSTAMP_FILTER_NTP_ALL;
|
ts_config.rx_filter = HWTSTAMP_FILTER_NTP_ALL;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
/* Fall through */
|
|
||||||
default:
|
default:
|
||||||
ts_config.rx_filter = HWTSTAMP_FILTER_ALL;
|
ts_config.rx_filter = HWTSTAMP_FILTER_ALL;
|
||||||
break;
|
break;
|
||||||
@@ -203,7 +232,8 @@ add_interface(CNF_HwTsInterface *conf_iface)
|
|||||||
|
|
||||||
iface->clock = HCL_CreateInstance(UTI_Log2ToDouble(MAX(conf_iface->minpoll, MIN_PHC_POLL)));
|
iface->clock = HCL_CreateInstance(UTI_Log2ToDouble(MAX(conf_iface->minpoll, MIN_PHC_POLL)));
|
||||||
|
|
||||||
LOG(LOGS_INFO, "Enabled HW timestamping on %s", iface->name);
|
LOG(LOGS_INFO, "Enabled HW timestamping %son %s",
|
||||||
|
ts_config.rx_filter == HWTSTAMP_FILTER_NONE ? "(TX only) " : "", iface->name);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -243,7 +273,7 @@ update_interface_speed(struct Interface *iface)
|
|||||||
{
|
{
|
||||||
struct ethtool_cmd cmd;
|
struct ethtool_cmd cmd;
|
||||||
struct ifreq req;
|
struct ifreq req;
|
||||||
int sock_fd;
|
int sock_fd, link_speed;
|
||||||
|
|
||||||
sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
if (sock_fd < 0)
|
if (sock_fd < 0)
|
||||||
@@ -264,7 +294,12 @@ update_interface_speed(struct Interface *iface)
|
|||||||
|
|
||||||
close(sock_fd);
|
close(sock_fd);
|
||||||
|
|
||||||
iface->link_speed = ethtool_cmd_speed(&cmd);
|
link_speed = ethtool_cmd_speed(&cmd);
|
||||||
|
|
||||||
|
if (iface->link_speed != link_speed) {
|
||||||
|
iface->link_speed = link_speed;
|
||||||
|
DEBUG_LOG("Updated speed of %s to %d Mb/s", iface->name, link_speed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
@@ -292,6 +327,29 @@ check_timestamping_option(int option)
|
|||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
|
static int
|
||||||
|
open_dummy_socket(void)
|
||||||
|
{
|
||||||
|
int sock_fd, events = 0;
|
||||||
|
|
||||||
|
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0
|
||||||
|
#ifdef FEAT_IPV6
|
||||||
|
&& (sock_fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0
|
||||||
|
#endif
|
||||||
|
)
|
||||||
|
return INVALID_SOCK_FD;
|
||||||
|
|
||||||
|
if (!NIO_Linux_SetTimestampSocketOptions(sock_fd, 1, &events)) {
|
||||||
|
close(sock_fd);
|
||||||
|
return INVALID_SOCK_FD;
|
||||||
|
}
|
||||||
|
|
||||||
|
UTI_FdSetCloexec(sock_fd);
|
||||||
|
return sock_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
void
|
void
|
||||||
NIO_Linux_Initialise(void)
|
NIO_Linux_Initialise(void)
|
||||||
{
|
{
|
||||||
@@ -341,6 +399,10 @@ NIO_Linux_Initialise(void)
|
|||||||
|
|
||||||
/* Kernels before 4.7 ignore timestamping flags set in control messages */
|
/* Kernels before 4.7 ignore timestamping flags set in control messages */
|
||||||
permanent_ts_options = !SYS_Linux_CheckKernelVersion(4, 7);
|
permanent_ts_options = !SYS_Linux_CheckKernelVersion(4, 7);
|
||||||
|
|
||||||
|
monitored_socket = INVALID_SOCK_FD;
|
||||||
|
suspended_socket = INVALID_SOCK_FD;
|
||||||
|
dummy_rxts_socket = INVALID_SOCK_FD;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
@@ -351,6 +413,9 @@ NIO_Linux_Finalise(void)
|
|||||||
struct Interface *iface;
|
struct Interface *iface;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
|
if (dummy_rxts_socket != INVALID_SOCK_FD)
|
||||||
|
close(dummy_rxts_socket);
|
||||||
|
|
||||||
for (i = 0; i < ARR_GetSize(interfaces); i++) {
|
for (i = 0; i < ARR_GetSize(interfaces); i++) {
|
||||||
iface = ARR_GetElement(interfaces, i);
|
iface = ARR_GetElement(interfaces, i);
|
||||||
HCL_DestroyInstance(iface->clock);
|
HCL_DestroyInstance(iface->clock);
|
||||||
@@ -397,6 +462,73 @@ NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events)
|
|||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
|
static void
|
||||||
|
resume_socket(int sock_fd)
|
||||||
|
{
|
||||||
|
if (monitored_socket == sock_fd)
|
||||||
|
monitored_socket = INVALID_SOCK_FD;
|
||||||
|
|
||||||
|
if (sock_fd == INVALID_SOCK_FD || sock_fd != suspended_socket)
|
||||||
|
return;
|
||||||
|
|
||||||
|
suspended_socket = INVALID_SOCK_FD;
|
||||||
|
|
||||||
|
SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_INPUT, 1);
|
||||||
|
|
||||||
|
DEBUG_LOG("Resumed RX processing %s timeout fd=%d",
|
||||||
|
resume_timeout_id ? "before" : "on", sock_fd);
|
||||||
|
|
||||||
|
if (resume_timeout_id) {
|
||||||
|
SCH_RemoveTimeout(resume_timeout_id);
|
||||||
|
resume_timeout_id = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
static void
|
||||||
|
resume_timeout(void *arg)
|
||||||
|
{
|
||||||
|
resume_timeout_id = 0;
|
||||||
|
resume_socket(suspended_socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
static void
|
||||||
|
suspend_socket(int sock_fd)
|
||||||
|
{
|
||||||
|
resume_socket(suspended_socket);
|
||||||
|
|
||||||
|
suspended_socket = sock_fd;
|
||||||
|
|
||||||
|
SCH_SetFileHandlerEvent(suspended_socket, SCH_FILE_INPUT, 0);
|
||||||
|
resume_timeout_id = SCH_AddTimeoutByDelay(RESUME_TIMEOUT, resume_timeout, NULL);
|
||||||
|
|
||||||
|
DEBUG_LOG("Suspended RX processing fd=%d", sock_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
int
|
||||||
|
NIO_Linux_ProcessEvent(int sock_fd, int event)
|
||||||
|
{
|
||||||
|
if (sock_fd != monitored_socket)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (event == SCH_FILE_INPUT) {
|
||||||
|
suspend_socket(monitored_socket);
|
||||||
|
monitored_socket = INVALID_SOCK_FD;
|
||||||
|
|
||||||
|
/* Don't process the message yet */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
static struct Interface *
|
static struct Interface *
|
||||||
get_interface(int if_index)
|
get_interface(int if_index)
|
||||||
{
|
{
|
||||||
@@ -512,14 +644,43 @@ extract_udp_data(unsigned char *msg, NTP_Remote_Address *remote_addr, int len)
|
|||||||
len -= ihl + 8, msg += ihl + 8;
|
len -= ihl + 8, msg += ihl + 8;
|
||||||
#ifdef FEAT_IPV6
|
#ifdef FEAT_IPV6
|
||||||
} else if (len >= 48 && msg[0] >> 4 == 6) {
|
} else if (len >= 48 && msg[0] >> 4 == 6) {
|
||||||
/* IPv6 extension headers are not supported */
|
int eh_len, next_header = msg[6];
|
||||||
if (msg[6] != 17)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
memcpy(&addr.in6.sin6_addr.s6_addr, msg + 24, 16);
|
memcpy(&addr.in6.sin6_addr.s6_addr, msg + 24, 16);
|
||||||
addr.in6.sin6_port = *(uint16_t *)(msg + 40 + 2);
|
len -= 40, msg += 40;
|
||||||
|
|
||||||
|
/* Skip IPv6 extension headers if present */
|
||||||
|
while (next_header != 17) {
|
||||||
|
switch (next_header) {
|
||||||
|
case 44: /* Fragment Header */
|
||||||
|
/* Process only the first fragment */
|
||||||
|
if (ntohs(*(uint16_t *)(msg + 2)) >> 3 != 0)
|
||||||
|
return 0;
|
||||||
|
eh_len = 8;
|
||||||
|
break;
|
||||||
|
case 0: /* Hop-by-Hop Options */
|
||||||
|
case 43: /* Routing Header */
|
||||||
|
case 60: /* Destination Options */
|
||||||
|
case 135: /* Mobility Header */
|
||||||
|
eh_len = 8 * (msg[1] + 1);
|
||||||
|
break;
|
||||||
|
case 51: /* Authentication Header */
|
||||||
|
eh_len = 4 * (msg[1] + 2);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eh_len < 8 || len < eh_len + 8)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
next_header = msg[0];
|
||||||
|
len -= eh_len, msg += eh_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr.in6.sin6_port = *(uint16_t *)(msg + 2);
|
||||||
addr.in6.sin6_family = AF_INET6;
|
addr.in6.sin6_family = AF_INET6;
|
||||||
len -= 48, msg += 48;
|
len -= 8, msg += 8;
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -576,6 +737,11 @@ NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *loc
|
|||||||
} else {
|
} else {
|
||||||
DEBUG_LOG("HW clock not found for interface %d", ts_if_index);
|
DEBUG_LOG("HW clock not found for interface %d", ts_if_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If a HW transmit timestamp was received, resume processing
|
||||||
|
of non-error messages on this socket */
|
||||||
|
if (is_tx)
|
||||||
|
resume_socket(local_addr->sock_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (local_ts->source == NTP_TS_DAEMON && !UTI_IsZeroTimespec(&ts3.ts[0]) &&
|
if (local_ts->source == NTP_TS_DAEMON && !UTI_IsZeroTimespec(&ts3.ts[0]) &&
|
||||||
@@ -600,6 +766,14 @@ NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *loc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If the kernel is slow with enabling RX timestamping, open a dummy
|
||||||
|
socket to keep the kernel RX timestamping permanently enabled */
|
||||||
|
if (!is_tx && local_ts->source == NTP_TS_DAEMON && ts_flags) {
|
||||||
|
DEBUG_LOG("Missing kernel RX timestamp");
|
||||||
|
if (dummy_rxts_socket == INVALID_SOCK_FD)
|
||||||
|
dummy_rxts_socket = open_dummy_socket();
|
||||||
|
}
|
||||||
|
|
||||||
/* Return the message if it's not received from the error queue */
|
/* Return the message if it's not received from the error queue */
|
||||||
if (!is_tx)
|
if (!is_tx)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -644,6 +818,15 @@ NIO_Linux_RequestTxTimestamp(struct msghdr *msg, int cmsglen, int sock_fd)
|
|||||||
{
|
{
|
||||||
struct cmsghdr *cmsg;
|
struct cmsghdr *cmsg;
|
||||||
|
|
||||||
|
if (!ts_flags)
|
||||||
|
return cmsglen;
|
||||||
|
|
||||||
|
/* If a HW transmit timestamp is requested on a client socket, monitor
|
||||||
|
events on the socket in order to avoid processing of a fast response
|
||||||
|
without the HW timestamp of the request */
|
||||||
|
if (ts_tx_flags & SOF_TIMESTAMPING_TX_HARDWARE && !NIO_IsServerSocket(sock_fd))
|
||||||
|
monitored_socket = sock_fd;
|
||||||
|
|
||||||
/* Check if TX timestamping is disabled on this socket */
|
/* Check if TX timestamping is disabled on this socket */
|
||||||
if (permanent_ts_options || !NIO_IsServerSocket(sock_fd))
|
if (permanent_ts_options || !NIO_IsServerSocket(sock_fd))
|
||||||
return cmsglen;
|
return cmsglen;
|
||||||
@@ -663,3 +846,11 @@ NIO_Linux_RequestTxTimestamp(struct msghdr *msg, int cmsglen, int sock_fd)
|
|||||||
|
|
||||||
return cmsglen;
|
return cmsglen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
void
|
||||||
|
NIO_Linux_NotifySocketClosing(int sock_fd)
|
||||||
|
{
|
||||||
|
resume_socket(sock_fd);
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,13 +24,22 @@
|
|||||||
This is the header file for the Linux-specific NTP socket I/O bits.
|
This is the header file for the Linux-specific NTP socket I/O bits.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef GOT_NTP_IO_LINUX_H
|
||||||
|
#define GOT_NTP_IO_LINUX_H
|
||||||
|
|
||||||
extern void NIO_Linux_Initialise(void);
|
extern void NIO_Linux_Initialise(void);
|
||||||
|
|
||||||
extern void NIO_Linux_Finalise(void);
|
extern void NIO_Linux_Finalise(void);
|
||||||
|
|
||||||
extern int NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events);
|
extern int NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events);
|
||||||
|
|
||||||
|
extern int NIO_Linux_ProcessEvent(int sock_fd, int event);
|
||||||
|
|
||||||
extern int NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
|
extern int NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
|
||||||
NTP_Local_Timestamp *local_ts, struct msghdr *hdr, int length);
|
NTP_Local_Timestamp *local_ts, struct msghdr *hdr, int length);
|
||||||
|
|
||||||
extern int NIO_Linux_RequestTxTimestamp(struct msghdr *msg, int cmsglen, int sock_fd);
|
extern int NIO_Linux_RequestTxTimestamp(struct msghdr *msg, int cmsglen, int sock_fd);
|
||||||
|
|
||||||
|
extern void NIO_Linux_NotifySocketClosing(int sock_fd);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ read_write_socket(int sock_fd, int event, void *anything)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/* Disable output and wait for a response */
|
/* Disable output and wait for a response */
|
||||||
SCH_SetFileHandlerEvents(sock_fd, SCH_FILE_INPUT);
|
SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_OUTPUT, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event == SCH_FILE_INPUT) {
|
if (event == SCH_FILE_INPUT) {
|
||||||
@@ -283,7 +283,7 @@ read_write_socket(int sock_fd, int event, void *anything)
|
|||||||
/* Move the head and enable output for the next packet */
|
/* Move the head and enable output for the next packet */
|
||||||
queue_head = NEXT_QUEUE_INDEX(queue_head);
|
queue_head = NEXT_QUEUE_INDEX(queue_head);
|
||||||
if (!IS_QUEUE_EMPTY())
|
if (!IS_QUEUE_EMPTY())
|
||||||
SCH_SetFileHandlerEvents(sock_fd, SCH_FILE_INPUT | SCH_FILE_OUTPUT);
|
SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_OUTPUT, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,7 +369,7 @@ NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_Remote_Address *r
|
|||||||
|
|
||||||
/* Enable output if there was no pending request */
|
/* Enable output if there was no pending request */
|
||||||
if (IS_QUEUE_EMPTY())
|
if (IS_QUEUE_EMPTY())
|
||||||
SCH_SetFileHandlerEvents(sock_fd, SCH_FILE_INPUT | SCH_FILE_OUTPUT);
|
SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_OUTPUT, 1);
|
||||||
|
|
||||||
queue_tail = NEXT_QUEUE_INDEX(queue_tail);
|
queue_tail = NEXT_QUEUE_INDEX(queue_tail);
|
||||||
|
|
||||||
|
|||||||
25
pktlength.c
25
pktlength.c
@@ -114,8 +114,11 @@ static const struct request_length request_lengths[] = {
|
|||||||
client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX2 */
|
client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX2 */
|
||||||
REQ_LENGTH_ENTRY(local, null), /* LOCAL2 */
|
REQ_LENGTH_ENTRY(local, null), /* LOCAL2 */
|
||||||
REQ_LENGTH_ENTRY(ntp_data, ntp_data), /* NTP_DATA */
|
REQ_LENGTH_ENTRY(ntp_data, ntp_data), /* NTP_DATA */
|
||||||
REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_SERVER2 */
|
{ 0, 0 }, /* ADD_SERVER2 */
|
||||||
REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_PEER2 */
|
{ 0, 0 }, /* ADD_PEER2 */
|
||||||
|
REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_SERVER3 */
|
||||||
|
REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_PEER3 */
|
||||||
|
REQ_LENGTH_ENTRY(null, null), /* SHUTDOWN */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint16_t reply_lengths[] = {
|
static const uint16_t reply_lengths[] = {
|
||||||
@@ -130,13 +133,14 @@ static const uint16_t reply_lengths[] = {
|
|||||||
0, /* SUBNETS_ACCESSED - not supported */
|
0, /* SUBNETS_ACCESSED - not supported */
|
||||||
0, /* CLIENT_ACCESSES - not supported */
|
0, /* CLIENT_ACCESSES - not supported */
|
||||||
0, /* CLIENT_ACCESSES_BY_INDEX - not supported */
|
0, /* CLIENT_ACCESSES_BY_INDEX - not supported */
|
||||||
0, /* MANUAL_LIST - variable length */
|
0, /* MANUAL_LIST - not supported */
|
||||||
RPY_LENGTH_ENTRY(activity), /* ACTIVITY */
|
RPY_LENGTH_ENTRY(activity), /* ACTIVITY */
|
||||||
RPY_LENGTH_ENTRY(smoothing), /* SMOOTHING */
|
RPY_LENGTH_ENTRY(smoothing), /* SMOOTHING */
|
||||||
RPY_LENGTH_ENTRY(server_stats), /* SERVER_STATS */
|
RPY_LENGTH_ENTRY(server_stats), /* SERVER_STATS */
|
||||||
RPY_LENGTH_ENTRY(client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX2 */
|
RPY_LENGTH_ENTRY(client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX2 */
|
||||||
RPY_LENGTH_ENTRY(ntp_data), /* NTP_DATA */
|
RPY_LENGTH_ENTRY(ntp_data), /* NTP_DATA */
|
||||||
RPY_LENGTH_ENTRY(manual_timestamp), /* MANUAL_TIMESTAMP2 */
|
RPY_LENGTH_ENTRY(manual_timestamp), /* MANUAL_TIMESTAMP2 */
|
||||||
|
RPY_LENGTH_ENTRY(manual_list), /* MANUAL_LIST2 */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
@@ -193,21 +197,6 @@ PKL_ReplyLength(CMD_Reply *r)
|
|||||||
if (type < 1 || type >= N_REPLY_TYPES)
|
if (type < 1 || type >= N_REPLY_TYPES)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Length of MANUAL_LIST depends on number of samples stored in it */
|
|
||||||
if (type == RPY_MANUAL_LIST) {
|
|
||||||
uint32_t ns;
|
|
||||||
|
|
||||||
if (r->status != htons(STT_SUCCESS))
|
|
||||||
return offsetof(CMD_Reply, data);
|
|
||||||
|
|
||||||
ns = ntohl(r->data.manual_list.n_samples);
|
|
||||||
if (ns > MAX_MANUAL_LIST_SAMPLES)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return offsetof(CMD_Reply, data.manual_list.samples) +
|
|
||||||
ns * sizeof (RPY_ManualListSample);
|
|
||||||
}
|
|
||||||
|
|
||||||
return reply_lengths[type];
|
return reply_lengths[type];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) Bryan Christianson 2015
|
* Copyright (C) Bryan Christianson 2015
|
||||||
* Copyright (C) Miroslav Lichvar 2016
|
* Copyright (C) Miroslav Lichvar 2017
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of version 2 of the GNU General Public License as
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
|
|||||||
52
refclock.c
52
refclock.c
@@ -2,7 +2,7 @@
|
|||||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||||
|
|
||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) Miroslav Lichvar 2009-2011, 2013-2014, 2016
|
* Copyright (C) Miroslav Lichvar 2009-2011, 2013-2014, 2016-2017
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of version 2 of the GNU General Public License as
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
@@ -79,6 +79,8 @@ struct RCL_Instance_Record {
|
|||||||
int pps_rate;
|
int pps_rate;
|
||||||
int pps_active;
|
int pps_active;
|
||||||
int max_lock_age;
|
int max_lock_age;
|
||||||
|
int stratum;
|
||||||
|
int tai;
|
||||||
struct MedianFilter filter;
|
struct MedianFilter filter;
|
||||||
uint32_t ref_id;
|
uint32_t ref_id;
|
||||||
uint32_t lock_ref;
|
uint32_t lock_ref;
|
||||||
@@ -181,13 +183,13 @@ RCL_AddRefclock(RefclockParameters *params)
|
|||||||
inst->driver = &RCL_PHC_driver;
|
inst->driver = &RCL_PHC_driver;
|
||||||
} else {
|
} else {
|
||||||
LOG_FATAL("unknown refclock driver %s", params->driver_name);
|
LOG_FATAL("unknown refclock driver %s", params->driver_name);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!inst->driver->init && !inst->driver->poll) {
|
if (!inst->driver->init && !inst->driver->poll)
|
||||||
LOG_FATAL("refclock driver %s is not compiled in", params->driver_name);
|
LOG_FATAL("refclock driver %s is not compiled in", params->driver_name);
|
||||||
return 0;
|
|
||||||
}
|
if (params->tai && !CNF_GetLeapSecTimezone())
|
||||||
|
LOG_FATAL("refclock tai option requires leapsectz");
|
||||||
|
|
||||||
inst->data = NULL;
|
inst->data = NULL;
|
||||||
inst->driver_parameter = params->driver_parameter;
|
inst->driver_parameter = params->driver_parameter;
|
||||||
@@ -200,6 +202,8 @@ RCL_AddRefclock(RefclockParameters *params)
|
|||||||
inst->pps_rate = params->pps_rate;
|
inst->pps_rate = params->pps_rate;
|
||||||
inst->pps_active = 0;
|
inst->pps_active = 0;
|
||||||
inst->max_lock_age = params->max_lock_age;
|
inst->max_lock_age = params->max_lock_age;
|
||||||
|
inst->stratum = params->stratum;
|
||||||
|
inst->tai = params->tai;
|
||||||
inst->lock_ref = params->lock_ref_id;
|
inst->lock_ref = params->lock_ref_id;
|
||||||
inst->offset = params->offset;
|
inst->offset = params->offset;
|
||||||
inst->delay = params->delay;
|
inst->delay = params->delay;
|
||||||
@@ -251,16 +255,13 @@ RCL_AddRefclock(RefclockParameters *params)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst->driver->init)
|
if (inst->driver->init && !inst->driver->init(inst))
|
||||||
if (!inst->driver->init(inst)) {
|
LOG_FATAL("refclock %s initialisation failed", params->driver_name);
|
||||||
LOG_FATAL("refclock %s initialisation failed", params->driver_name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
filter_init(&inst->filter, params->filter_length, params->max_dispersion);
|
filter_init(&inst->filter, params->filter_length, params->max_dispersion);
|
||||||
|
|
||||||
inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, params->sel_options, NULL,
|
inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, params->sel_options, NULL,
|
||||||
params->min_samples, params->max_samples);
|
params->min_samples, params->max_samples, 0.0, 0.0);
|
||||||
|
|
||||||
DEBUG_LOG("refclock %s refid=%s poll=%d dpoll=%d filter=%d",
|
DEBUG_LOG("refclock %s refid=%s poll=%d dpoll=%d filter=%d",
|
||||||
params->driver_name, UTI_RefidToString(inst->ref_id),
|
params->driver_name, UTI_RefidToString(inst->ref_id),
|
||||||
@@ -356,6 +357,28 @@ RCL_GetDriverOption(RCL_Instance instance, char *name)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
convert_tai_offset(struct timespec *sample_time, double *offset)
|
||||||
|
{
|
||||||
|
struct timespec tai_ts, utc_ts;
|
||||||
|
int tai_offset;
|
||||||
|
|
||||||
|
/* Get approximate TAI-UTC offset for the reference time in TAI */
|
||||||
|
UTI_AddDoubleToTimespec(sample_time, *offset, &tai_ts);
|
||||||
|
tai_offset = REF_GetTaiOffset(&tai_ts);
|
||||||
|
|
||||||
|
/* Get TAI-UTC offset for the reference time in UTC +/- 1 second */
|
||||||
|
UTI_AddDoubleToTimespec(&tai_ts, -tai_offset, &utc_ts);
|
||||||
|
tai_offset = REF_GetTaiOffset(&utc_ts);
|
||||||
|
|
||||||
|
if (!tai_offset)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*offset -= tai_offset;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
RCL_AddSample(RCL_Instance instance, struct timespec *sample_time, double offset, int leap)
|
RCL_AddSample(RCL_Instance instance, struct timespec *sample_time, double offset, int leap)
|
||||||
{
|
{
|
||||||
@@ -385,6 +408,11 @@ RCL_AddSample(RCL_Instance instance, struct timespec *sample_time, double offset
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (instance->tai && !convert_tai_offset(sample_time, &offset)) {
|
||||||
|
DEBUG_LOG("refclock sample ignored unknown TAI offset");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
filter_add_sample(&instance->filter, &cooked_time, offset - correction + instance->offset, dispersion);
|
filter_add_sample(&instance->filter, &cooked_time, offset - correction + instance->offset, dispersion);
|
||||||
instance->pps_active = 0;
|
instance->pps_active = 0;
|
||||||
|
|
||||||
@@ -635,7 +663,7 @@ poll_timeout(void *arg)
|
|||||||
/* Handle special case when PPS is used with local stratum */
|
/* Handle special case when PPS is used with local stratum */
|
||||||
stratum = pps_stratum(inst, &sample_time);
|
stratum = pps_stratum(inst, &sample_time);
|
||||||
else
|
else
|
||||||
stratum = 0;
|
stratum = inst->stratum;
|
||||||
|
|
||||||
SRC_UpdateReachability(inst->source, 1);
|
SRC_UpdateReachability(inst->source, 1);
|
||||||
SRC_AccumulateSample(inst->source, &sample_time, offset,
|
SRC_AccumulateSample(inst->source, &sample_time, offset,
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ typedef struct {
|
|||||||
int max_samples;
|
int max_samples;
|
||||||
int sel_options;
|
int sel_options;
|
||||||
int max_lock_age;
|
int max_lock_age;
|
||||||
|
int stratum;
|
||||||
|
int tai;
|
||||||
uint32_t ref_id;
|
uint32_t ref_id;
|
||||||
uint32_t lock_ref_id;
|
uint32_t lock_ref_id;
|
||||||
double offset;
|
double offset;
|
||||||
|
|||||||
144
reference.c
144
reference.c
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) Richard P. Curnow 1997-2003
|
* Copyright (C) Richard P. Curnow 1997-2003
|
||||||
* Copyright (C) Miroslav Lichvar 2009-2016
|
* Copyright (C) Miroslav Lichvar 2009-2017
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of version 2 of the GNU General Public License as
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
@@ -156,7 +156,8 @@ handle_slew(struct timespec *raw,
|
|||||||
double delta;
|
double delta;
|
||||||
struct timespec now;
|
struct timespec now;
|
||||||
|
|
||||||
UTI_AdjustTimespec(&our_ref_time, cooked, &our_ref_time, &delta, dfreq, doffset);
|
if (!UTI_IsZeroTimespec(&our_ref_time))
|
||||||
|
UTI_AdjustTimespec(&our_ref_time, cooked, &our_ref_time, &delta, dfreq, doffset);
|
||||||
|
|
||||||
if (change_type == LCL_ChangeUnknownStep) {
|
if (change_type == LCL_ChangeUnknownStep) {
|
||||||
UTI_ZeroTimespec(&last_ref_update);
|
UTI_ZeroTimespec(&last_ref_update);
|
||||||
@@ -225,7 +226,7 @@ REF_Initialise(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
logfileid = CNF_GetLogTracking() ? LOG_FileOpen("tracking",
|
logfileid = CNF_GetLogTracking() ? LOG_FileOpen("tracking",
|
||||||
" Date (UTC) Time IP Address St Freq ppm Skew ppm Offset L Co Offset sd Rem. corr.")
|
" Date (UTC) Time IP Address St Freq ppm Skew ppm Offset L Co Offset sd Rem. corr. Root delay Root disp. Max. error")
|
||||||
: -1;
|
: -1;
|
||||||
|
|
||||||
max_update_skew = fabs(CNF_GetMaxUpdateSkew()) * 1.0e-6;
|
max_update_skew = fabs(CNF_GetMaxUpdateSkew()) * 1.0e-6;
|
||||||
@@ -267,6 +268,7 @@ REF_Initialise(void)
|
|||||||
fb_drift_timeout_id = 0;
|
fb_drift_timeout_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UTI_ZeroTimespec(&our_ref_time);
|
||||||
UTI_ZeroTimespec(&last_ref_update);
|
UTI_ZeroTimespec(&last_ref_update);
|
||||||
last_ref_update_interval = 0.0;
|
last_ref_update_interval = 0.0;
|
||||||
|
|
||||||
@@ -607,7 +609,14 @@ is_offset_ok(double offset)
|
|||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
is_leap_second_day(struct tm *stm) {
|
is_leap_second_day(time_t when)
|
||||||
|
{
|
||||||
|
struct tm *stm;
|
||||||
|
|
||||||
|
stm = gmtime(&when);
|
||||||
|
if (!stm)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* Allow leap second only on the last day of June and December */
|
/* Allow leap second only on the last day of June and December */
|
||||||
return (stm->tm_mon == 5 && stm->tm_mday == 30) ||
|
return (stm->tm_mon == 5 && stm->tm_mday == 30) ||
|
||||||
(stm->tm_mon == 11 && stm->tm_mday == 31);
|
(stm->tm_mon == 11 && stm->tm_mday == 31);
|
||||||
@@ -622,7 +631,7 @@ get_tz_leap(time_t when, int *tai_offset)
|
|||||||
static NTP_Leap tz_leap;
|
static NTP_Leap tz_leap;
|
||||||
static int tz_tai_offset;
|
static int tz_tai_offset;
|
||||||
|
|
||||||
struct tm stm;
|
struct tm stm, *tm;
|
||||||
time_t t;
|
time_t t;
|
||||||
char *tz_env, tz_orig[128];
|
char *tz_env, tz_orig[128];
|
||||||
|
|
||||||
@@ -637,7 +646,11 @@ get_tz_leap(time_t when, int *tai_offset)
|
|||||||
tz_leap = LEAP_Normal;
|
tz_leap = LEAP_Normal;
|
||||||
tz_tai_offset = 0;
|
tz_tai_offset = 0;
|
||||||
|
|
||||||
stm = *gmtime(&when);
|
tm = gmtime(&when);
|
||||||
|
if (!tm)
|
||||||
|
return tz_leap;
|
||||||
|
|
||||||
|
stm = *tm;
|
||||||
|
|
||||||
/* Temporarily switch to the timezone containing leap seconds */
|
/* Temporarily switch to the timezone containing leap seconds */
|
||||||
tz_env = getenv("TZ");
|
tz_env = getenv("TZ");
|
||||||
@@ -782,7 +795,7 @@ update_leap_status(NTP_Leap leap, time_t now, int reset)
|
|||||||
if (leap == LEAP_InsertSecond || leap == LEAP_DeleteSecond) {
|
if (leap == LEAP_InsertSecond || leap == LEAP_DeleteSecond) {
|
||||||
/* Check that leap second is allowed today */
|
/* Check that leap second is allowed today */
|
||||||
|
|
||||||
if (is_leap_second_day(gmtime(&now))) {
|
if (is_leap_second_day(now)) {
|
||||||
if (leap == LEAP_InsertSecond) {
|
if (leap == LEAP_InsertSecond) {
|
||||||
leap_sec = 1;
|
leap_sec = 1;
|
||||||
} else {
|
} else {
|
||||||
@@ -820,18 +833,43 @@ update_leap_status(NTP_Leap leap, time_t now, int reset)
|
|||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
|
static double
|
||||||
|
get_root_dispersion(struct timespec *ts)
|
||||||
|
{
|
||||||
|
if (UTI_IsZeroTimespec(&our_ref_time))
|
||||||
|
return 1.0;
|
||||||
|
|
||||||
|
return our_root_dispersion +
|
||||||
|
fabs(UTI_DiffTimespecsToDouble(ts, &our_ref_time)) *
|
||||||
|
(our_skew + fabs(our_residual_freq) + LCL_GetMaxClockError());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
write_log(struct timespec *ref_time, char *ref, int stratum, NTP_Leap leap,
|
write_log(struct timespec *now, int combined_sources, double freq,
|
||||||
double freq, double skew, double offset, int combined_sources,
|
double offset, double offset_sd, double uncorrected_offset,
|
||||||
double offset_sd, double uncorrected_offset)
|
double orig_root_distance)
|
||||||
{
|
{
|
||||||
const char leap_codes[4] = {'N', '+', '-', '?'};
|
const char leap_codes[4] = {'N', '+', '-', '?'};
|
||||||
if (logfileid != -1) {
|
double root_dispersion, max_error;
|
||||||
LOG_FileWrite(logfileid, "%s %-15s %2d %10.3f %10.3f %10.3e %1c %2d %10.3e %10.3e",
|
static double last_sys_offset = 0.0;
|
||||||
UTI_TimeToLogForm(ref_time->tv_sec), ref, stratum, freq, skew,
|
|
||||||
offset, leap_codes[leap], combined_sources, offset_sd,
|
if (logfileid == -1)
|
||||||
uncorrected_offset);
|
return;
|
||||||
}
|
|
||||||
|
max_error = orig_root_distance + fabs(last_sys_offset);
|
||||||
|
root_dispersion = get_root_dispersion(now);
|
||||||
|
last_sys_offset = offset - uncorrected_offset;
|
||||||
|
|
||||||
|
LOG_FileWrite(logfileid,
|
||||||
|
"%s %-15s %2d %10.3f %10.3f %10.3e %1c %2d %10.3e %10.3e %10.3e %10.3e %10.3e",
|
||||||
|
UTI_TimeToLogForm(now->tv_sec),
|
||||||
|
our_ref_ip.family != IPADDR_UNSPEC ?
|
||||||
|
UTI_IPToString(&our_ref_ip) : UTI_RefidToString(our_ref_id),
|
||||||
|
our_stratum, freq, 1.0e6 * our_skew, offset,
|
||||||
|
leap_codes[our_leap_status], combined_sources, offset_sd,
|
||||||
|
uncorrected_offset, our_root_delay, root_dispersion, max_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
@@ -915,8 +953,7 @@ REF_SetReference(int stratum,
|
|||||||
double our_frequency;
|
double our_frequency;
|
||||||
double abs_freq_ppm;
|
double abs_freq_ppm;
|
||||||
double update_interval;
|
double update_interval;
|
||||||
double elapsed;
|
double elapsed, correction_rate, orig_root_distance;
|
||||||
double correction_rate;
|
|
||||||
double uncorrected_offset, accumulate_offset, step_offset;
|
double uncorrected_offset, accumulate_offset, step_offset;
|
||||||
struct timespec now, raw_now;
|
struct timespec now, raw_now;
|
||||||
NTP_int64 ref_fuzz;
|
NTP_int64 ref_fuzz;
|
||||||
@@ -929,28 +966,10 @@ REF_SetReference(int stratum,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Guard against dividing by zero */
|
/* Guard against dividing by zero and NaN */
|
||||||
if (skew < MIN_SKEW)
|
if (!(skew > MIN_SKEW))
|
||||||
skew = MIN_SKEW;
|
skew = MIN_SKEW;
|
||||||
|
|
||||||
/* If we get a serious rounding error in the source stats regression
|
|
||||||
processing, there is a remote chance that the skew argument is a
|
|
||||||
'not a number'. If such a quantity gets propagated into the
|
|
||||||
machine's kernel clock variables, nasty things will happen ..
|
|
||||||
|
|
||||||
To guard against this we need to check whether the skew argument
|
|
||||||
is a reasonable real number. I don't think isnan, isinf etc are
|
|
||||||
platform independent, so the following algorithm is used. */
|
|
||||||
|
|
||||||
{
|
|
||||||
double t;
|
|
||||||
t = (skew + skew) / skew; /* Skew shouldn't be zero either */
|
|
||||||
if ((t < 1.9) || (t > 2.1)) {
|
|
||||||
LOG(LOGS_WARN, "Bogus skew value encountered");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LCL_ReadRawTime(&raw_now);
|
LCL_ReadRawTime(&raw_now);
|
||||||
LCL_GetOffsetCorrection(&raw_now, &uncorrected_offset, NULL);
|
LCL_GetOffsetCorrection(&raw_now, &uncorrected_offset, NULL);
|
||||||
UTI_AddDoubleToTimespec(&raw_now, uncorrected_offset, &now);
|
UTI_AddDoubleToTimespec(&raw_now, uncorrected_offset, &now);
|
||||||
@@ -961,6 +980,8 @@ REF_SetReference(int stratum,
|
|||||||
if (!is_offset_ok(our_offset))
|
if (!is_offset_ok(our_offset))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
orig_root_distance = our_root_delay / 2.0 + get_root_dispersion(&now);
|
||||||
|
|
||||||
are_we_synchronised = leap != LEAP_Unsynchronised ? 1 : 0;
|
are_we_synchronised = leap != LEAP_Unsynchronised ? 1 : 0;
|
||||||
our_stratum = stratum + 1;
|
our_stratum = stratum + 1;
|
||||||
our_ref_id = ref_id;
|
our_ref_id = ref_id;
|
||||||
@@ -1071,16 +1092,8 @@ REF_SetReference(int stratum,
|
|||||||
|
|
||||||
abs_freq_ppm = LCL_ReadAbsoluteFrequency();
|
abs_freq_ppm = LCL_ReadAbsoluteFrequency();
|
||||||
|
|
||||||
write_log(&now,
|
write_log(&now, combined_sources, abs_freq_ppm, our_offset, offset_sd,
|
||||||
our_ref_ip.family != IPADDR_UNSPEC ? UTI_IPToString(&our_ref_ip) : UTI_RefidToString(our_ref_id),
|
uncorrected_offset, orig_root_distance);
|
||||||
our_stratum,
|
|
||||||
our_leap_status,
|
|
||||||
abs_freq_ppm,
|
|
||||||
1.0e6*our_skew,
|
|
||||||
our_offset,
|
|
||||||
combined_sources,
|
|
||||||
offset_sd,
|
|
||||||
uncorrected_offset);
|
|
||||||
|
|
||||||
if (drift_file) {
|
if (drift_file) {
|
||||||
/* Update drift file at most once per hour */
|
/* Update drift file at most once per hour */
|
||||||
@@ -1092,7 +1105,7 @@ REF_SetReference(int stratum,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Update fallback drifts */
|
/* Update fallback drifts */
|
||||||
if (fb_drifts) {
|
if (fb_drifts && are_we_synchronised) {
|
||||||
update_fb_drifts(abs_freq_ppm, update_interval);
|
update_fb_drifts(abs_freq_ppm, update_interval);
|
||||||
schedule_fb_drift(&now);
|
schedule_fb_drift(&now);
|
||||||
}
|
}
|
||||||
@@ -1154,20 +1167,15 @@ REF_SetUnsynchronised(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
update_leap_status(LEAP_Unsynchronised, 0, 0);
|
update_leap_status(LEAP_Unsynchronised, 0, 0);
|
||||||
|
our_ref_ip.family = IPADDR_INET4;
|
||||||
|
our_ref_ip.addr.in4 = 0;
|
||||||
|
our_stratum = 0;
|
||||||
are_we_synchronised = 0;
|
are_we_synchronised = 0;
|
||||||
|
|
||||||
LCL_SetSyncStatus(0, 0.0, 0.0);
|
LCL_SetSyncStatus(0, 0.0, 0.0);
|
||||||
|
|
||||||
write_log(&now,
|
write_log(&now, 0, LCL_ReadAbsoluteFrequency(), 0.0, 0.0, uncorrected_offset,
|
||||||
"0.0.0.0",
|
our_root_delay / 2.0 + get_root_dispersion(&now));
|
||||||
0,
|
|
||||||
our_leap_status,
|
|
||||||
LCL_ReadAbsoluteFrequency(),
|
|
||||||
1.0e6*our_skew,
|
|
||||||
0.0,
|
|
||||||
0,
|
|
||||||
0.0,
|
|
||||||
uncorrected_offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
@@ -1185,14 +1193,12 @@ REF_GetReferenceParams
|
|||||||
double *root_dispersion
|
double *root_dispersion
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
double elapsed, dispersion;
|
double dispersion;
|
||||||
|
|
||||||
assert(initialised);
|
assert(initialised);
|
||||||
|
|
||||||
if (are_we_synchronised) {
|
if (are_we_synchronised) {
|
||||||
elapsed = UTI_DiffTimespecsToDouble(local_time, &our_ref_time);
|
dispersion = get_root_dispersion(local_time);
|
||||||
dispersion = our_root_dispersion +
|
|
||||||
(our_skew + fabs(our_residual_freq) + LCL_GetMaxClockError()) * elapsed;
|
|
||||||
} else {
|
} else {
|
||||||
dispersion = 0.0;
|
dispersion = 0.0;
|
||||||
}
|
}
|
||||||
@@ -1350,6 +1356,18 @@ int REF_IsLeapSecondClose(void)
|
|||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
|
int
|
||||||
|
REF_GetTaiOffset(struct timespec *ts)
|
||||||
|
{
|
||||||
|
int tai_offset;
|
||||||
|
|
||||||
|
get_tz_leap(ts->tv_sec, &tai_offset);
|
||||||
|
|
||||||
|
return tai_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
void
|
void
|
||||||
REF_GetTrackingReport(RPT_TrackingReport *rep)
|
REF_GetTrackingReport(RPT_TrackingReport *rep)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -184,6 +184,9 @@ extern void REF_DisableLocal(void);
|
|||||||
and is better to discard any measurements */
|
and is better to discard any measurements */
|
||||||
extern int REF_IsLeapSecondClose(void);
|
extern int REF_IsLeapSecondClose(void);
|
||||||
|
|
||||||
|
/* Return TAI-UTC offset corresponding to a time in UTC if available */
|
||||||
|
extern int REF_GetTaiOffset(struct timespec *ts);
|
||||||
|
|
||||||
extern void REF_GetTrackingReport(RPT_TrackingReport *rep);
|
extern void REF_GetTrackingReport(RPT_TrackingReport *rep);
|
||||||
|
|
||||||
#endif /* GOT_REFERENCE_H */
|
#endif /* GOT_REFERENCE_H */
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) Richard P. Curnow 1997-2003
|
* Copyright (C) Richard P. Curnow 1997-2003
|
||||||
* Copyright (C) Miroslav Lichvar 2011, 2016
|
* Copyright (C) Miroslav Lichvar 2011, 2016-2017
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of version 2 of the GNU General Public License as
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
|
|||||||
9
sched.c
9
sched.c
@@ -219,13 +219,16 @@ SCH_RemoveFileHandler(int fd)
|
|||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
void
|
void
|
||||||
SCH_SetFileHandlerEvents(int fd, int events)
|
SCH_SetFileHandlerEvent(int fd, int event, int enable)
|
||||||
{
|
{
|
||||||
FileHandlerEntry *ptr;
|
FileHandlerEntry *ptr;
|
||||||
|
|
||||||
assert(events);
|
|
||||||
ptr = ARR_GetElement(file_handlers, fd);
|
ptr = ARR_GetElement(file_handlers, fd);
|
||||||
ptr->events = events;
|
|
||||||
|
if (enable)
|
||||||
|
ptr->events |= event;
|
||||||
|
else
|
||||||
|
ptr->events &= ~event;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|||||||
5
sched.h
5
sched.h
@@ -34,7 +34,8 @@ typedef unsigned int SCH_TimeoutID;
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SCH_ReservedTimeoutValue = 0,
|
SCH_ReservedTimeoutValue = 0,
|
||||||
SCH_NtpSamplingClass,
|
SCH_NtpClientClass,
|
||||||
|
SCH_NtpPeerClass,
|
||||||
SCH_NtpBroadcastClass,
|
SCH_NtpBroadcastClass,
|
||||||
SCH_NumberOfClasses /* needs to be last */
|
SCH_NumberOfClasses /* needs to be last */
|
||||||
} SCH_TimeoutClass;
|
} SCH_TimeoutClass;
|
||||||
@@ -59,7 +60,7 @@ extern void SCH_Finalise(void);
|
|||||||
/* Register a handler for when select goes true on a file descriptor */
|
/* Register a handler for when select goes true on a file descriptor */
|
||||||
extern void SCH_AddFileHandler(int fd, int events, SCH_FileHandler handler, SCH_ArbitraryArgument arg);
|
extern void SCH_AddFileHandler(int fd, int events, SCH_FileHandler handler, SCH_ArbitraryArgument arg);
|
||||||
extern void SCH_RemoveFileHandler(int fd);
|
extern void SCH_RemoveFileHandler(int fd);
|
||||||
extern void SCH_SetFileHandlerEvents(int fd, int events);
|
extern void SCH_SetFileHandlerEvent(int fd, int event, int enable);
|
||||||
|
|
||||||
/* Get the time stamp taken after a file descriptor became ready or a timeout expired */
|
/* Get the time stamp taken after a file descriptor became ready or a timeout expired */
|
||||||
extern void SCH_GetLastEventTime(struct timespec *cooked, double *err, struct timespec *raw);
|
extern void SCH_GetLastEventTime(struct timespec *cooked, double *err, struct timespec *raw);
|
||||||
|
|||||||
5
smooth.c
5
smooth.c
@@ -246,7 +246,8 @@ handle_slew(struct timespec *raw, struct timespec *cooked, double dfreq,
|
|||||||
update_smoothing(cooked, doffset, dfreq);
|
update_smoothing(cooked, doffset, dfreq);
|
||||||
}
|
}
|
||||||
|
|
||||||
UTI_AdjustTimespec(&last_update, cooked, &last_update, &delta, dfreq, doffset);
|
if (!UTI_IsZeroTimespec(&last_update))
|
||||||
|
UTI_AdjustTimespec(&last_update, cooked, &last_update, &delta, dfreq, doffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMT_Initialise(void)
|
void SMT_Initialise(void)
|
||||||
@@ -264,6 +265,8 @@ void SMT_Initialise(void)
|
|||||||
max_freq *= 1e-6;
|
max_freq *= 1e-6;
|
||||||
max_wander *= 1e-6;
|
max_wander *= 1e-6;
|
||||||
|
|
||||||
|
UTI_ZeroTimespec(&last_update);
|
||||||
|
|
||||||
LCL_AddParameterChangeHandler(handle_slew, NULL);
|
LCL_AddParameterChangeHandler(handle_slew, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
17
sources.c
17
sources.c
@@ -213,7 +213,9 @@ void SRC_Finalise(void)
|
|||||||
/* Function to create a new instance. This would be called by one of
|
/* Function to create a new instance. This would be called by one of
|
||||||
the individual source-type instance creation routines. */
|
the individual source-type instance creation routines. */
|
||||||
|
|
||||||
SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_options, IPAddr *addr, int min_samples, int max_samples)
|
SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_options,
|
||||||
|
IPAddr *addr, int min_samples, int max_samples,
|
||||||
|
double min_delay, double asymmetry)
|
||||||
{
|
{
|
||||||
SRC_Instance result;
|
SRC_Instance result;
|
||||||
|
|
||||||
@@ -225,7 +227,8 @@ SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_optio
|
|||||||
max_samples = CNF_GetMaxSamples();
|
max_samples = CNF_GetMaxSamples();
|
||||||
|
|
||||||
result = MallocNew(struct SRC_Instance_Record);
|
result = MallocNew(struct SRC_Instance_Record);
|
||||||
result->stats = SST_CreateInstance(ref_id, addr, min_samples, max_samples);
|
result->stats = SST_CreateInstance(ref_id, addr, min_samples, max_samples,
|
||||||
|
min_delay, asymmetry);
|
||||||
|
|
||||||
if (n_sources == max_n_sources) {
|
if (n_sources == max_n_sources) {
|
||||||
/* Reallocate memory */
|
/* Reallocate memory */
|
||||||
@@ -662,6 +665,16 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Include extra dispersion in the root distance of sources that don't
|
||||||
|
have new samples (the last sample is older than span of all samples) */
|
||||||
|
if (first_sample_ago < 2.0 * si->last_sample_ago) {
|
||||||
|
double extra_disp = LCL_GetMaxClockError() *
|
||||||
|
(2.0 * si->last_sample_ago - first_sample_ago);
|
||||||
|
si->root_distance += extra_disp;
|
||||||
|
si->lo_limit -= extra_disp;
|
||||||
|
si->hi_limit += extra_disp;
|
||||||
|
}
|
||||||
|
|
||||||
/* Require the root distance to be below the allowed maximum */
|
/* Require the root distance to be below the allowed maximum */
|
||||||
if (si->root_distance > max_distance) {
|
if (si->root_distance > max_distance) {
|
||||||
sources[i]->status = SRC_BAD_DISTANCE;
|
sources[i]->status = SRC_BAD_DISTANCE;
|
||||||
|
|||||||
@@ -59,7 +59,9 @@ typedef enum {
|
|||||||
/* Function to create a new instance. This would be called by one of
|
/* Function to create a new instance. This would be called by one of
|
||||||
the individual source-type instance creation routines. */
|
the individual source-type instance creation routines. */
|
||||||
|
|
||||||
extern SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_options, IPAddr *addr, int min_samples, int max_samples);
|
extern SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_options,
|
||||||
|
IPAddr *addr, int min_samples, int max_samples,
|
||||||
|
double min_delay, double asymmetry);
|
||||||
|
|
||||||
/* Function to get rid of a source when it is being unconfigured.
|
/* Function to get rid of a source when it is being unconfigured.
|
||||||
This may cause the current reference source to be reselected, if this
|
This may cause the current reference source to be reselected, if this
|
||||||
|
|||||||
132
sourcestats.c
132
sourcestats.c
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) Richard P. Curnow 1997-2003
|
* Copyright (C) Richard P. Curnow 1997-2003
|
||||||
* Copyright (C) Miroslav Lichvar 2011-2014, 2016
|
* Copyright (C) Miroslav Lichvar 2011-2014, 2016-2017
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of version 2 of the GNU General Public License as
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
@@ -51,6 +51,9 @@
|
|||||||
#define MIN_SKEW 1.0e-12
|
#define MIN_SKEW 1.0e-12
|
||||||
#define MAX_SKEW 1.0e+02
|
#define MAX_SKEW 1.0e+02
|
||||||
|
|
||||||
|
/* The minimum standard deviation */
|
||||||
|
#define MIN_STDDEV 1.0e-9
|
||||||
|
|
||||||
/* The asymmetry of network jitter when all jitter is in one direction */
|
/* The asymmetry of network jitter when all jitter is in one direction */
|
||||||
#define MAX_ASYMMETRY 0.5
|
#define MAX_ASYMMETRY 0.5
|
||||||
|
|
||||||
@@ -82,6 +85,12 @@ struct SST_Stats_Record {
|
|||||||
int min_samples;
|
int min_samples;
|
||||||
int max_samples;
|
int max_samples;
|
||||||
|
|
||||||
|
/* User defined minimum delay */
|
||||||
|
double fixed_min_delay;
|
||||||
|
|
||||||
|
/* User defined asymmetry of network jitter */
|
||||||
|
double fixed_asymmetry;
|
||||||
|
|
||||||
/* Number of samples currently stored. The samples are stored in circular
|
/* Number of samples currently stored. The samples are stored in circular
|
||||||
buffer. */
|
buffer. */
|
||||||
int n_samples;
|
int n_samples;
|
||||||
@@ -197,13 +206,16 @@ SST_Finalise(void)
|
|||||||
/* This function creates a new instance of the statistics handler */
|
/* This function creates a new instance of the statistics handler */
|
||||||
|
|
||||||
SST_Stats
|
SST_Stats
|
||||||
SST_CreateInstance(uint32_t refid, IPAddr *addr, int min_samples, int max_samples)
|
SST_CreateInstance(uint32_t refid, IPAddr *addr, int min_samples, int max_samples,
|
||||||
|
double min_delay, double asymmetry)
|
||||||
{
|
{
|
||||||
SST_Stats inst;
|
SST_Stats inst;
|
||||||
inst = MallocNew(struct SST_Stats_Record);
|
inst = MallocNew(struct SST_Stats_Record);
|
||||||
|
|
||||||
inst->min_samples = min_samples;
|
inst->min_samples = min_samples;
|
||||||
inst->max_samples = max_samples;
|
inst->max_samples = max_samples;
|
||||||
|
inst->fixed_min_delay = min_delay;
|
||||||
|
inst->fixed_asymmetry = asymmetry;
|
||||||
|
|
||||||
SST_SetRefid(inst, refid, addr);
|
SST_SetRefid(inst, refid, addr);
|
||||||
SST_ResetInstance(inst);
|
SST_ResetInstance(inst);
|
||||||
@@ -310,6 +322,9 @@ SST_AccumulateSample(SST_Stats inst, struct timespec *sample_time,
|
|||||||
inst->root_dispersions[m] = root_dispersion;
|
inst->root_dispersions[m] = root_dispersion;
|
||||||
inst->strata[m] = stratum;
|
inst->strata[m] = stratum;
|
||||||
|
|
||||||
|
if (inst->peer_delays[n] < inst->fixed_min_delay)
|
||||||
|
inst->peer_delays[n] = 2.0 * inst->fixed_min_delay - inst->peer_delays[n];
|
||||||
|
|
||||||
if (!inst->n_samples || inst->peer_delays[n] < inst->peer_delays[inst->min_delay_sample])
|
if (!inst->n_samples || inst->peer_delays[n] < inst->peer_delays[inst->min_delay_sample])
|
||||||
inst->min_delay_sample = n;
|
inst->min_delay_sample = n;
|
||||||
|
|
||||||
@@ -415,45 +430,63 @@ find_min_delay_sample(SST_Stats inst)
|
|||||||
minimum network delay. This can significantly improve the accuracy and
|
minimum network delay. This can significantly improve the accuracy and
|
||||||
stability of the estimated offset and frequency. */
|
stability of the estimated offset and frequency. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
estimate_asymmetry(double *times_back, double *offsets, double *delays, int n,
|
||||||
|
double *asymmetry, int *asymmetry_run)
|
||||||
|
{
|
||||||
|
double a;
|
||||||
|
|
||||||
|
/* Reset the counter when the regression fails or the sign changes */
|
||||||
|
if (!RGR_MultipleRegress(times_back, delays, offsets, n, &a) ||
|
||||||
|
a * *asymmetry_run < 0.0) {
|
||||||
|
*asymmetry = 0;
|
||||||
|
*asymmetry_run = 0.0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a <= -MIN_ASYMMETRY && *asymmetry_run > -MAX_ASYMMETRY_RUN)
|
||||||
|
(*asymmetry_run)--;
|
||||||
|
else if (a >= MIN_ASYMMETRY && *asymmetry_run < MAX_ASYMMETRY_RUN)
|
||||||
|
(*asymmetry_run)++;
|
||||||
|
|
||||||
|
if (abs(*asymmetry_run) < MIN_ASYMMETRY_RUN)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*asymmetry = CLAMP(-MAX_ASYMMETRY, a, MAX_ASYMMETRY);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
correct_asymmetry(SST_Stats inst, double *times_back, double *offsets)
|
correct_asymmetry(SST_Stats inst, double *times_back, double *offsets)
|
||||||
{
|
{
|
||||||
double asymmetry, delays[MAX_SAMPLES * REGRESS_RUNS_RATIO];
|
double min_delay, delays[MAX_SAMPLES * REGRESS_RUNS_RATIO];
|
||||||
int i, n;
|
int i, n;
|
||||||
|
|
||||||
/* Don't try to estimate the asymmetry with reference clocks */
|
/* Check if the asymmetry was not specified to be zero */
|
||||||
if (!inst->ip_addr)
|
if (inst->fixed_asymmetry == 0.0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
min_delay = SST_MinRoundTripDelay(inst);
|
||||||
n = inst->runs_samples + inst->n_samples;
|
n = inst->runs_samples + inst->n_samples;
|
||||||
|
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
delays[i] = inst->peer_delays[get_runsbuf_index(inst, i - inst->runs_samples)] -
|
delays[i] = inst->peer_delays[get_runsbuf_index(inst, i - inst->runs_samples)] -
|
||||||
inst->peer_delays[inst->min_delay_sample];
|
min_delay;
|
||||||
|
|
||||||
/* Reset the counter when the regression fails or the sign changes */
|
if (fabs(inst->fixed_asymmetry) <= MAX_ASYMMETRY) {
|
||||||
if (!RGR_MultipleRegress(times_back, delays, offsets, n, &asymmetry) ||
|
inst->asymmetry = inst->fixed_asymmetry;
|
||||||
asymmetry * inst->asymmetry_run < 0.0) {
|
} else {
|
||||||
inst->asymmetry_run = 0;
|
if (!estimate_asymmetry(times_back, offsets, delays, n,
|
||||||
inst->asymmetry = 0.0;
|
&inst->asymmetry, &inst->asymmetry_run))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
asymmetry = CLAMP(-MAX_ASYMMETRY, asymmetry, MAX_ASYMMETRY);
|
|
||||||
|
|
||||||
if (asymmetry <= -MIN_ASYMMETRY && inst->asymmetry_run > -MAX_ASYMMETRY_RUN)
|
|
||||||
inst->asymmetry_run--;
|
|
||||||
else if (asymmetry >= MIN_ASYMMETRY && inst->asymmetry_run < MAX_ASYMMETRY_RUN)
|
|
||||||
inst->asymmetry_run++;
|
|
||||||
|
|
||||||
if (abs(inst->asymmetry_run) < MIN_ASYMMETRY_RUN)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Correct the offsets */
|
/* Correct the offsets */
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
offsets[i] -= asymmetry * delays[i];
|
offsets[i] -= inst->asymmetry * delays[i];
|
||||||
|
|
||||||
inst->asymmetry = asymmetry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
@@ -541,7 +574,7 @@ SST_DoNewRegression(SST_Stats inst)
|
|||||||
inst->estimated_offset = est_intercept;
|
inst->estimated_offset = est_intercept;
|
||||||
inst->offset_time = inst->sample_times[inst->last_sample];
|
inst->offset_time = inst->sample_times[inst->last_sample];
|
||||||
inst->estimated_offset_sd = est_intercept_sd;
|
inst->estimated_offset_sd = est_intercept_sd;
|
||||||
inst->std_dev = sqrt(est_var);
|
inst->std_dev = MAX(MIN_STDDEV, sqrt(est_var));
|
||||||
inst->nruns = nruns;
|
inst->nruns = nruns;
|
||||||
|
|
||||||
inst->skew = CLAMP(MIN_SKEW, inst->skew, MAX_SKEW);
|
inst->skew = CLAMP(MIN_SKEW, inst->skew, MAX_SKEW);
|
||||||
@@ -771,47 +804,33 @@ SST_PredictOffset(SST_Stats inst, struct timespec *when)
|
|||||||
double
|
double
|
||||||
SST_MinRoundTripDelay(SST_Stats inst)
|
SST_MinRoundTripDelay(SST_Stats inst)
|
||||||
{
|
{
|
||||||
|
if (inst->fixed_min_delay > 0.0)
|
||||||
|
return inst->fixed_min_delay;
|
||||||
|
|
||||||
if (!inst->n_samples)
|
if (!inst->n_samples)
|
||||||
return DBL_MAX;
|
return DBL_MAX;
|
||||||
|
|
||||||
return inst->peer_delays[inst->min_delay_sample];
|
return inst->peer_delays[inst->min_delay_sample];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
int
|
int
|
||||||
SST_IsGoodSample(SST_Stats inst, double offset, double delay,
|
SST_GetDelayTestData(SST_Stats inst, struct timespec *sample_time,
|
||||||
double max_delay_dev_ratio, double clock_error, struct timespec *when)
|
double *last_sample_ago, double *predicted_offset,
|
||||||
|
double *min_delay, double *skew, double *std_dev)
|
||||||
{
|
{
|
||||||
double elapsed, allowed_increase, delay_increase;
|
|
||||||
|
|
||||||
if (inst->n_samples < 6)
|
if (inst->n_samples < 6)
|
||||||
return 1;
|
return 0;
|
||||||
|
|
||||||
elapsed = UTI_DiffTimespecsToDouble(when, &inst->offset_time);
|
*last_sample_ago = UTI_DiffTimespecsToDouble(sample_time, &inst->offset_time);
|
||||||
|
*predicted_offset = inst->estimated_offset +
|
||||||
|
*last_sample_ago * inst->estimated_frequency;
|
||||||
|
*min_delay = SST_MinRoundTripDelay(inst);
|
||||||
|
*skew = inst->skew;
|
||||||
|
*std_dev = inst->std_dev;
|
||||||
|
|
||||||
/* Require that the ratio of the increase in delay from the minimum to the
|
return 1;
|
||||||
standard deviation is less than max_delay_dev_ratio. In the allowed
|
|
||||||
increase in delay include also skew and clock_error. */
|
|
||||||
|
|
||||||
allowed_increase = inst->std_dev * max_delay_dev_ratio +
|
|
||||||
elapsed * (inst->skew + clock_error);
|
|
||||||
delay_increase = (delay - SST_MinRoundTripDelay(inst)) / 2.0;
|
|
||||||
|
|
||||||
if (delay_increase < allowed_increase)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
offset -= inst->estimated_offset + elapsed * inst->estimated_frequency;
|
|
||||||
|
|
||||||
/* Before we decide to drop the sample, make sure the difference between
|
|
||||||
measured offset and predicted offset is not significantly larger than
|
|
||||||
the increase in delay */
|
|
||||||
if (fabs(offset) - delay_increase > allowed_increase)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
DEBUG_LOG("Bad sample: offset=%f delay=%f incr_delay=%f allowed=%f",
|
|
||||||
offset, delay, delay_increase, allowed_increase);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
@@ -868,7 +887,7 @@ SST_LoadFromFile(SST_Stats inst, FILE *in)
|
|||||||
char line[1024];
|
char line[1024];
|
||||||
double weight;
|
double weight;
|
||||||
|
|
||||||
assert(!inst->n_samples);
|
SST_ResetInstance(inst);
|
||||||
|
|
||||||
if (fgets(line, sizeof(line), in) &&
|
if (fgets(line, sizeof(line), in) &&
|
||||||
sscanf(line, "%d", &inst->n_samples) == 1 &&
|
sscanf(line, "%d", &inst->n_samples) == 1 &&
|
||||||
@@ -917,7 +936,6 @@ SST_LoadFromFile(SST_Stats inst, FILE *in)
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
inst->last_sample = inst->n_samples - 1;
|
inst->last_sample = inst->n_samples - 1;
|
||||||
inst->runs_samples = 0;
|
|
||||||
|
|
||||||
find_min_delay_sample(inst);
|
find_min_delay_sample(inst);
|
||||||
SST_DoNewRegression(inst);
|
SST_DoNewRegression(inst);
|
||||||
|
|||||||
@@ -38,7 +38,9 @@ extern void SST_Initialise(void);
|
|||||||
extern void SST_Finalise(void);
|
extern void SST_Finalise(void);
|
||||||
|
|
||||||
/* This function creates a new instance of the statistics handler */
|
/* This function creates a new instance of the statistics handler */
|
||||||
extern SST_Stats SST_CreateInstance(uint32_t refid, IPAddr *addr, int min_samples, int max_samples);
|
extern SST_Stats SST_CreateInstance(uint32_t refid, IPAddr *addr,
|
||||||
|
int min_samples, int max_samples,
|
||||||
|
double min_delay, double asymmetry);
|
||||||
|
|
||||||
/* This function deletes an instance of the statistics handler. */
|
/* This function deletes an instance of the statistics handler. */
|
||||||
extern void SST_DeleteInstance(SST_Stats inst);
|
extern void SST_DeleteInstance(SST_Stats inst);
|
||||||
@@ -124,10 +126,10 @@ extern double SST_PredictOffset(SST_Stats inst, struct timespec *when);
|
|||||||
/* Find the minimum round trip delay in the register */
|
/* Find the minimum round trip delay in the register */
|
||||||
extern double SST_MinRoundTripDelay(SST_Stats inst);
|
extern double SST_MinRoundTripDelay(SST_Stats inst);
|
||||||
|
|
||||||
/* This routine determines if a new sample is good enough that it should be
|
/* Get data needed for testing NTP delay */
|
||||||
accumulated */
|
extern int SST_GetDelayTestData(SST_Stats inst, struct timespec *sample_time,
|
||||||
extern int SST_IsGoodSample(SST_Stats inst, double offset, double delay,
|
double *last_sample_ago, double *predicted_offset,
|
||||||
double max_delay_dev_ratio, double clock_error, struct timespec *when);
|
double *min_delay, double *skew, double *std_dev);
|
||||||
|
|
||||||
extern void SST_SaveToFile(SST_Stats inst, FILE *out);
|
extern void SST_SaveToFile(SST_Stats inst, FILE *out);
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ typedef struct {
|
|||||||
int online;
|
int online;
|
||||||
int auto_offline;
|
int auto_offline;
|
||||||
int presend_minpoll;
|
int presend_minpoll;
|
||||||
|
int burst;
|
||||||
int iburst;
|
int iburst;
|
||||||
int min_stratum;
|
int min_stratum;
|
||||||
int poll_target;
|
int poll_target;
|
||||||
@@ -48,6 +49,8 @@ typedef struct {
|
|||||||
double max_delay;
|
double max_delay;
|
||||||
double max_delay_ratio;
|
double max_delay_ratio;
|
||||||
double max_delay_dev_ratio;
|
double max_delay_dev_ratio;
|
||||||
|
double min_delay;
|
||||||
|
double asymmetry;
|
||||||
double offset;
|
double offset;
|
||||||
} SourceParameters;
|
} SourceParameters;
|
||||||
|
|
||||||
@@ -63,6 +66,7 @@ typedef struct {
|
|||||||
#define SRC_DEFAULT_MAXSOURCES 4
|
#define SRC_DEFAULT_MAXSOURCES 4
|
||||||
#define SRC_DEFAULT_MINSAMPLES (-1)
|
#define SRC_DEFAULT_MINSAMPLES (-1)
|
||||||
#define SRC_DEFAULT_MAXSAMPLES (-1)
|
#define SRC_DEFAULT_MAXSAMPLES (-1)
|
||||||
|
#define SRC_DEFAULT_ASYMMETRY 1.0
|
||||||
#define INACTIVE_AUTHKEY 0
|
#define INACTIVE_AUTHKEY 0
|
||||||
|
|
||||||
/* Flags for source selection */
|
/* Flags for source selection */
|
||||||
|
|||||||
2
sys.c
2
sys.c
@@ -97,7 +97,7 @@ SYS_Finalise(void)
|
|||||||
void SYS_DropRoot(uid_t uid, gid_t gid)
|
void SYS_DropRoot(uid_t uid, gid_t gid)
|
||||||
{
|
{
|
||||||
#if defined(LINUX) && defined (FEAT_PRIVDROP)
|
#if defined(LINUX) && defined (FEAT_PRIVDROP)
|
||||||
SYS_Linux_DropRoot(uid, gid);
|
SYS_Linux_DropRoot(uid, gid, !null_driver);
|
||||||
#elif defined(SOLARIS) && defined(FEAT_PRIVDROP)
|
#elif defined(SOLARIS) && defined(FEAT_PRIVDROP)
|
||||||
SYS_Solaris_DropRoot(uid, gid);
|
SYS_Solaris_DropRoot(uid, gid);
|
||||||
#elif (defined(NETBSD) || defined(FREEBSD)) && defined(FEAT_PRIVDROP)
|
#elif (defined(NETBSD) || defined(FREEBSD)) && defined(FEAT_PRIVDROP)
|
||||||
|
|||||||
41
sys_linux.c
41
sys_linux.c
@@ -4,7 +4,7 @@
|
|||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) Richard P. Curnow 1997-2003
|
* Copyright (C) Richard P. Curnow 1997-2003
|
||||||
* Copyright (C) John G. Hasler 2009
|
* Copyright (C) John G. Hasler 2009
|
||||||
* Copyright (C) Miroslav Lichvar 2009-2012, 2014-2016
|
* Copyright (C) Miroslav Lichvar 2009-2012, 2014-2017
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of version 2 of the GNU General Public License as
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
@@ -380,6 +380,18 @@ test_step_offset(void)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
static void
|
||||||
|
report_time_adjust_blockers(void)
|
||||||
|
{
|
||||||
|
#ifdef FEAT_PRIVDROP
|
||||||
|
if (CAP_IS_SUPPORTED(CAP_SYS_TIME) && cap_get_bound(CAP_SYS_TIME))
|
||||||
|
return;
|
||||||
|
LOG(LOGS_WARN, "CAP_SYS_TIME not present");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
/* Initialisation code for this module */
|
/* Initialisation code for this module */
|
||||||
|
|
||||||
@@ -388,6 +400,8 @@ SYS_Linux_Initialise(void)
|
|||||||
{
|
{
|
||||||
get_version_specific_details();
|
get_version_specific_details();
|
||||||
|
|
||||||
|
report_time_adjust_blockers();
|
||||||
|
|
||||||
reset_adjtime_offset();
|
reset_adjtime_offset();
|
||||||
|
|
||||||
if (have_setoffset && !test_step_offset()) {
|
if (have_setoffset && !test_step_offset()) {
|
||||||
@@ -415,9 +429,9 @@ SYS_Linux_Finalise(void)
|
|||||||
|
|
||||||
#ifdef FEAT_PRIVDROP
|
#ifdef FEAT_PRIVDROP
|
||||||
void
|
void
|
||||||
SYS_Linux_DropRoot(uid_t uid, gid_t gid)
|
SYS_Linux_DropRoot(uid_t uid, gid_t gid, int clock_control)
|
||||||
{
|
{
|
||||||
const char *cap_text;
|
char cap_text[256];
|
||||||
cap_t cap;
|
cap_t cap;
|
||||||
|
|
||||||
if (prctl(PR_SET_KEEPCAPS, 1)) {
|
if (prctl(PR_SET_KEEPCAPS, 1)) {
|
||||||
@@ -426,9 +440,12 @@ SYS_Linux_DropRoot(uid_t uid, gid_t gid)
|
|||||||
|
|
||||||
UTI_DropRoot(uid, gid);
|
UTI_DropRoot(uid, gid);
|
||||||
|
|
||||||
/* Keep CAP_NET_BIND_SERVICE only if NTP port can be opened */
|
/* Keep CAP_NET_BIND_SERVICE only if a server NTP port can be opened
|
||||||
cap_text = CNF_GetNTPPort() ?
|
and keep CAP_SYS_TIME only if the clock control is enabled */
|
||||||
"cap_net_bind_service,cap_sys_time=ep" : "cap_sys_time=ep";
|
if (snprintf(cap_text, sizeof (cap_text), "%s %s",
|
||||||
|
CNF_GetNTPPort() ? "cap_net_bind_service=ep" : "",
|
||||||
|
clock_control ? "cap_sys_time=ep" : "") >= sizeof (cap_text))
|
||||||
|
assert(0);
|
||||||
|
|
||||||
if ((cap = cap_from_text(cap_text)) == NULL) {
|
if ((cap = cap_from_text(cap_text)) == NULL) {
|
||||||
LOG_FATAL("cap_from_text() failed");
|
LOG_FATAL("cap_from_text() failed");
|
||||||
@@ -517,7 +534,10 @@ SYS_Linux_EnableSystemCallFilter(int level)
|
|||||||
const static unsigned long ioctls[] = {
|
const static unsigned long ioctls[] = {
|
||||||
FIONREAD, TCGETS,
|
FIONREAD, TCGETS,
|
||||||
#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
|
#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
|
||||||
PTP_EXTTS_REQUEST, PTP_PIN_SETFUNC, PTP_SYS_OFFSET,
|
PTP_EXTTS_REQUEST, PTP_SYS_OFFSET,
|
||||||
|
#ifdef PTP_PIN_SETFUNC
|
||||||
|
PTP_PIN_SETFUNC,
|
||||||
|
#endif
|
||||||
#ifdef PTP_SYS_OFFSET_PRECISE
|
#ifdef PTP_SYS_OFFSET_PRECISE
|
||||||
PTP_SYS_OFFSET_PRECISE,
|
PTP_SYS_OFFSET_PRECISE,
|
||||||
#endif
|
#endif
|
||||||
@@ -822,8 +842,9 @@ int
|
|||||||
SYS_Linux_SetPHCExtTimestamping(int fd, int pin, int channel,
|
SYS_Linux_SetPHCExtTimestamping(int fd, int pin, int channel,
|
||||||
int rising, int falling, int enable)
|
int rising, int falling, int enable)
|
||||||
{
|
{
|
||||||
struct ptp_pin_desc pin_desc;
|
|
||||||
struct ptp_extts_request extts_req;
|
struct ptp_extts_request extts_req;
|
||||||
|
#ifdef PTP_PIN_SETFUNC
|
||||||
|
struct ptp_pin_desc pin_desc;
|
||||||
|
|
||||||
memset(&pin_desc, 0, sizeof (pin_desc));
|
memset(&pin_desc, 0, sizeof (pin_desc));
|
||||||
pin_desc.index = pin;
|
pin_desc.index = pin;
|
||||||
@@ -834,6 +855,10 @@ SYS_Linux_SetPHCExtTimestamping(int fd, int pin, int channel,
|
|||||||
DEBUG_LOG("ioctl(%s) failed : %s", "PTP_PIN_SETFUNC", strerror(errno));
|
DEBUG_LOG("ioctl(%s) failed : %s", "PTP_PIN_SETFUNC", strerror(errno));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
DEBUG_LOG("Missing PTP_PIN_SETFUNC");
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
memset(&extts_req, 0, sizeof (extts_req));
|
memset(&extts_req, 0, sizeof (extts_req));
|
||||||
extts_req.index = channel;
|
extts_req.index = channel;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ extern void SYS_Linux_Initialise(void);
|
|||||||
|
|
||||||
extern void SYS_Linux_Finalise(void);
|
extern void SYS_Linux_Finalise(void);
|
||||||
|
|
||||||
extern void SYS_Linux_DropRoot(uid_t uid, gid_t gid);
|
extern void SYS_Linux_DropRoot(uid_t uid, gid_t gid, int clock_control);
|
||||||
|
|
||||||
extern void SYS_Linux_EnableSystemCallFilter(int level);
|
extern void SYS_Linux_EnableSystemCallFilter(int level);
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) Richard P. Curnow 1997-2001
|
* Copyright (C) Richard P. Curnow 1997-2001
|
||||||
* Copyright (C) J. Hannken-Illjes 2001
|
* Copyright (C) J. Hannken-Illjes 2001
|
||||||
* Copyright (C) Bryan Christianson 2015
|
* Copyright (C) Bryan Christianson 2015, 2017
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of version 2 of the GNU General Public License as
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
|
|||||||
@@ -84,9 +84,18 @@ get_offset_correction(struct timespec *raw,
|
|||||||
{
|
{
|
||||||
struct timeval remadj;
|
struct timeval remadj;
|
||||||
double adjustment_remaining;
|
double adjustment_remaining;
|
||||||
|
#ifdef MACOSX
|
||||||
|
struct timeval tv = {0, 0};
|
||||||
|
|
||||||
|
if (PRV_AdjustTime(&tv, &remadj) < 0)
|
||||||
|
LOG_FATAL("adjtime() failed");
|
||||||
|
|
||||||
|
if (PRV_AdjustTime(&remadj, NULL) < 0)
|
||||||
|
LOG_FATAL("adjtime() failed");
|
||||||
|
#else
|
||||||
if (PRV_AdjustTime(NULL, &remadj) < 0)
|
if (PRV_AdjustTime(NULL, &remadj) < 0)
|
||||||
LOG_FATAL("adjtime() failed");
|
LOG_FATAL("adjtime() failed");
|
||||||
|
#endif
|
||||||
|
|
||||||
adjustment_remaining = UTI_TimevalToDouble(&remadj);
|
adjustment_remaining = UTI_TimevalToDouble(&remadj);
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) Richard P. Curnow 1997-2003
|
* Copyright (C) Richard P. Curnow 1997-2003
|
||||||
* Copyright (C) Miroslav Lichvar 2009-2012, 2014-2015
|
* Copyright (C) Miroslav Lichvar 2009-2012, 2014-2015, 2017
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of version 2 of the GNU General Public License as
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
|
|||||||
@@ -6,8 +6,9 @@ for opts in \
|
|||||||
"--host-system=Linux" \
|
"--host-system=Linux" \
|
||||||
"--host-system=NetBSD" \
|
"--host-system=NetBSD" \
|
||||||
"--host-system=FreeBSD" \
|
"--host-system=FreeBSD" \
|
||||||
"--without-nss" \
|
"--without-nettle" \
|
||||||
"--without-tomcrypt --without-nss"
|
"--without-nettle --without-nss" \
|
||||||
|
"--without-nettle --without-nss --without-tomcrypt"
|
||||||
do
|
do
|
||||||
./configure $opts
|
./configure $opts
|
||||||
scan-build make "$@" || exit 1
|
scan-build make "$@" || exit 1
|
||||||
|
|||||||
@@ -8,11 +8,20 @@ limit=1000
|
|||||||
refclock_jitter=$jitter
|
refclock_jitter=$jitter
|
||||||
min_sync_time=45
|
min_sync_time=45
|
||||||
max_sync_time=70
|
max_sync_time=70
|
||||||
client_conf="refclock SHM 0"
|
chronyc_start=70
|
||||||
|
client_conf="refclock SHM 0 stratum 3 delay 1e-3 refid GPS"
|
||||||
|
chronyc_conf="tracking"
|
||||||
|
|
||||||
run_test || test_fail
|
run_test || test_fail
|
||||||
check_chronyd_exit || test_fail
|
check_chronyd_exit || test_fail
|
||||||
check_source_selection || test_fail
|
check_source_selection || test_fail
|
||||||
check_sync || test_fail
|
check_sync || test_fail
|
||||||
|
check_chronyc_output "^Reference ID.*47505300 \(GPS\)
|
||||||
|
Stratum.*: 4
|
||||||
|
.*
|
||||||
|
Root delay : 0.001000000 seconds
|
||||||
|
.*
|
||||||
|
Update interval : 16\.. seconds
|
||||||
|
.*$" || test_fail
|
||||||
|
|
||||||
test_pass
|
test_pass
|
||||||
|
|||||||
@@ -4,14 +4,30 @@
|
|||||||
|
|
||||||
test_start "chronyc"
|
test_start "chronyc"
|
||||||
|
|
||||||
chronyc_conf="tracking
|
refclock_jitter=$jitter
|
||||||
|
client_conf="
|
||||||
|
refclock SHM 0 noselect
|
||||||
|
smoothtime 400 0.001 leaponly"
|
||||||
|
|
||||||
|
chronyc_conf="activity
|
||||||
|
tracking
|
||||||
sources
|
sources
|
||||||
sourcestats"
|
sourcestats
|
||||||
|
manual list
|
||||||
|
smoothing
|
||||||
|
waitsync
|
||||||
|
rtcdata"
|
||||||
|
|
||||||
run_test || test_fail
|
run_test || test_fail
|
||||||
check_chronyd_exit || test_fail
|
check_chronyd_exit || test_fail
|
||||||
|
|
||||||
check_chronyc_output "^Reference ID : C0A87B01 \(192\.168\.123\.1\)
|
check_chronyc_output "^200 OK
|
||||||
|
1 sources online
|
||||||
|
0 sources offline
|
||||||
|
0 sources doing burst \(return to online\)
|
||||||
|
0 sources doing burst \(return to offline\)
|
||||||
|
0 sources with unknown address
|
||||||
|
Reference ID : C0A87B01 \(192\.168\.123\.1\)
|
||||||
Stratum : 2
|
Stratum : 2
|
||||||
Ref time \(UTC\) : Fri Jan 01 00:1.:.. 2010
|
Ref time \(UTC\) : Fri Jan 01 00:1.:.. 2010
|
||||||
System time : 0\.0000..... seconds (slow|fast) of NTP time
|
System time : 0\.0000..... seconds (slow|fast) of NTP time
|
||||||
@@ -24,14 +40,27 @@ Root delay : 0\.000...... seconds
|
|||||||
Root dispersion : 0\.000...... seconds
|
Root dispersion : 0\.000...... seconds
|
||||||
Update interval : [0-9]+\.. seconds
|
Update interval : [0-9]+\.. seconds
|
||||||
Leap status : Normal
|
Leap status : Normal
|
||||||
210 Number of sources = 1
|
210 Number of sources = 2
|
||||||
MS Name/IP address Stratum Poll Reach LastRx Last sample
|
MS Name/IP address Stratum Poll Reach LastRx Last sample
|
||||||
===============================================================================
|
===============================================================================
|
||||||
|
#\? SHM0 0 4 377 [0-9]+ [0-9 +-]+[un]s\[[0-9 +-]+[un]s\] \+/-[ 0-9]+[un]s
|
||||||
\^\* 192\.168\.123\.1 1 [67] 377 [0-9]+ [0-9 +-]+[un]s\[[0-9 +-]+[un]s\] \+/-[ 0-9]+[un]s
|
\^\* 192\.168\.123\.1 1 [67] 377 [0-9]+ [0-9 +-]+[un]s\[[0-9 +-]+[un]s\] \+/-[ 0-9]+[un]s
|
||||||
210 Number of sources = 1
|
210 Number of sources = 2
|
||||||
Name/IP Address NP NR Span Frequency Freq Skew Offset Std Dev
|
Name/IP Address NP NR Span Frequency Freq Skew Offset Std Dev
|
||||||
==============================================================================
|
==============================================================================
|
||||||
192\.168\.123\.1 [0-9 ]+ [0-9 ]+ [0-9 ]+ [ +-][01]\.... [0-9 ]+\.... [0-9 +-]+[un]s [0-9 ]+[un]s$" \
|
SHM0 [0-9 ]+ [0-9 ]+ [0-9 ]+ [ +-][01]\.... [0-9 ]+\.... [0-9 +-]+[un]s [0-9 ]+[un]s
|
||||||
|
192\.168\.123\.1 [0-9 ]+ [0-9 ]+ [0-9 ]+ [ +-][01]\.... [0-9 ]+\.... [0-9 +-]+[un]s [0-9 ]+[un]s
|
||||||
|
210 n_samples = 0
|
||||||
|
# Date Time\(UTC\) Slewed Original Residual
|
||||||
|
=======================================================
|
||||||
|
Active : Yes \(leap second only\)
|
||||||
|
Offset : \+0\.000000000 seconds
|
||||||
|
Frequency : \+0\.000000 ppm
|
||||||
|
Wander : \+0\.000000 ppm per second
|
||||||
|
Last update : [0-9]+\.. seconds ago
|
||||||
|
Remaining time : 0\.0 seconds
|
||||||
|
try: 1, refid: C0A87B01, correction: 0\.000......, skew: .\....
|
||||||
|
513 RTC driver not running$" \
|
||||||
|| test_fail
|
|| test_fail
|
||||||
|
|
||||||
test_pass
|
test_pass
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ check_source_selection || test_fail
|
|||||||
check_packet_interval || test_fail
|
check_packet_interval || test_fail
|
||||||
check_sync || test_fail
|
check_sync || test_fail
|
||||||
|
|
||||||
for client_server_options in "maxpoll 6 maxdelay 2e-5" "maxpoll 6 maxdelayratio 1.001"; do
|
for client_server_options in "maxpoll 6 maxdelay 2e-5"; do
|
||||||
run_test || test_fail
|
run_test || test_fail
|
||||||
check_chronyd_exit || test_fail
|
check_chronyd_exit || test_fail
|
||||||
check_packet_interval || test_fail
|
check_packet_interval || test_fail
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ test_start "smoothtime option"
|
|||||||
|
|
||||||
server_strata=2
|
server_strata=2
|
||||||
server_conf="smoothtime 400 0.001"
|
server_conf="smoothtime 400 0.001"
|
||||||
min_sync_time=250
|
server_server_options="minpoll 8"
|
||||||
max_sync_time=1000
|
min_sync_time=600
|
||||||
|
max_sync_time=800
|
||||||
|
|
||||||
run_test || test_fail
|
run_test || test_fail
|
||||||
check_chronyd_exit || test_fail
|
check_chronyd_exit || test_fail
|
||||||
@@ -22,6 +23,7 @@ server_conf="refclock SHM 0 dpoll 4 poll 6
|
|||||||
smoothtime 2000 1
|
smoothtime 2000 1
|
||||||
maxjitter 10.0"
|
maxjitter 10.0"
|
||||||
time_offset=-10
|
time_offset=-10
|
||||||
|
server_server_options=""
|
||||||
client_server_options="minpoll 6 maxpoll 6"
|
client_server_options="minpoll 6 maxpoll 6"
|
||||||
client_conf="corrtimeratio 100"
|
client_conf="corrtimeratio 100"
|
||||||
min_sync_time=8000
|
min_sync_time=8000
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ max_sync_time=500
|
|||||||
base_delay="(+ 1e-4 (* -1 (equal 0.1 from 2) (equal 0.1 to 1)))"
|
base_delay="(+ 1e-4 (* -1 (equal 0.1 from 2) (equal 0.1 to 1)))"
|
||||||
|
|
||||||
client_lpeer_options="xleave minpoll 5 maxpoll 5"
|
client_lpeer_options="xleave minpoll 5 maxpoll 5"
|
||||||
|
client_rpeer_options="minpoll 5 maxpoll 5"
|
||||||
|
|
||||||
run_test || test_fail
|
run_test || test_fail
|
||||||
check_chronyd_exit || test_fail
|
check_chronyd_exit || test_fail
|
||||||
|
|||||||
27
test/simulation/123-mindelay
Executable file
27
test/simulation/123-mindelay
Executable file
@@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
. ./test.common
|
||||||
|
|
||||||
|
test_start "mindelay and asymmetry options"
|
||||||
|
|
||||||
|
jitter_asymmetry=0.499
|
||||||
|
time_rms_limit=1e-6
|
||||||
|
time_freq_limit=1e-9
|
||||||
|
wander=1e-12
|
||||||
|
|
||||||
|
for client_server_options in "mindelay 2e-4 asymmetry 0.499"; do
|
||||||
|
run_test || test_fail
|
||||||
|
check_chronyd_exit || test_fail
|
||||||
|
check_source_selection || test_fail
|
||||||
|
check_packet_interval || test_fail
|
||||||
|
check_sync || test_fail
|
||||||
|
done
|
||||||
|
|
||||||
|
for client_server_options in "mindelay 1e-4 asymmetry 0.499" "mindelay 2e-4 asymmetry 0.0"; do
|
||||||
|
run_test || test_fail
|
||||||
|
check_chronyd_exit || test_fail
|
||||||
|
check_source_selection || test_fail
|
||||||
|
check_sync && test_fail
|
||||||
|
done
|
||||||
|
|
||||||
|
test_pass
|
||||||
42
test/simulation/124-tai
Executable file
42
test/simulation/124-tai
Executable file
@@ -0,0 +1,42 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
. ./test.common
|
||||||
|
test_start "tai option"
|
||||||
|
|
||||||
|
export CLKNETSIM_START_DATE=$(TZ=UTC date -d 'Dec 31 2008 23:50:00' +'%s')
|
||||||
|
|
||||||
|
leap=$[10 * 60]
|
||||||
|
limit=$[20 * 60]
|
||||||
|
min_sync_time=2
|
||||||
|
max_sync_time=15
|
||||||
|
refclock_jitter=1e-6
|
||||||
|
servers=0
|
||||||
|
|
||||||
|
refclock_offset="(+ -34 (equal 0.1 (max (sum 1.0) $leap) $leap))"
|
||||||
|
client_conf="
|
||||||
|
refclock SHM 0 dpoll 0 poll 0 tai
|
||||||
|
leapsectz right/UTC
|
||||||
|
leapsecmode ignore
|
||||||
|
maxchange 1e-3 1 0"
|
||||||
|
|
||||||
|
run_test || test_fail
|
||||||
|
check_chronyd_exit || test_fail
|
||||||
|
check_source_selection || test_fail
|
||||||
|
check_sync || test_fail
|
||||||
|
|
||||||
|
export CLKNETSIM_START_DATE=$(TZ=UTC date -d 'Jan 01 2009 00:10:00' +'%s')
|
||||||
|
|
||||||
|
time_offset=-1000
|
||||||
|
refclock_offset="(+ -34)"
|
||||||
|
client_conf="
|
||||||
|
refclock SHM 0 dpoll 0 poll 0 tai
|
||||||
|
leapsectz right/UTC
|
||||||
|
makestep 1 1
|
||||||
|
maxchange 1e-3 1 0"
|
||||||
|
|
||||||
|
run_test || test_fail
|
||||||
|
check_chronyd_exit || test_fail
|
||||||
|
check_source_selection || test_fail
|
||||||
|
check_sync || test_fail
|
||||||
|
|
||||||
|
test_pass
|
||||||
29
test/simulation/125-packetloss
Executable file
29
test/simulation/125-packetloss
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
. ./test.common
|
||||||
|
|
||||||
|
test_start "packet loss"
|
||||||
|
|
||||||
|
# Drop 33% of packets by default and 100% on the 3->1 path
|
||||||
|
base_delay=$(cat <<-EOF | tr -d '\n'
|
||||||
|
(+ 1e-4
|
||||||
|
(* -1 (equal 0.33 (uniform) 1.0))
|
||||||
|
(* -1 (equal 0.1 from 3) (equal 0.1 to 1)))
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
clients=2
|
||||||
|
peers=2
|
||||||
|
jitter=1e-5
|
||||||
|
limit=20000
|
||||||
|
max_sync_time=10000
|
||||||
|
|
||||||
|
for options in "maxpoll 8" "maxpoll 8 xleave"; do
|
||||||
|
client_server_options=$options
|
||||||
|
client_peer_options=$options
|
||||||
|
|
||||||
|
run_test || test_fail
|
||||||
|
check_chronyd_exit || test_fail
|
||||||
|
check_sync || test_fail
|
||||||
|
done
|
||||||
|
|
||||||
|
test_pass
|
||||||
29
test/simulation/126-burst
Executable file
29
test/simulation/126-burst
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
. ./test.common
|
||||||
|
|
||||||
|
test_start "burst option"
|
||||||
|
|
||||||
|
# Pass every fourth packet on the 2->1 path
|
||||||
|
base_delay=$(cat <<-EOF | tr -d '\n'
|
||||||
|
(+ 1e-4
|
||||||
|
(* -1
|
||||||
|
(equal 0.1 from 2)
|
||||||
|
(equal 0.1 to 1)
|
||||||
|
(equal 0.1 (min (% (sum 1) 4) 1) 1)))
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
|
||||||
|
client_server_options="burst polltarget 1"
|
||||||
|
min_sync_time=700
|
||||||
|
max_sync_time=730
|
||||||
|
client_max_min_out_interval=2.2
|
||||||
|
client_min_mean_out_interval=150.0
|
||||||
|
|
||||||
|
run_test || test_fail
|
||||||
|
check_chronyd_exit || test_fail
|
||||||
|
check_source_selection || test_fail
|
||||||
|
check_packet_interval || test_fail
|
||||||
|
check_sync || test_fail
|
||||||
|
|
||||||
|
test_pass
|
||||||
@@ -71,6 +71,9 @@ default_freq_rms_limit=1e-5
|
|||||||
default_min_sync_time=120
|
default_min_sync_time=120
|
||||||
default_max_sync_time=210
|
default_max_sync_time=210
|
||||||
|
|
||||||
|
default_client_min_mean_out_interval=0.0
|
||||||
|
default_client_max_min_out_interval=inf
|
||||||
|
|
||||||
# Initialize test settings from their defaults
|
# Initialize test settings from their defaults
|
||||||
for defopt in $(declare | grep '^default_'); do
|
for defopt in $(declare | grep '^default_'); do
|
||||||
defoptname=${defopt%%=*}
|
defoptname=${defopt%%=*}
|
||||||
@@ -251,6 +254,7 @@ check_chronyd_exit() {
|
|||||||
test_message 3 0 "node $i:"
|
test_message 3 0 "node $i:"
|
||||||
|
|
||||||
tail -n 1 tmp/log.$i | grep -q 'chronyd exiting' && \
|
tail -n 1 tmp/log.$i | grep -q 'chronyd exiting' && \
|
||||||
|
! grep -q 'Adjustment.*exceeds.*exiting' tmp/log.$i && \
|
||||||
test_ok || test_bad
|
test_ok || test_bad
|
||||||
[ $? -eq 0 ] || ret=1
|
[ $? -eq 0 ] || ret=1
|
||||||
done
|
done
|
||||||
@@ -302,10 +306,12 @@ check_packet_interval() {
|
|||||||
([ $i -gt $servers ] || \
|
([ $i -gt $servers ] || \
|
||||||
check_stat $mean_in_interval 0.0 $mean_out_interval 10*$jitter) && \
|
check_stat $mean_in_interval 0.0 $mean_out_interval 10*$jitter) && \
|
||||||
([ $i -le $[$servers * $server_strata] ] || \
|
([ $i -le $[$servers * $server_strata] ] || \
|
||||||
check_stat $mean_out_interval 0.0 $mean_in_interval 10*$jitter) && \
|
check_stat $mean_out_interval $client_min_mean_out_interval \
|
||||||
|
$mean_in_interval 10*$jitter) && \
|
||||||
([ $i -le $[$servers * $server_strata] ] || \
|
([ $i -le $[$servers * $server_strata] ] || \
|
||||||
check_stat $min_out_interval \
|
check_stat $min_out_interval \
|
||||||
$([ $servers -gt 1 ] && echo 0.18 || echo 1.8) inf) && \
|
$([ $servers -gt 1 ] && echo 0.18 || echo 1.8) \
|
||||||
|
$client_max_min_out_interval) && \
|
||||||
test_ok || test_bad
|
test_ok || test_bad
|
||||||
|
|
||||||
[ $? -eq 0 ] || ret=1
|
[ $? -eq 0 ] || ret=1
|
||||||
|
|||||||
123
test/unit/hash.c
Normal file
123
test/unit/hash.c
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
**********************************************************************
|
||||||
|
* Copyright (C) Miroslav Lichvar 2018
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <sysincl.h>
|
||||||
|
#include <hash.h>
|
||||||
|
#include <logging.h>
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
struct hash_test {
|
||||||
|
const char *name;
|
||||||
|
const unsigned char out[MAX_HASH_LENGTH];
|
||||||
|
unsigned int length;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
test_unit(void)
|
||||||
|
{
|
||||||
|
unsigned char data1[] = "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
unsigned char data2[] = "12345678910";
|
||||||
|
unsigned char out[MAX_HASH_LENGTH];
|
||||||
|
struct hash_test tests[] = {
|
||||||
|
{ "MD5", "\xfc\x24\x97\x1b\x52\x66\xdc\x46\xef\xe0\xe8\x08\x46\x89\xb6\x88", 16 },
|
||||||
|
{ "SHA1", "\xd8\x85\xb3\x86\xce\xea\x93\xeb\x92\xcd\x7b\x94\xb9\x8d\xc2\x8e"
|
||||||
|
"\x3e\x31\x13\xdd", 20},
|
||||||
|
{ "SHA256", "\x0e\x35\x14\xe7\x15\x7a\x1d\xdd\xea\x11\x78\xd3\x41\xf6\xb9\x3e"
|
||||||
|
"\xa0\x42\x96\x73\x3c\x54\x74\x0b\xfa\x6b\x9e\x29\x59\xad\x69\xd3", 32 },
|
||||||
|
{ "SHA384", "\x2c\xeb\xbd\x4d\x95\xed\xad\x03\xed\x80\xc4\xf3\xa6\x10\x21\xde"
|
||||||
|
"\x40\x69\x54\xed\x42\x70\xb8\x95\xb0\x6f\x01\x1d\x04\xdf\x57\xbc"
|
||||||
|
"\x1d\xb5\x85\xbf\x4f\x03\x88\xd5\x83\x93\xbc\x81\x90\xb0\xa9\x9b", 48 },
|
||||||
|
{ "SHA512", "\x20\xba\xec\xcb\x68\x98\x33\x5b\x70\x26\x63\x13\xe2\xf7\x0e\x67"
|
||||||
|
"\x08\xf3\x77\x4f\xbd\xeb\xc4\xa8\xc5\x94\xe2\x39\x40\x7e\xed\x0b"
|
||||||
|
"\x69\x0e\x18\xa5\xa2\x03\x73\xe7\x1d\x20\x7d\x3f\xc8\x70\x2d\x64"
|
||||||
|
"\x9e\x89\x6d\x20\x6a\x4a\x5a\x46\xe7\x4f\x2c\xf9\x0f\x0a\x54\xdc", 64 },
|
||||||
|
{ "SHA3-224", "\x3b\xa2\x22\x28\xdd\x26\x18\xec\x3b\xb9\x25\x39\x5e\xbd\x94\x25"
|
||||||
|
"\xd4\x20\x8a\x76\x76\xc0\x3c\x5d\x9e\x0a\x06\x46", 28},
|
||||||
|
{ "SHA3-256", "\x26\xd1\x19\xb2\xc1\x64\xc8\xb8\x10\xd8\xa8\x1c\xb6\xa4\x0d\x29"
|
||||||
|
"\x09\xc9\x8e\x2e\x2d\xde\x7a\x74\x8c\x43\x70\xb8\xaa\x0f\x09\x17", 32 },
|
||||||
|
{ "SHA3-384", "\x6a\x64\xb9\x89\x08\x29\xd0\xa7\x4b\x84\xba\xa6\x65\xf5\xe7\x54"
|
||||||
|
"\xe2\x18\x12\xc3\x63\x34\xc6\xba\x26\xf5\x6e\x99\xe2\x54\xcc\x9d"
|
||||||
|
"\x01\x10\x9d\xee\x35\x38\x04\x83\xe5\x71\x70\xd8\xc8\x99\x96\xd8", 48 },
|
||||||
|
{ "SHA3-512", "\xa8\xe3\x2b\x65\x1f\x87\x90\x73\x19\xc8\xa0\x3f\xe3\x85\x60\x3c"
|
||||||
|
"\x39\xfc\xcb\xc1\x29\xe1\x23\x7d\x8b\x56\x54\xe3\x08\x9d\xf9\x74"
|
||||||
|
"\x78\x69\x2e\x3c\x7e\x51\x1e\x9d\xab\x09\xbe\xe7\x6b\x1a\xa1\x22"
|
||||||
|
"\x93\xb1\x2b\x82\x9d\x1e\xcf\xa8\x99\xc5\xec\x7b\x1d\x89\x07\x2b", 64 },
|
||||||
|
{ "RMD128", "\x6f\xd7\x1f\x37\x47\x0f\xbd\x42\x57\xc8\xbb\xee\xba\x65\xf9\x35", 16 },
|
||||||
|
{ "RMD160", "\x7a\x88\xec\xc7\x09\xc5\x65\x34\x11\x24\xe3\xf9\xf7\xa5\xbf\xc6"
|
||||||
|
"\x01\xe2\xc9\x32", 20},
|
||||||
|
{ "RMD256", "\x59\xdf\xd4\xcb\xc9\xbe\x7c\x27\x08\xa7\x23\xf7\xb3\x0c\xf0\x0d"
|
||||||
|
"\xa0\xcf\x5b\x18\x16\x51\x56\x6d\xda\x7b\x87\x24\x9d\x83\x35\xe1", 32 },
|
||||||
|
{ "RMD320", "\x68\x98\x10\xf4\xb6\x79\xb6\x15\xf1\x48\x2d\x73\xd0\x23\x84\x01"
|
||||||
|
"\xbf\xaa\x67\xcf\x1e\x35\x5c\xbf\xe9\xb8\xaf\xe1\xee\x0d\xf0\x6b"
|
||||||
|
"\xe2\x3a\x9a\x3a\xa7\x56\xad\x70", 40},
|
||||||
|
{ "TIGER", "\x1c\xcd\x68\x74\xca\xd6\xd5\x17\xba\x3e\x82\xaf\xbd\x70\xdc\x66"
|
||||||
|
"\x99\xaa\xae\x16\x72\x59\xd1\x64", 24},
|
||||||
|
{ "WHIRLPOOL", "\xe3\xcd\xe6\xbf\xe1\x8c\xe4\x4d\xc8\xb4\xa5\x7c\x36\x8d\xc8\x8a"
|
||||||
|
"\x8b\xad\x52\x24\xc0\x4e\x99\x5b\x7e\x86\x94\x2d\x10\x56\x12\xa3"
|
||||||
|
"\x29\x2a\x65\x0f\x9e\x07\xbc\x15\x21\x14\xe6\x07\xfc\xe6\xb9\x2f"
|
||||||
|
"\x13\xe2\x57\xe9\x0a\xb0\xd2\xf4\xa3\x20\x36\x9c\x88\x92\x8e\xc9", 64 },
|
||||||
|
{ "", "", 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned int length;
|
||||||
|
int i, j, hash_id;
|
||||||
|
|
||||||
|
for (i = 0; tests[i].name[0] != '\0'; i++) {
|
||||||
|
hash_id = HSH_GetHashId(tests[i].name);
|
||||||
|
if (hash_id < 0) {
|
||||||
|
TEST_CHECK(strcmp(tests[i].name, "MD5"));
|
||||||
|
#ifdef FEAT_SECHASH
|
||||||
|
TEST_CHECK(strcmp(tests[i].name, "SHA1"));
|
||||||
|
TEST_CHECK(strcmp(tests[i].name, "SHA256"));
|
||||||
|
TEST_CHECK(strcmp(tests[i].name, "SHA384"));
|
||||||
|
TEST_CHECK(strcmp(tests[i].name, "SHA512"));
|
||||||
|
#endif
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_LOG("testing %s", tests[i].name);
|
||||||
|
|
||||||
|
for (j = 0; j <= sizeof (out); j++) {
|
||||||
|
TEST_CHECK(HSH_GetHashId(tests[i].name) == hash_id);
|
||||||
|
TEST_CHECK(HSH_GetHashId("nosuchhash") < 0);
|
||||||
|
|
||||||
|
memset(out, 0, sizeof (out));
|
||||||
|
length = HSH_Hash(hash_id, data1, sizeof (data1) - 1, data2, sizeof (data2) - 1,
|
||||||
|
out, j);
|
||||||
|
|
||||||
|
if (j >= tests[i].length)
|
||||||
|
TEST_CHECK(length == tests[i].length);
|
||||||
|
else
|
||||||
|
TEST_CHECK(length == 0 || length == j);
|
||||||
|
|
||||||
|
TEST_CHECK(!memcmp(out, tests[i].out, length));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 0; j < 10000; j++) {
|
||||||
|
length = HSH_Hash(hash_id, data1, random() % sizeof (data1),
|
||||||
|
random() % 2 ? data2 : NULL, random() % sizeof (data2),
|
||||||
|
out, sizeof (out));
|
||||||
|
TEST_CHECK(length == tests[i].length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HSH_Finalise();
|
||||||
|
}
|
||||||
@@ -26,14 +26,14 @@ test_unit(void)
|
|||||||
{
|
{
|
||||||
struct timespec start_hw_ts, start_local_ts, hw_ts, local_ts, ts;
|
struct timespec start_hw_ts, start_local_ts, hw_ts, local_ts, ts;
|
||||||
HCL_Instance clock;
|
HCL_Instance clock;
|
||||||
double freq, jitter, interval, d;
|
double freq, jitter, interval, dj, sum;
|
||||||
int i, j;
|
int i, j, count;
|
||||||
|
|
||||||
LCL_Initialise();
|
LCL_Initialise();
|
||||||
|
|
||||||
clock = HCL_CreateInstance(1.0);
|
clock = HCL_CreateInstance(1.0);
|
||||||
|
|
||||||
for (i = 0; i < 2000; i++) {
|
for (i = 0, count = 0, sum = 0.0; i < 2000; i++) {
|
||||||
UTI_ZeroTimespec(&start_hw_ts);
|
UTI_ZeroTimespec(&start_hw_ts);
|
||||||
UTI_ZeroTimespec(&start_local_ts);
|
UTI_ZeroTimespec(&start_local_ts);
|
||||||
UTI_AddDoubleToTimespec(&start_hw_ts, TST_GetRandomDouble(0.0, 1e9), &start_hw_ts);
|
UTI_AddDoubleToTimespec(&start_hw_ts, TST_GetRandomDouble(0.0, 1e9), &start_hw_ts);
|
||||||
@@ -49,17 +49,23 @@ test_unit(void)
|
|||||||
clock->valid_coefs = 0;
|
clock->valid_coefs = 0;
|
||||||
|
|
||||||
for (j = 0; j < 100; j++) {
|
for (j = 0; j < 100; j++) {
|
||||||
UTI_AddDoubleToTimespec(&start_hw_ts, j * interval * freq + TST_GetRandomDouble(-jitter, jitter), &hw_ts);
|
UTI_AddDoubleToTimespec(&start_hw_ts, j * interval * freq, &hw_ts);
|
||||||
UTI_AddDoubleToTimespec(&start_local_ts, j * interval, &local_ts);
|
UTI_AddDoubleToTimespec(&start_local_ts, j * interval, &local_ts);
|
||||||
if (HCL_CookTime(clock, &hw_ts, &ts, NULL)) {
|
if (HCL_CookTime(clock, &hw_ts, &ts, NULL)) {
|
||||||
d = UTI_DiffTimespecsToDouble(&ts, &local_ts);
|
dj = fabs(UTI_DiffTimespecsToDouble(&ts, &local_ts) / jitter);
|
||||||
TEST_CHECK(fabs(d) <= 5.0 * jitter);
|
DEBUG_LOG("delta/jitter %f", dj);
|
||||||
|
if (clock->n_samples >= 8)
|
||||||
|
sum += dj, count++;
|
||||||
|
TEST_CHECK(clock->n_samples < 4 || dj <= 4.0);
|
||||||
|
TEST_CHECK(clock->n_samples < 8 || dj <= 3.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UTI_AddDoubleToTimespec(&start_hw_ts, j * interval * freq + TST_GetRandomDouble(-jitter, jitter), &hw_ts);
|
||||||
|
|
||||||
if (HCL_NeedsNewSample(clock, &local_ts))
|
if (HCL_NeedsNewSample(clock, &local_ts))
|
||||||
HCL_AccumulateSample(clock, &hw_ts, &local_ts, 2.0 * jitter);
|
HCL_AccumulateSample(clock, &hw_ts, &local_ts, 2.0 * jitter);
|
||||||
|
|
||||||
TEST_CHECK(j < 20 || clock->valid_coefs);
|
TEST_CHECK(clock->valid_coefs || clock->n_samples < 2);
|
||||||
|
|
||||||
if (!clock->valid_coefs)
|
if (!clock->valid_coefs)
|
||||||
continue;
|
continue;
|
||||||
@@ -68,6 +74,8 @@ test_unit(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CHECK(sum / count < 0.4);
|
||||||
|
|
||||||
HCL_DestroyInstance(clock);
|
HCL_DestroyInstance(clock);
|
||||||
|
|
||||||
LCL_Finalise();
|
LCL_Finalise();
|
||||||
|
|||||||
@@ -134,8 +134,8 @@ test_unit(void)
|
|||||||
UTI_GetRandomBytes(&key, sizeof (key));
|
UTI_GetRandomBytes(&key, sizeof (key));
|
||||||
if (KEY_KeyKnown(key))
|
if (KEY_KeyKnown(key))
|
||||||
continue;
|
continue;
|
||||||
TEST_CHECK(!KEY_GenerateAuth(j, data, data_len, auth, sizeof (auth)));
|
TEST_CHECK(!KEY_GenerateAuth(key, data, data_len, auth, sizeof (auth)));
|
||||||
TEST_CHECK(!KEY_CheckAuth(j, data, data_len, auth, auth_len, auth_len));
|
TEST_CHECK(!KEY_CheckAuth(key, data, data_len, auth, auth_len, auth_len));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ static int req_length, res_length;
|
|||||||
#define NIO_CloseServerSocket(fd) assert(fd == 100)
|
#define NIO_CloseServerSocket(fd) assert(fd == 100)
|
||||||
#define NIO_OpenClientSocket(addr) ((addr)->ip_addr.family != IPADDR_UNSPEC ? 101 : 0)
|
#define NIO_OpenClientSocket(addr) ((addr)->ip_addr.family != IPADDR_UNSPEC ? 101 : 0)
|
||||||
#define NIO_CloseClientSocket(fd) assert(fd == 101)
|
#define NIO_CloseClientSocket(fd) assert(fd == 101)
|
||||||
|
#define NIO_IsServerSocket(fd) (fd == 100)
|
||||||
#define NIO_SendPacket(msg, to, from, len, process_tx) (memcpy(&req_buffer, msg, len), req_length = len, 1)
|
#define NIO_SendPacket(msg, to, from, len, process_tx) (memcpy(&req_buffer, msg, len), req_length = len, 1)
|
||||||
#define SCH_AddTimeoutByDelay(delay, handler, arg) (1 ? 102 : (handler(arg), 1))
|
#define SCH_AddTimeoutByDelay(delay, handler, arg) (1 ? 102 : (handler(arg), 1))
|
||||||
#define SCH_AddTimeoutInClass(delay, separation, randomness, class, handler, arg) \
|
#define SCH_AddTimeoutInClass(delay, separation, randomness, class, handler, arg) \
|
||||||
@@ -43,6 +44,7 @@ static int req_length, res_length;
|
|||||||
#define SCH_RemoveTimeout(id) assert(!id || id == 102)
|
#define SCH_RemoveTimeout(id) assert(!id || id == 102)
|
||||||
#define LCL_ReadRawTime(ts) (*ts = current_time)
|
#define LCL_ReadRawTime(ts) (*ts = current_time)
|
||||||
#define LCL_ReadCookedTime(ts, err) do {double *p = err; *ts = current_time; if (p) *p = 0.0;} while (0)
|
#define LCL_ReadCookedTime(ts, err) do {double *p = err; *ts = current_time; if (p) *p = 0.0;} while (0)
|
||||||
|
#define LCL_GetSysPrecisionAsLog() (random() % 10 - 30)
|
||||||
#define SRC_UpdateReachability(inst, reach)
|
#define SRC_UpdateReachability(inst, reach)
|
||||||
#define SRC_ResetReachability(inst)
|
#define SRC_ResetReachability(inst)
|
||||||
|
|
||||||
@@ -55,8 +57,6 @@ add_timeout_in_class(double min_delay, double separation, double randomness,
|
|||||||
|
|
||||||
#include <ntp_core.c>
|
#include <ntp_core.c>
|
||||||
|
|
||||||
static NCR_Instance inst;
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
advance_time(double x)
|
advance_time(double x)
|
||||||
{
|
{
|
||||||
@@ -64,7 +64,7 @@ advance_time(double x)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
send_request(void)
|
send_request(NCR_Instance inst)
|
||||||
{
|
{
|
||||||
NTP_Local_Address local_addr;
|
NTP_Local_Address local_addr;
|
||||||
NTP_Local_Timestamp local_ts;
|
NTP_Local_Timestamp local_ts;
|
||||||
@@ -74,19 +74,48 @@ send_request(void)
|
|||||||
|
|
||||||
transmit_timeout(inst);
|
transmit_timeout(inst);
|
||||||
TEST_CHECK(!inst->valid_rx);
|
TEST_CHECK(!inst->valid_rx);
|
||||||
TEST_CHECK(!inst->updated_timestamps);
|
|
||||||
TEST_CHECK(prev_tx_count + 1 == inst->report.total_tx_count);
|
TEST_CHECK(prev_tx_count + 1 == inst->report.total_tx_count);
|
||||||
|
|
||||||
advance_time(1e-4);
|
advance_time(1e-5);
|
||||||
|
|
||||||
|
if (random() % 2) {
|
||||||
|
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||||
|
local_addr.if_index = INVALID_IF_INDEX;
|
||||||
|
local_addr.sock_fd = 101;
|
||||||
|
local_ts.ts = current_time;
|
||||||
|
local_ts.err = 0.0;
|
||||||
|
local_ts.source = NTP_TS_KERNEL;
|
||||||
|
|
||||||
|
NCR_ProcessTxKnown(inst, &local_addr, &local_ts, &req_buffer.ntp_pkt, req_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
process_request(NTP_Remote_Address *remote_addr)
|
||||||
|
{
|
||||||
|
NTP_Local_Address local_addr;
|
||||||
|
NTP_Local_Timestamp local_ts;
|
||||||
|
|
||||||
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||||
local_addr.if_index = INVALID_IF_INDEX;
|
local_addr.if_index = INVALID_IF_INDEX;
|
||||||
local_addr.sock_fd = 101;
|
local_addr.sock_fd = 100;
|
||||||
local_ts.ts = current_time;
|
local_ts.ts = current_time;
|
||||||
local_ts.err = 0.0;
|
local_ts.err = 0.0;
|
||||||
local_ts.source = NTP_TS_DAEMON;
|
local_ts.source = NTP_TS_KERNEL;
|
||||||
|
|
||||||
NCR_ProcessTxKnown(inst, &local_addr, &local_ts, &req_buffer.ntp_pkt, req_length);
|
res_length = 0;
|
||||||
|
NCR_ProcessRxUnknown(remote_addr, &local_addr, &local_ts,
|
||||||
|
&req_buffer.ntp_pkt, req_length);
|
||||||
|
res_length = req_length;
|
||||||
|
res_buffer = req_buffer;
|
||||||
|
|
||||||
|
advance_time(1e-5);
|
||||||
|
|
||||||
|
if (random() % 2) {
|
||||||
|
local_ts.ts = current_time;
|
||||||
|
NCR_ProcessTxUnknown(remote_addr, &local_addr, &local_ts,
|
||||||
|
&res_buffer.ntp_pkt, res_length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -165,30 +194,36 @@ send_response(int interleaved, int authenticated, int allow_update, int valid_ts
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
process_response(int valid, int updated)
|
process_response(NCR_Instance inst, int good, int valid, int updated_sync, int updated_init)
|
||||||
{
|
{
|
||||||
NTP_Local_Address local_addr;
|
NTP_Local_Address local_addr;
|
||||||
NTP_Local_Timestamp local_ts;
|
NTP_Local_Timestamp local_ts;
|
||||||
NTP_Packet *res;
|
NTP_Packet *res;
|
||||||
uint32_t prev_rx_count, prev_valid_count;
|
uint32_t prev_rx_count, prev_valid_count;
|
||||||
struct timespec prev_rx_ts;
|
struct timespec prev_rx_ts, prev_init_rx_ts;
|
||||||
int prev_open_socket;
|
int prev_open_socket, ret;
|
||||||
|
|
||||||
res = &res_buffer.ntp_pkt;
|
res = &res_buffer.ntp_pkt;
|
||||||
|
|
||||||
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||||
local_addr.if_index = INVALID_IF_INDEX;
|
local_addr.if_index = INVALID_IF_INDEX;
|
||||||
local_addr.sock_fd = NTP_LVM_TO_MODE(res->lvm) == MODE_ACTIVE ? 100 : 101;
|
local_addr.sock_fd = NTP_LVM_TO_MODE(res->lvm) != MODE_SERVER ? 100 : 101;
|
||||||
local_ts.ts = current_time;
|
local_ts.ts = current_time;
|
||||||
local_ts.err = 0.0;
|
local_ts.err = 0.0;
|
||||||
local_ts.source = NTP_TS_DAEMON;
|
local_ts.source = NTP_TS_KERNEL;
|
||||||
|
|
||||||
prev_rx_count = inst->report.total_rx_count;
|
prev_rx_count = inst->report.total_rx_count;
|
||||||
prev_valid_count = inst->report.total_valid_count;
|
prev_valid_count = inst->report.total_valid_count;
|
||||||
prev_rx_ts = inst->local_rx.ts;
|
prev_rx_ts = inst->local_rx.ts;
|
||||||
|
prev_init_rx_ts = inst->init_local_rx.ts;
|
||||||
prev_open_socket = inst->local_addr.sock_fd != INVALID_SOCK_FD;
|
prev_open_socket = inst->local_addr.sock_fd != INVALID_SOCK_FD;
|
||||||
|
|
||||||
NCR_ProcessRxKnown(inst, &local_addr, &local_ts, res, res_length);
|
ret = NCR_ProcessRxKnown(inst, &local_addr, &local_ts, res, res_length);
|
||||||
|
|
||||||
|
if (good > 0)
|
||||||
|
TEST_CHECK(ret);
|
||||||
|
else if (!good)
|
||||||
|
TEST_CHECK(!ret);
|
||||||
|
|
||||||
if (prev_open_socket)
|
if (prev_open_socket)
|
||||||
TEST_CHECK(prev_rx_count + 1 == inst->report.total_rx_count);
|
TEST_CHECK(prev_rx_count + 1 == inst->report.total_rx_count);
|
||||||
@@ -200,23 +235,51 @@ process_response(int valid, int updated)
|
|||||||
else
|
else
|
||||||
TEST_CHECK(prev_valid_count == inst->report.total_valid_count);
|
TEST_CHECK(prev_valid_count == inst->report.total_valid_count);
|
||||||
|
|
||||||
if (updated)
|
if (updated_sync)
|
||||||
TEST_CHECK(UTI_CompareTimespecs(&inst->local_rx.ts, &prev_rx_ts));
|
TEST_CHECK(UTI_CompareTimespecs(&inst->local_rx.ts, &prev_rx_ts));
|
||||||
else
|
else
|
||||||
TEST_CHECK(!UTI_CompareTimespecs(&inst->local_rx.ts, &prev_rx_ts));
|
TEST_CHECK(!UTI_CompareTimespecs(&inst->local_rx.ts, &prev_rx_ts));
|
||||||
|
|
||||||
|
if (updated_init > 0)
|
||||||
|
TEST_CHECK(UTI_CompareTimespecs(&inst->init_local_rx.ts, &prev_init_rx_ts));
|
||||||
|
else if (!updated_init)
|
||||||
|
TEST_CHECK(!UTI_CompareTimespecs(&inst->init_local_rx.ts, &prev_init_rx_ts));
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
TEST_CHECK(UTI_IsZeroTimespec(&inst->init_local_rx.ts));
|
||||||
|
TEST_CHECK(UTI_IsZeroNtp64(&inst->init_remote_ntp_tx));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
process_replay(NCR_Instance inst, NTP_Receive_Buffer *packet_queue,
|
||||||
|
int queue_length, int updated_init)
|
||||||
|
{
|
||||||
|
do {
|
||||||
|
res_buffer = packet_queue[random() % queue_length];
|
||||||
|
} while (!UTI_CompareNtp64(&res_buffer.ntp_pkt.transmit_ts,
|
||||||
|
&inst->remote_ntp_tx));
|
||||||
|
process_response(inst, 0, 0, 0, updated_init);
|
||||||
|
advance_time(1e-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PACKET_QUEUE_LENGTH 10
|
||||||
|
|
||||||
void
|
void
|
||||||
test_unit(void)
|
test_unit(void)
|
||||||
{
|
{
|
||||||
char source_line[] = "127.0.0.1";
|
char source_line[] = "127.0.0.1 maxdelaydevratio 1e6";
|
||||||
char conf[][100] = {
|
char conf[][100] = {
|
||||||
|
"allow",
|
||||||
"port 0",
|
"port 0",
|
||||||
|
"local",
|
||||||
"keyfile ntp_core.keys"
|
"keyfile ntp_core.keys"
|
||||||
};
|
};
|
||||||
int i, j, interleaved, authenticated, valid, updated, has_updated;
|
int i, j, k, interleaved, authenticated, valid, updated, has_updated;
|
||||||
CPS_NTP_Source source;
|
CPS_NTP_Source source;
|
||||||
NTP_Remote_Address remote_addr;
|
NTP_Remote_Address remote_addr;
|
||||||
|
NCR_Instance inst1, inst2;
|
||||||
|
NTP_Receive_Buffer packet_queue[PACKET_QUEUE_LENGTH];
|
||||||
|
|
||||||
CNF_Initialise(0, 0);
|
CNF_Initialise(0, 0);
|
||||||
for (i = 0; i < sizeof conf / sizeof conf[0]; i++)
|
for (i = 0; i < sizeof conf / sizeof conf[0]; i++)
|
||||||
@@ -231,12 +294,16 @@ test_unit(void)
|
|||||||
REF_Initialise();
|
REF_Initialise();
|
||||||
KEY_Initialise();
|
KEY_Initialise();
|
||||||
|
|
||||||
|
CNF_SetupAccessRestrictions();
|
||||||
|
|
||||||
|
CPS_ParseNTPSourceAdd(source_line, &source);
|
||||||
|
|
||||||
for (i = 0; i < 1000; i++) {
|
for (i = 0; i < 1000; i++) {
|
||||||
CPS_ParseNTPSourceAdd(source_line, &source);
|
|
||||||
if (random() % 2)
|
if (random() % 2)
|
||||||
source.params.interleaved = 1;
|
source.params.interleaved = 1;
|
||||||
if (random() % 2)
|
if (random() % 2)
|
||||||
source.params.authkey = 1;
|
source.params.authkey = 1;
|
||||||
|
source.params.version = random() % 4 + 1;
|
||||||
|
|
||||||
UTI_ZeroTimespec(¤t_time);
|
UTI_ZeroTimespec(¤t_time);
|
||||||
advance_time(TST_GetRandomDouble(1.0, 1e9));
|
advance_time(TST_GetRandomDouble(1.0, 1e9));
|
||||||
@@ -244,47 +311,125 @@ test_unit(void)
|
|||||||
TST_GetRandomAddress(&remote_addr.ip_addr, IPADDR_UNSPEC, -1);
|
TST_GetRandomAddress(&remote_addr.ip_addr, IPADDR_UNSPEC, -1);
|
||||||
remote_addr.port = 123;
|
remote_addr.port = 123;
|
||||||
|
|
||||||
inst = NCR_GetInstance(&remote_addr, random() % 2 ? NTP_SERVER : NTP_PEER, &source.params);
|
inst1 = NCR_GetInstance(&remote_addr, random() % 2 ? NTP_SERVER : NTP_PEER, &source.params);
|
||||||
NCR_StartInstance(inst);
|
NCR_StartInstance(inst1);
|
||||||
has_updated = 0;
|
has_updated = 0;
|
||||||
|
|
||||||
for (j = 0; j < 50; j++) {
|
for (j = 0; j < 50; j++) {
|
||||||
DEBUG_LOG("iteration %d, %d", i, j);
|
DEBUG_LOG("client/peer test iteration %d/%d", i, j);
|
||||||
|
|
||||||
interleaved = random() % 2;
|
interleaved = random() % 2 && (inst1->mode != MODE_CLIENT ||
|
||||||
|
inst1->tx_count < MAX_CLIENT_INTERLEAVED_TX);
|
||||||
authenticated = random() % 2;
|
authenticated = random() % 2;
|
||||||
valid = (!interleaved || (source.params.interleaved && has_updated)) &&
|
valid = (!interleaved || (source.params.interleaved && has_updated)) &&
|
||||||
(!source.params.authkey || authenticated);
|
(!source.params.authkey || authenticated);
|
||||||
updated = (valid || inst->mode == MODE_ACTIVE) &&
|
updated = (valid || inst1->mode == MODE_ACTIVE) &&
|
||||||
(!source.params.authkey || authenticated);
|
(!source.params.authkey || authenticated);
|
||||||
has_updated = has_updated || updated;
|
has_updated = has_updated || updated;
|
||||||
|
if (inst1->mode == MODE_CLIENT)
|
||||||
|
updated = 0;
|
||||||
|
|
||||||
send_request();
|
send_request(inst1);
|
||||||
|
|
||||||
send_response(interleaved, authenticated, 1, 0, 1);
|
send_response(interleaved, authenticated, 1, 0, 1);
|
||||||
process_response(0, inst->mode == MODE_CLIENT ? 0 : updated);
|
DEBUG_LOG("response 1");
|
||||||
|
process_response(inst1, 0, 0, 0, updated);
|
||||||
|
|
||||||
if (source.params.authkey) {
|
if (source.params.authkey) {
|
||||||
send_response(interleaved, authenticated, 1, 1, 0);
|
send_response(interleaved, authenticated, 1, 1, 0);
|
||||||
process_response(0, 0);
|
DEBUG_LOG("response 2");
|
||||||
|
process_response(inst1, 0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
send_response(interleaved, authenticated, 1, 1, 1);
|
send_response(interleaved, authenticated, 1, 1, 1);
|
||||||
process_response(valid, updated);
|
DEBUG_LOG("response 3");
|
||||||
process_response(0, 0);
|
process_response(inst1, -1, valid, valid, updated);
|
||||||
|
DEBUG_LOG("response 4");
|
||||||
|
process_response(inst1, 0, 0, 0, 0);
|
||||||
|
|
||||||
advance_time(-1.0);
|
advance_time(-1.0);
|
||||||
|
|
||||||
send_response(interleaved, authenticated, 1, 1, 1);
|
send_response(interleaved, authenticated, 1, 1, 1);
|
||||||
process_response(0, 0);
|
DEBUG_LOG("response 5");
|
||||||
|
process_response(inst1, 0, 0, 0, updated && valid);
|
||||||
|
|
||||||
advance_time(1.0);
|
advance_time(1.0);
|
||||||
|
|
||||||
send_response(interleaved, authenticated, 1, 1, 1);
|
send_response(interleaved, authenticated, 1, 1, 1);
|
||||||
process_response(0, inst->mode == MODE_CLIENT ? 0 : updated);
|
DEBUG_LOG("response 6");
|
||||||
|
process_response(inst1, 0, 0, valid && updated, updated);
|
||||||
}
|
}
|
||||||
|
|
||||||
NCR_DestroyInstance(inst);
|
NCR_DestroyInstance(inst1);
|
||||||
|
|
||||||
|
inst1 = NCR_GetInstance(&remote_addr, random() % 2 ? NTP_SERVER : NTP_PEER, &source.params);
|
||||||
|
NCR_StartInstance(inst1);
|
||||||
|
|
||||||
|
for (j = 0; j < 20; j++) {
|
||||||
|
DEBUG_LOG("server test iteration %d/%d", i, j);
|
||||||
|
|
||||||
|
send_request(inst1);
|
||||||
|
process_request(&remote_addr);
|
||||||
|
process_response(inst1, 1, 1, 1, 0);
|
||||||
|
advance_time(1 << inst1->local_poll);
|
||||||
|
}
|
||||||
|
|
||||||
|
NCR_DestroyInstance(inst1);
|
||||||
|
|
||||||
|
inst1 = NCR_GetInstance(&remote_addr, NTP_PEER, &source.params);
|
||||||
|
NCR_StartInstance(inst1);
|
||||||
|
inst2 = NCR_GetInstance(&remote_addr, NTP_PEER, &source.params);
|
||||||
|
NCR_StartInstance(inst2);
|
||||||
|
|
||||||
|
res_length = req_length = 0;
|
||||||
|
|
||||||
|
for (j = 0; j < 20; j++) {
|
||||||
|
DEBUG_LOG("peer replay test iteration %d/%d", i, j);
|
||||||
|
|
||||||
|
send_request(inst1);
|
||||||
|
res_buffer = req_buffer;
|
||||||
|
assert(!res_length || res_length == req_length);
|
||||||
|
res_length = req_length;
|
||||||
|
|
||||||
|
TEST_CHECK(inst1->valid_timestamps == (j > 0));
|
||||||
|
|
||||||
|
DEBUG_LOG("response 1->2");
|
||||||
|
process_response(inst2, j > source.params.interleaved, j > 0, j > 0, 1);
|
||||||
|
|
||||||
|
packet_queue[(j * 2) % PACKET_QUEUE_LENGTH] = res_buffer;
|
||||||
|
|
||||||
|
for (k = 0; k < j % 4 + 1; k++) {
|
||||||
|
DEBUG_LOG("replay ?->1 %d", k);
|
||||||
|
process_replay(inst1, packet_queue, MIN(j * 2 + 1, PACKET_QUEUE_LENGTH), k ? -1 : 1);
|
||||||
|
DEBUG_LOG("replay ?->2 %d", k);
|
||||||
|
process_replay(inst2, packet_queue, MIN(j * 2 + 1, PACKET_QUEUE_LENGTH), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
advance_time(1 << (source.params.minpoll - 1));
|
||||||
|
|
||||||
|
send_request(inst2);
|
||||||
|
res_buffer = req_buffer;
|
||||||
|
assert(res_length == req_length);
|
||||||
|
|
||||||
|
TEST_CHECK(inst2->valid_timestamps == (j > 0));
|
||||||
|
|
||||||
|
DEBUG_LOG("response 2->1");
|
||||||
|
process_response(inst1, 1, 1, 1, 1);
|
||||||
|
|
||||||
|
packet_queue[(j * 2 + 1) % PACKET_QUEUE_LENGTH] = res_buffer;
|
||||||
|
|
||||||
|
for (k = 0; k < j % 4 + 1; k++) {
|
||||||
|
DEBUG_LOG("replay ?->1 %d", k);
|
||||||
|
process_replay(inst1, packet_queue, MIN(j * 2 + 2, PACKET_QUEUE_LENGTH), k ? -1 : 1);
|
||||||
|
DEBUG_LOG("replay ?->2 %d", k);
|
||||||
|
process_replay(inst2, packet_queue, MIN(j * 2 + 2, PACKET_QUEUE_LENGTH), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
advance_time(1 << (source.params.minpoll - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
NCR_DestroyInstance(inst1);
|
||||||
|
NCR_DestroyInstance(inst2);
|
||||||
}
|
}
|
||||||
|
|
||||||
KEY_Finalise();
|
KEY_Finalise();
|
||||||
|
|||||||
@@ -53,7 +53,8 @@ test_unit(void)
|
|||||||
|
|
||||||
DEBUG_LOG("added source %d options %d", j, sel_options);
|
DEBUG_LOG("added source %d options %d", j, sel_options);
|
||||||
srcs[j] = SRC_CreateNewInstance(UTI_IPToRefid(&addr), SRC_NTP, sel_options, &addr,
|
srcs[j] = SRC_CreateNewInstance(UTI_IPToRefid(&addr), SRC_NTP, sel_options, &addr,
|
||||||
SRC_DEFAULT_MINSAMPLES, SRC_DEFAULT_MAXSAMPLES);
|
SRC_DEFAULT_MINSAMPLES, SRC_DEFAULT_MAXSAMPLES,
|
||||||
|
0.0, 1.0);
|
||||||
SRC_UpdateReachability(srcs[j], 1);
|
SRC_UpdateReachability(srcs[j], 1);
|
||||||
|
|
||||||
samples = (i + j) % 5 + 3;
|
samples = (i + j) % 5 + 3;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
void test_unit(void) {
|
void test_unit(void) {
|
||||||
NTP_int64 ntp_ts, ntp_fuzz;
|
NTP_int64 ntp_ts, ntp_fuzz;
|
||||||
struct timespec ts, ts2;
|
struct timespec ts, ts2;
|
||||||
|
struct timeval tv;
|
||||||
struct sockaddr_un sun;
|
struct sockaddr_un sun;
|
||||||
double x, y;
|
double x, y;
|
||||||
Float f;
|
Float f;
|
||||||
@@ -40,6 +41,32 @@ void test_unit(void) {
|
|||||||
TEST_CHECK(UTI_DoubleToNtp32(1000000) == htonl(0xffffffff));
|
TEST_CHECK(UTI_DoubleToNtp32(1000000) == htonl(0xffffffff));
|
||||||
TEST_CHECK(UTI_DoubleToNtp32(-1.0) == htonl(0));
|
TEST_CHECK(UTI_DoubleToNtp32(-1.0) == htonl(0));
|
||||||
|
|
||||||
|
UTI_DoubleToTimeval(0.4e-6, &tv);
|
||||||
|
TEST_CHECK(tv.tv_sec == 0);
|
||||||
|
TEST_CHECK(tv.tv_usec == 0);
|
||||||
|
UTI_DoubleToTimeval(-0.4e-6, &tv);
|
||||||
|
TEST_CHECK(tv.tv_sec == 0);
|
||||||
|
TEST_CHECK(tv.tv_usec == 0);
|
||||||
|
UTI_DoubleToTimeval(0.5e-6, &tv);
|
||||||
|
TEST_CHECK(tv.tv_sec == 0);
|
||||||
|
TEST_CHECK(tv.tv_usec == 1);
|
||||||
|
UTI_DoubleToTimeval(-0.5e-6, &tv);
|
||||||
|
TEST_CHECK(tv.tv_sec == -1);
|
||||||
|
TEST_CHECK(tv.tv_usec == 999999);
|
||||||
|
|
||||||
|
UTI_DoubleToTimespec(0.9e-9, &ts);
|
||||||
|
TEST_CHECK(ts.tv_sec == 0);
|
||||||
|
TEST_CHECK(ts.tv_nsec == 0);
|
||||||
|
UTI_DoubleToTimespec(1.0e-9, &ts);
|
||||||
|
TEST_CHECK(ts.tv_sec == 0);
|
||||||
|
TEST_CHECK(ts.tv_nsec == 1);
|
||||||
|
UTI_DoubleToTimespec(-0.9e-9, &ts);
|
||||||
|
TEST_CHECK(ts.tv_sec == 0);
|
||||||
|
TEST_CHECK(ts.tv_nsec == 0);
|
||||||
|
UTI_DoubleToTimespec(-1.0e-9, &ts);
|
||||||
|
TEST_CHECK(ts.tv_sec == -1);
|
||||||
|
TEST_CHECK(ts.tv_nsec == 999999999);
|
||||||
|
|
||||||
ntp_ts.hi = htonl(JAN_1970);
|
ntp_ts.hi = htonl(JAN_1970);
|
||||||
ntp_ts.lo = 0xffffffff;
|
ntp_ts.lo = 0xffffffff;
|
||||||
UTI_Ntp64ToTimespec(&ntp_ts, &ts);
|
UTI_Ntp64ToTimespec(&ntp_ts, &ts);
|
||||||
@@ -109,6 +136,11 @@ void test_unit(void) {
|
|||||||
TEST_CHECK(UTI_CompareNtp64(&ntp_ts, &ntp_fuzz) < 0);
|
TEST_CHECK(UTI_CompareNtp64(&ntp_ts, &ntp_fuzz) < 0);
|
||||||
TEST_CHECK(UTI_CompareNtp64(&ntp_fuzz, &ntp_ts) > 0);
|
TEST_CHECK(UTI_CompareNtp64(&ntp_fuzz, &ntp_ts) > 0);
|
||||||
|
|
||||||
|
TEST_CHECK(UTI_IsEqualAnyNtp64(&ntp_ts, &ntp_ts, NULL, NULL));
|
||||||
|
TEST_CHECK(UTI_IsEqualAnyNtp64(&ntp_ts, NULL, &ntp_ts, NULL));
|
||||||
|
TEST_CHECK(UTI_IsEqualAnyNtp64(&ntp_ts, NULL, NULL, &ntp_ts));
|
||||||
|
TEST_CHECK(!UTI_IsEqualAnyNtp64(&ntp_ts, &ntp_fuzz, &ntp_fuzz, &ntp_fuzz));
|
||||||
|
|
||||||
ts.tv_sec = 1;
|
ts.tv_sec = 1;
|
||||||
ts.tv_nsec = 2;
|
ts.tv_nsec = 2;
|
||||||
ts2.tv_sec = 1;
|
ts2.tv_sec = 1;
|
||||||
|
|||||||
56
util.c
56
util.c
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) Richard P. Curnow 1997-2003
|
* Copyright (C) Richard P. Curnow 1997-2003
|
||||||
* Copyright (C) Miroslav Lichvar 2009, 2012-2016
|
* Copyright (C) Miroslav Lichvar 2009, 2012-2017
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of version 2 of the GNU General Public License as
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
@@ -119,13 +119,11 @@ UTI_TimevalToDouble(struct timeval *tv)
|
|||||||
void
|
void
|
||||||
UTI_DoubleToTimeval(double a, struct timeval *b)
|
UTI_DoubleToTimeval(double a, struct timeval *b)
|
||||||
{
|
{
|
||||||
long int_part;
|
|
||||||
double frac_part;
|
double frac_part;
|
||||||
int_part = (long)(a);
|
|
||||||
frac_part = 1.0e6 * (a - (double)(int_part));
|
b->tv_sec = a;
|
||||||
frac_part = frac_part > 0 ? frac_part + 0.5 : frac_part - 0.5;
|
frac_part = 1.0e6 * (a - b->tv_sec);
|
||||||
b->tv_sec = int_part;
|
b->tv_usec = frac_part > 0 ? frac_part + 0.5 : frac_part - 0.5;
|
||||||
b->tv_usec = (long)frac_part;
|
|
||||||
UTI_NormaliseTimeval(b);
|
UTI_NormaliseTimeval(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,16 +366,14 @@ UTI_IPToRefid(IPAddr *ip)
|
|||||||
case IPADDR_INET4:
|
case IPADDR_INET4:
|
||||||
return ip->addr.in4;
|
return ip->addr.in4;
|
||||||
case IPADDR_INET6:
|
case IPADDR_INET6:
|
||||||
if (MD5_hash < 0) {
|
if (MD5_hash < 0)
|
||||||
MD5_hash = HSH_GetHashId("MD5");
|
MD5_hash = HSH_GetHashId("MD5");
|
||||||
assert(MD5_hash >= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (HSH_Hash(MD5_hash, (unsigned const char *)ip->addr.in6, sizeof
|
if (MD5_hash < 0 ||
|
||||||
(ip->addr.in6), NULL, 0, buf, 16) != 16) {
|
HSH_Hash(MD5_hash, (const unsigned char *)ip->addr.in6, sizeof (ip->addr.in6),
|
||||||
assert(0);
|
NULL, 0, buf, sizeof (buf)) != sizeof (buf))
|
||||||
return 0;
|
LOG_FATAL("Could not get MD5");
|
||||||
};
|
|
||||||
return (uint32_t)buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
|
return (uint32_t)buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -610,13 +606,17 @@ UTI_SockaddrFamilyToString(int family)
|
|||||||
char *
|
char *
|
||||||
UTI_TimeToLogForm(time_t t)
|
UTI_TimeToLogForm(time_t t)
|
||||||
{
|
{
|
||||||
struct tm stm;
|
struct tm *stm;
|
||||||
char *result;
|
char *result;
|
||||||
|
|
||||||
result = NEXT_BUFFER;
|
result = NEXT_BUFFER;
|
||||||
|
|
||||||
stm = *gmtime(&t);
|
stm = gmtime(&t);
|
||||||
strftime(result, BUFFER_LENGTH, "%Y-%m-%d %H:%M:%S", &stm);
|
|
||||||
|
if (stm)
|
||||||
|
strftime(result, BUFFER_LENGTH, "%Y-%m-%d %H:%M:%S", stm);
|
||||||
|
else
|
||||||
|
snprintf(result, BUFFER_LENGTH, "INVALID INVALID ");
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -641,6 +641,7 @@ UTI_GetNtp64Fuzz(NTP_int64 *ts, int precision)
|
|||||||
int start, bits;
|
int start, bits;
|
||||||
|
|
||||||
assert(precision >= -32 && precision <= 32);
|
assert(precision >= -32 && precision <= 32);
|
||||||
|
assert(sizeof (*ts) == 8);
|
||||||
|
|
||||||
start = sizeof (*ts) - (precision + 32 + 7) / 8;
|
start = sizeof (*ts) - (precision + 32 + 7) / 8;
|
||||||
ts->hi = ts->lo = 0;
|
ts->hi = ts->lo = 0;
|
||||||
@@ -723,6 +724,23 @@ UTI_CompareNtp64(NTP_int64 *a, NTP_int64 *b)
|
|||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
|
int
|
||||||
|
UTI_IsEqualAnyNtp64(NTP_int64 *a, NTP_int64 *b1, NTP_int64 *b2, NTP_int64 *b3)
|
||||||
|
{
|
||||||
|
if (b1 && a->lo == b1->lo && a->hi == b1->hi)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (b2 && a->lo == b2->lo && a->hi == b2->hi)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (b3 && a->lo == b3->lo && a->hi == b3->hi)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
/* Seconds part of NTP timestamp correponding to the origin of the time_t format */
|
/* Seconds part of NTP timestamp correponding to the origin of the time_t format */
|
||||||
#define JAN_1970 0x83aa7e80UL
|
#define JAN_1970 0x83aa7e80UL
|
||||||
|
|
||||||
@@ -855,7 +873,7 @@ UTI_TimespecNetworkToHost(Timespec *src, struct timespec *dest)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
nsec = ntohl(src->tv_nsec);
|
nsec = ntohl(src->tv_nsec);
|
||||||
dest->tv_nsec = CLAMP(0U, nsec, 999999999U);
|
dest->tv_nsec = MIN(nsec, 999999999U);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|||||||
4
util.h
4
util.h
@@ -136,6 +136,10 @@ extern int UTI_IsZeroNtp64(NTP_int64 *ts);
|
|||||||
b, and 1 if a is after b. */
|
b, and 1 if a is after b. */
|
||||||
extern int UTI_CompareNtp64(NTP_int64 *a, NTP_int64 *b);
|
extern int UTI_CompareNtp64(NTP_int64 *a, NTP_int64 *b);
|
||||||
|
|
||||||
|
/* Compare an NTP timestamp with up to three other timestamps. Returns 0
|
||||||
|
if a is not equal to any of b1, b2, and b3, 1 otherwise. */
|
||||||
|
extern int UTI_IsEqualAnyNtp64(NTP_int64 *a, NTP_int64 *b1, NTP_int64 *b2, NTP_int64 *b3);
|
||||||
|
|
||||||
/* Convert a timespec into an NTP timestamp */
|
/* Convert a timespec into an NTP timestamp */
|
||||||
extern void UTI_TimespecToNtp64(struct timespec *src, NTP_int64 *dest, NTP_int64 *fuzz);
|
extern void UTI_TimespecToNtp64(struct timespec *src, NTP_int64 *dest, NTP_int64 *fuzz);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user