summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FAQ10
-rw-r--r--INSTALL2
-rw-r--r--Makefile.in8
-rw-r--r--NEWS36
-rw-r--r--README2
-rw-r--r--array.c7
-rw-r--r--candm.h17
-rw-r--r--client.c238
-rw-r--r--clientlog.c23
-rw-r--r--clientlog.h1
-rw-r--r--cmdmon.c57
-rw-r--r--cmdparse.c8
-rw-r--r--conf.c90
-rw-r--r--conf.h11
-rwxr-xr-xconfigure59
-rw-r--r--doc/chrony.conf.adoc305
-rw-r--r--doc/chrony.conf.man.in391
-rw-r--r--doc/chronyc.adoc20
-rw-r--r--doc/chronyc.man.in22
-rw-r--r--doc/chronyd.adoc24
-rw-r--r--doc/chronyd.man.in30
-rw-r--r--doc/faq.adoc8
-rw-r--r--examples/chrony.conf.example23
-rw-r--r--examples/chrony.conf.example36
-rw-r--r--examples/chrony.nm-dispatcher34
-rw-r--r--examples/chrony.spec2
-rw-r--r--hwclock.c30
-rw-r--r--keys.c12
-rw-r--r--local.c22
-rw-r--r--local.h9
-rw-r--r--localp.h4
-rw-r--r--logging.c35
-rw-r--r--logging.h68
-rw-r--r--main.c287
-rw-r--r--manual.c46
-rw-r--r--manual.h2
-rw-r--r--memory.c34
-rw-r--r--memory.h6
-rw-r--r--nameserv_async.c6
-rw-r--r--ntp.h3
-rw-r--r--ntp_core.c473
-rw-r--r--ntp_io.c63
-rw-r--r--ntp_io_linux.c213
-rw-r--r--ntp_signd.c41
-rw-r--r--ntp_sources.c25
-rw-r--r--pktlength.c9
-rw-r--r--privops.c67
-rw-r--r--privops.h6
-rw-r--r--refclock.c152
-rw-r--r--refclock.h5
-rw-r--r--refclock_phc.c81
-rw-r--r--refclock_pps.c18
-rw-r--r--refclock_shm.c6
-rw-r--r--refclock_sock.c12
-rw-r--r--reference.c242
-rw-r--r--regress.c59
-rw-r--r--regress.h3
-rw-r--r--rtc.c6
-rw-r--r--rtc_linux.c52
-rw-r--r--sched.c14
-rw-r--r--sched.h3
-rw-r--r--smooth.c11
-rw-r--r--sources.c42
-rw-r--r--sources.h4
-rw-r--r--sourcestats.c165
-rw-r--r--sourcestats.h12
-rw-r--r--srcparams.h3
-rw-r--r--stubs.c2
-rw-r--r--sys.c24
-rw-r--r--sys.h2
-rw-r--r--sys_generic.c6
-rw-r--r--sys_linux.c127
-rw-r--r--sys_linux.h5
-rw-r--r--sys_macosx.c103
-rw-r--r--sys_netbsd.c17
-rw-r--r--sys_null.c140
-rw-r--r--sys_null.h34
-rw-r--r--sys_timex.c70
-rw-r--r--sysincl.h6
-rw-r--r--tempcomp.c14
-rwxr-xr-xtest/simulation/117-fallbackdrift5
-rwxr-xr-xtest/simulation/118-maxdelay4
-rwxr-xr-xtest/simulation/122-xleave1
-rwxr-xr-xtest/simulation/123-mindelay27
-rwxr-xr-xtest/simulation/run78
-rw-r--r--test/unit/addrfilt.c2
-rw-r--r--test/unit/clientlog.c10
-rw-r--r--test/unit/hwclock.c24
-rw-r--r--test/unit/keys.c8
-rw-r--r--test/unit/ntp_core.c7
-rw-r--r--test/unit/ntp_sources.c8
-rw-r--r--test/unit/regress.c119
-rw-r--r--test/unit/smooth.c4
-rw-r--r--test/unit/sources.c15
-rw-r--r--test/unit/test.c4
-rw-r--r--test/unit/util.c21
-rw-r--r--util.c96
-rw-r--r--version.txt2
98 files changed, 3176 insertions, 1574 deletions
diff --git a/FAQ b/FAQ
index 73db92b..57483fb 100644
--- a/FAQ
+++ b/FAQ
@@ -72,7 +72,7 @@ can be used for names that resolve to multiple addresses. For good reliability
the client should have at least three servers. The iburst option 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.
If the system clock can be far from the true time after boot for any reason,
@@ -80,7 +80,7 @@ chronyd should be allowed to correct it quickly by stepping instead of slewing,
which would take a very long time. The makestep directive does that.
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
system time is periodically copied to the RTC. It is supported on Linux and
macOS.
@@ -344,14 +344,14 @@ side).
5.1. What is the real-time clock (RTC)?
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.
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 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 still be
-close to the true time when the system clock will be initialized from it on the
+close to the true time when the system clock will be initialised from it on the
next boot.
The other option is to use the rtcfile directive, which tells chronyd to
@@ -441,4 +441,4 @@ needs to be made to work as a service.
We have no plans to do this. Anyone is welcome to pick this work up and
contribute it back to the project.
-Last updated 2017-01-31 11:22:11 CET
+Last updated 2017-09-15 08:32:09 CEST
diff --git a/INSTALL b/INSTALL
index 584d759..c734166 100644
--- a/INSTALL
+++ b/INSTALL
@@ -147,4 +147,4 @@ tar cvf - . | gzip -9 > chrony.tar.gz
to build a package. When untarred within the root directory, this will install
the files to the intended final locations.
-Last updated 2017-01-31 11:22:11 CET
+Last updated 2017-09-15 08:32:09 CEST
diff --git a/Makefile.in b/Makefile.in
index 6f67b92..5a4aeee 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -37,7 +37,7 @@ HASH_OBJ = @HASH_OBJ@
OBJS = array.o cmdparse.o conf.o local.o logging.o main.o memory.o \
reference.o regress.o rtc.o sched.o sources.o sourcestats.o stubs.o \
- sys.o smooth.o tempcomp.o util.o $(HASH_OBJ)
+ smooth.o sys.o sys_null.o tempcomp.o util.o $(HASH_OBJ)
EXTRA_OBJS=@EXTRA_OBJECTS@
@@ -109,10 +109,14 @@ install-docs :
%.s : %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -S $<
-check : chronyd chronyc
+quickcheck : chronyd chronyc
$(MAKE) -C test/unit check
cd test/simulation && ./run
+check : chronyd chronyc
+ $(MAKE) -C test/unit check
+ cd test/simulation && ./run -i 20 -m 2
+
Makefile : Makefile.in configure
@echo
@echo Makefile needs to be regenerated, run ./configure
diff --git a/NEWS b/NEWS
index fe5390e..e261098 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,39 @@
+New in version 3.2
+==================
+
+Enhancements
+------------
+* Improve stability with NTP sources and reference clocks
+* Improve stability with hardware timestamping
+* Improve support for NTP interleaved modes
+* Control frequency of system clock on macOS 10.13 and later
+* Set TAI-UTC offset of system clock with leapsectz directive
+* Minimise data in client requests to improve privacy
+* 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 pps option to refclock directive to treat any refclock as PPS
+* 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 -l option to log to specified file instead of syslog
+* Allow multiple command-line options to be specified together
+* Allow starting without root privileges with -Q option
+* Update seccomp filter for new glibc versions
+* Dump history on exit by default with dumpdir directive
+* Use hardening compiler options by default
+
+Bug fixes
+---------
+* Don't drop PHC samples with low-resolution system clock
+* Ignore outliers in PHC tracking, RTC tracking, manual input
+* Increase polling interval when peer is not responding
+* Exit with error message when include directive fails
+* Don't allow slash after hostname in allow/deny directive/command
+* Try to connect to all addresses in chronyc before giving up
+
New in version 3.1
==================
diff --git a/README b/README
index 52dad73..d868660 100644
--- a/README
+++ b/README
@@ -4,7 +4,7 @@ What is chrony?
===============
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.
It can also operate as an NTPv4 (RFC 5905) server and peer to provide
a time service to other computers in the network.
diff --git a/array.c b/array.c
index ffe5a4e..d70cff9 100644
--- a/array.c
+++ b/array.c
@@ -66,8 +66,6 @@ ARR_DestroyInstance(ARR_Instance array)
static void
realloc_array(ARR_Instance array, unsigned int min_size)
{
- size_t data_size;
-
assert(min_size <= 2 * min_size);
if (array->allocated >= min_size && array->allocated <= 2 * min_size)
return;
@@ -79,10 +77,7 @@ realloc_array(ARR_Instance array, unsigned int min_size)
array->allocated = min_size;
}
- data_size = (size_t)array->elem_size * array->allocated;
- assert(data_size / array->elem_size == array->allocated);
-
- array->data = Realloc(array->data, data_size);
+ array->data = Realloc2(array->data, array->allocated, array->elem_size);
}
void *
diff --git a/candm.h b/candm.h
index 0900343..b03448c 100644
--- a/candm.h
+++ b/candm.h
@@ -97,7 +97,9 @@
#define REQ_NTP_DATA 57
#define REQ_ADD_SERVER2 58
#define REQ_ADD_PEER2 59
-#define N_REQUEST_TYPES 60
+#define REQ_ADD_SERVER3 60
+#define REQ_ADD_PEER3 61
+#define N_REQUEST_TYPES 62
/* Structure used to exchange timespecs independent of time_t size */
typedef struct {
@@ -267,8 +269,11 @@ typedef struct {
Float max_delay;
Float max_delay_ratio;
Float max_delay_dev_ratio;
+ Float min_delay;
+ Float asymmetry;
Float offset;
uint32_t flags;
+ uint32_t reserved[4];
int32_t EOR;
} REQ_NTP_Source;
@@ -362,8 +367,9 @@ typedef struct {
domain socket.
Version 6 (no authentication) : changed format of client accesses by index
- (using new request/reply types), new fields and flags in NTP source request
- and report, new commands: ntpdata, refresh, serverstats
+ (using new request/reply types) and manual timestamp, new fields and flags
+ in NTP source request and report, new commands: ntpdata, refresh,
+ serverstats
*/
#define PROTO_VERSION_NUMBER 6
@@ -461,7 +467,8 @@ typedef struct {
#define RPY_SERVER_STATS 14
#define RPY_CLIENT_ACCESSES_BY_INDEX2 15
#define RPY_NTP_DATA 16
-#define N_REPLY_TYPES 17
+#define RPY_MANUAL_TIMESTAMP2 17
+#define N_REPLY_TYPES 18
/* Status codes */
#define STT_SUCCESS 0
@@ -569,7 +576,7 @@ typedef struct {
} RPY_Rtc;
typedef struct {
- uint32_t centiseconds;
+ Float offset;
Float dfreq_ppm;
Float new_afreq_ppm;
int32_t EOR;
diff --git a/client.c b/client.c
index a22f7ad..5c3a99e 100644
--- a/client.c
+++ b/client.c
@@ -4,7 +4,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* 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
* it under the terms of version 2 of the GNU General Public License as
@@ -81,8 +81,7 @@ int log_debug_enabled = 0;
void LOG_Message(LOG_Severity severity,
#if DEBUG > 0
- LOG_Facility facility, int line_number,
- const char *filename, const char *function_name,
+ int line_number, const char *filename, const char *function_name,
#endif
const char *format, ...)
{
@@ -168,18 +167,18 @@ get_sockaddrs(const char *hostnames, int port)
addr = (union sockaddr_all *)ARR_GetNewElement(addrs);
if (snprintf(addr->un.sun_path, sizeof (addr->un.sun_path), "%s", hostname) >=
sizeof (addr->un.sun_path))
- LOG_FATAL(LOGF_Client, "Unix socket path too long");
+ LOG_FATAL("Unix socket path too long");
addr->un.sun_family = AF_UNIX;
} else {
if (DNS_Name2IPAddress(hostname, ip_addrs, DNS_MAX_ADDRESSES) != DNS_Success) {
- DEBUG_LOG(LOGF_Client, "Could not get IP address for %s", hostname);
- break;
+ DEBUG_LOG("Could not get IP address for %s", hostname);
+ continue;
}
for (i = 0; i < DNS_MAX_ADDRESSES && ip_addrs[i].family != IPADDR_UNSPEC; i++) {
addr = (union sockaddr_all *)ARR_GetNewElement(addrs);
UTI_IPAndPortToSockaddr(&ip_addrs[i], port, (struct sockaddr *)addr);
- DEBUG_LOG(LOGF_Client, "Resolved %s to %s", hostname, UTI_IPToString(&ip_addrs[i]));
+ DEBUG_LOG("Resolved %s to %s", hostname, UTI_IPToString(&ip_addrs[i]));
}
}
}
@@ -216,7 +215,7 @@ prepare_socket(union sockaddr_all *addr)
sock_fd = socket(addr->sa.sa_family, SOCK_DGRAM, 0);
if (sock_fd < 0) {
- DEBUG_LOG(LOGF_Client, "Could not create socket : %s", strerror(errno));
+ DEBUG_LOG("Could not create socket : %s", strerror(errno));
return 0;
}
@@ -229,7 +228,7 @@ prepare_socket(union sockaddr_all *addr)
dir = UTI_PathToDir(addr->un.sun_path);
if (snprintf(sa_un.sun_path, sizeof (sa_un.sun_path),
"%s/chronyc.%d.sock", dir, (int)getpid()) >= sizeof (sa_un.sun_path))
- LOG_FATAL(LOGF_Client, "Unix socket path too long");
+ LOG_FATAL("Unix socket path too long");
Free(dir);
sa_un.sun_family = AF_UNIX;
@@ -237,19 +236,19 @@ prepare_socket(union sockaddr_all *addr)
/* Bind the socket to the path */
if (bind(sock_fd, (struct sockaddr *)&sa_un, sizeof (sa_un)) < 0) {
- DEBUG_LOG(LOGF_Client, "Could not bind socket : %s", strerror(errno));
+ DEBUG_LOG("Could not bind socket : %s", strerror(errno));
return 0;
}
/* Allow server without root privileges to send replies to our socket */
if (chmod(sa_un.sun_path, 0666) < 0) {
- DEBUG_LOG(LOGF_Client, "Could not change socket permissions : %s", strerror(errno));
+ DEBUG_LOG("Could not change socket permissions : %s", strerror(errno));
return 0;
}
}
if (connect(sock_fd, &addr->sa, addr_len) < 0) {
- DEBUG_LOG(LOGF_Client, "Could not connect socket : %s", strerror(errno));
+ DEBUG_LOG("Could not connect socket : %s", strerror(errno));
return 0;
}
@@ -269,7 +268,7 @@ close_io(void)
/* Remove our Unix domain socket */
if (getsockname(sock_fd, &addr.sa, &addr_len) < 0)
- LOG_FATAL(LOGF_Client, "getsockname() failed : %s", strerror(errno));
+ LOG_FATAL("getsockname() failed : %s", strerror(errno));
if (addr_len <= sizeof (addr) && addr_len > sizeof (addr.sa.sa_family) &&
addr.sa.sa_family == AF_UNIX)
unlink(addr.un.sun_path);
@@ -295,8 +294,7 @@ open_io(void)
/* Find an address for which a socket can be opened and connected */
for (; address_index < ARR_GetSize(sockaddrs); address_index++) {
addr = (union sockaddr_all *)ARR_GetElement(sockaddrs, address_index);
- DEBUG_LOG(LOGF_Client, "Opening connection to %s",
- UTI_SockaddrToString(&addr->sa));
+ DEBUG_LOG("Opening connection to %s", UTI_SockaddrToString(&addr->sa));
if (prepare_socket(addr))
return 1;
@@ -317,7 +315,7 @@ bits_to_mask(int bits, int family, IPAddr *mask)
mask->family = family;
switch (family) {
case IPADDR_INET4:
- if (bits < 0)
+ if (bits > 32 || bits < 0)
bits = 32;
if (bits > 0) {
mask->addr.in4 = -1;
@@ -373,13 +371,13 @@ read_mask_address(char *line, IPAddr *mask, IPAddr *address)
bits_to_mask(-1, address->family, mask);
return 1;
} else {
- LOG(LOGS_ERR, LOGF_Client, "Could not get address for hostname");
+ LOG(LOGS_ERR, "Could not get address for hostname");
return 0;
}
}
}
- LOG(LOGS_ERR, LOGF_Client, "Invalid syntax for mask/address");
+ LOG(LOGS_ERR, "Invalid syntax for mask/address");
return 0;
}
@@ -438,11 +436,11 @@ read_address_integer(char *line, IPAddr *address, int *value)
line = CPS_SplitWord(line);
if (sscanf(line, "%d", value) != 1) {
- LOG(LOGS_ERR, LOGF_Client, "Invalid syntax for address value");
+ LOG(LOGS_ERR, "Invalid syntax for address value");
ok = 0;
} else {
if (DNS_Name2IPAddress(hostname, address, 1) != DNS_Success) {
- LOG(LOGS_ERR, LOGF_Client, "Could not get address for hostname");
+ LOG(LOGS_ERR, "Could not get address for hostname");
ok = 0;
} else {
ok = 1;
@@ -466,11 +464,11 @@ read_address_double(char *line, IPAddr *address, double *value)
line = CPS_SplitWord(line);
if (sscanf(line, "%lf", value) != 1) {
- LOG(LOGS_ERR, LOGF_Client, "Invalid syntax for address value");
+ LOG(LOGS_ERR, "Invalid syntax for address value");
ok = 0;
} else {
if (DNS_Name2IPAddress(hostname, address, 1) != DNS_Success) {
- LOG(LOGS_ERR, LOGF_Client, "Could not get address for hostname");
+ LOG(LOGS_ERR, "Could not get address for hostname");
ok = 0;
} else {
ok = 1;
@@ -703,7 +701,7 @@ process_cmd_burst(CMD_Request *msg, char *line)
CPS_SplitWord(s2);
if (sscanf(s1, "%d/%d", &n_good_samples, &n_total_samples) != 2) {
- LOG(LOGS_ERR, LOGF_Client, "Invalid syntax for burst command");
+ LOG(LOGS_ERR, "Invalid syntax for burst command");
return 0;
}
@@ -735,7 +733,7 @@ process_cmd_local(CMD_Request *msg, char *line)
} else if (CPS_ParseLocal(line, &stratum, &orphan, &distance)) {
on_off = 1;
} else {
- LOG(LOGS_ERR, LOGF_Client, "Invalid syntax for local command");
+ LOG(LOGS_ERR, "Invalid syntax for local command");
return 0;
}
@@ -764,7 +762,7 @@ process_cmd_manual(CMD_Request *msg, const char *line)
} else if (!strcmp(p, "reset")) {
msg->data.manual.option = htonl(2);
} else {
- LOG(LOGS_ERR, LOGF_Client, "Invalid syntax for manual command");
+ LOG(LOGS_ERR, "Invalid syntax for manual command");
return 0;
}
msg->command = htons(REQ_MANUAL);
@@ -798,8 +796,8 @@ parse_allow_deny(CMD_Request *msg, char *line)
(n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d)) <= 0) {
/* Try to parse as the name of a machine */
- if (DNS_Name2IPAddress(p, &ip, 1) != DNS_Success) {
- LOG(LOGS_ERR, LOGF_Client, "Could not read address");
+ if (slashpos || DNS_Name2IPAddress(p, &ip, 1) != DNS_Success) {
+ LOG(LOGS_ERR, "Could not read address");
return 0;
} else {
UTI_IPHostToNetwork(&ip, &msg->data.allow_deny.ip);
@@ -852,7 +850,7 @@ parse_allow_deny(CMD_Request *msg, char *line)
if (n == 1) {
msg->data.allow_deny.subnet_bits = htonl(specified_subnet_bits);
} else {
- LOG(LOGS_WARN, LOGF_Client, "Warning: badly formatted subnet size, using %d",
+ LOG(LOGS_WARN, "Warning: badly formatted subnet size, using %d",
(int)ntohl(msg->data.allow_deny.subnet_bits));
}
}
@@ -987,7 +985,7 @@ process_cmd_accheck(CMD_Request *msg, char *line)
UTI_IPHostToNetwork(&ip, &msg->data.ac_check.ip);
return 1;
} else {
- LOG(LOGS_ERR, LOGF_Client, "Could not read address");
+ LOG(LOGS_ERR, "Could not read address");
return 0;
}
}
@@ -1003,7 +1001,7 @@ process_cmd_cmdaccheck(CMD_Request *msg, char *line)
UTI_IPHostToNetwork(&ip, &msg->data.ac_check.ip);
return 1;
} else {
- LOG(LOGS_ERR, LOGF_Client, "Could not read address");
+ LOG(LOGS_ERR, "Could not read address");
return 0;
}
}
@@ -1073,17 +1071,17 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
status = CPS_ParseNTPSourceAdd(line, &data);
switch (status) {
case 0:
- LOG(LOGS_ERR, LOGF_Client, "Invalid syntax for add command");
+ LOG(LOGS_ERR, "Invalid syntax for add command");
break;
default:
if (DNS_Name2IPAddress(data.name, &ip_addr, 1) != DNS_Success) {
- LOG(LOGS_ERR, LOGF_Client, "Invalid host/IP address");
+ LOG(LOGS_ERR, "Invalid host/IP address");
break;
}
opt_name = NULL;
if (opt_name) {
- LOG(LOGS_ERR, LOGF_Client, "%s can't be set in chronyc", opt_name);
+ LOG(LOGS_ERR, "%s can't be set in chronyc", opt_name);
break;
}
@@ -1103,6 +1101,8 @@ 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_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.flags = htonl(
(data.params.online ? REQ_ADDSRC_ONLINE : 0) |
@@ -1113,6 +1113,8 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
(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_REQUIRE ? REQ_ADDSRC_REQUIRE : 0));
+ memset(msg->data.ntp_source.reserved, 0, sizeof (msg->data.ntp_source.reserved));
+
result = 1;
break;
@@ -1126,7 +1128,7 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
static int
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);
}
@@ -1135,7 +1137,7 @@ process_cmd_add_server(CMD_Request *msg, char *line)
static int
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);
}
@@ -1153,11 +1155,11 @@ process_cmd_delete(CMD_Request *msg, char *line)
CPS_SplitWord(line);
if (!*hostname) {
- LOG(LOGS_ERR, LOGF_Client, "Invalid syntax for address");
+ LOG(LOGS_ERR, "Invalid syntax for address");
ok = 0;
} else {
if (DNS_Name2IPAddress(hostname, &address, 1) != DNS_Success) {
- LOG(LOGS_ERR, LOGF_Client, "Could not get address for hostname");
+ LOG(LOGS_ERR, "Could not get address for hostname");
ok = 0;
} else {
UTI_IPHostToNetwork(&address, &msg->data.del_source.ip_addr);
@@ -1369,17 +1371,16 @@ submit_request(CMD_Request *request, CMD_Reply *reply)
memset(((char *)request) + command_length - padding_length, 0, padding_length);
if (sock_fd < 0) {
- DEBUG_LOG(LOGF_Client, "No socket to send request");
+ DEBUG_LOG("No socket to send request");
return 0;
}
if (send(sock_fd, (void *)request, command_length, 0) < 0) {
- DEBUG_LOG(LOGF_Client, "Could not send %d bytes : %s",
- command_length, strerror(errno));
+ DEBUG_LOG("Could not send %d bytes : %s", command_length, strerror(errno));
return 0;
}
- DEBUG_LOG(LOGF_Client, "Sent %d bytes", command_length);
+ DEBUG_LOG("Sent %d bytes", command_length);
}
if (gettimeofday(&tv, NULL))
@@ -1394,7 +1395,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply)
timeout = initial_timeout / 1000.0 * (1U << (n_attempts - 1)) -
UTI_DiffTimespecsToDouble(&ts_now, &ts_start);
UTI_DoubleToTimeval(timeout, &tv);
- DEBUG_LOG(LOGF_Client, "Timeout %f seconds", timeout);
+ DEBUG_LOG("Timeout %f seconds", timeout);
FD_ZERO(&rdfd);
FD_ZERO(&wrfd);
@@ -1408,7 +1409,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply)
select_status = select(sock_fd + 1, &rdfd, &wrfd, &exfd, &tv);
if (select_status < 0) {
- DEBUG_LOG(LOGF_Client, "select failed : %s", strerror(errno));
+ DEBUG_LOG("select failed : %s", strerror(errno));
} else if (select_status == 0) {
/* Timeout must have elapsed, try a resend? */
new_attempt = 1;
@@ -1418,10 +1419,10 @@ submit_request(CMD_Request *request, CMD_Reply *reply)
if (recv_status < 0) {
/* If we get connrefused here, it suggests the sendto is
going to a dead port */
- DEBUG_LOG(LOGF_Client, "Could not receive : %s", strerror(errno));
+ DEBUG_LOG("Could not receive : %s", strerror(errno));
new_attempt = 1;
} else {
- DEBUG_LOG(LOGF_Client, "Received %d bytes", recv_status);
+ DEBUG_LOG("Received %d bytes", recv_status);
read_length = recv_status;
if (read_length >= offsetof(CMD_Reply, data)) {
@@ -1471,7 +1472,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply)
#endif
/* Good packet received, print out results */
- DEBUG_LOG(LOGF_Client, "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));
break;
}
@@ -2061,7 +2062,8 @@ process_cmd_sources(char *line)
mode = ntohs(reply.data.source_data.mode);
UTI_IPNetworkToHost(&reply.data.source_data.ip_addr, &ip_addr);
- format_name(name, sizeof (name), 25, mode == RPY_SD_MD_REF,
+ format_name(name, sizeof (name), 25,
+ mode == RPY_SD_MD_REF && ip_addr.family == IPADDR_INET4,
ip_addr.addr.in4, &ip_addr);
switch (mode) {
@@ -2264,7 +2266,7 @@ process_cmd_ntpdata(char *line)
for (i = 0; i < n_sources; i++) {
if (specified_addr) {
if (DNS_Name2IPAddress(line, &remote_addr, 1) != DNS_Success) {
- LOG(LOGS_ERR, LOGF_Client, "Could not get address for hostname");
+ LOG(LOGS_ERR, "Could not get address for hostname");
return 0;
}
} else {
@@ -2421,7 +2423,7 @@ process_cmd_smoothtime(CMD_Request *msg, const char *line)
} else if (!strcmp(line, "activate")) {
msg->data.smoothtime.option = htonl(REQ_SMOOTHTIME_ACTIVATE);
} else {
- LOG(LOGS_ERR, LOGF_Client, "Invalid syntax for smoothtime command");
+ LOG(LOGS_ERR, "Invalid syntax for smoothtime command");
return 0;
}
@@ -2569,7 +2571,7 @@ process_cmd_manual_delete(CMD_Request *msg, const char *line)
int index;
if (sscanf(line, "%d", &index) != 1) {
- LOG(LOGS_ERR, LOGF_Client, "Bad syntax for manual delete command");
+ LOG(LOGS_ERR, "Bad syntax for manual delete command");
return 0;
}
@@ -2587,7 +2589,6 @@ process_cmd_settime(char *line)
time_t now, new_time;
CMD_Request request;
CMD_Reply reply;
- long offset_cs;
double dfreq_ppm, new_afreq_ppm;
double offset;
@@ -2601,9 +2602,8 @@ process_cmd_settime(char *line)
ts.tv_nsec = 0;
UTI_TimespecHostToNetwork(&ts, &request.data.settime.ts);
request.command = htons(REQ_SETTIME);
- if (request_reply(&request, &reply, RPY_MANUAL_TIMESTAMP, 1)) {
- offset_cs = ntohl(reply.data.manual_timestamp.centiseconds);
- offset = 0.01 * (double)(int32_t)offset_cs;
+ if (request_reply(&request, &reply, RPY_MANUAL_TIMESTAMP2, 1)) {
+ offset = UTI_FloatNetworkToHost(reply.data.manual_timestamp.offset);
dfreq_ppm = UTI_FloatNetworkToHost(reply.data.manual_timestamp.dfreq_ppm);
new_afreq_ppm = UTI_FloatNetworkToHost(reply.data.manual_timestamp.new_afreq_ppm);
printf("Clock was %.2f seconds fast. Frequency change = %.2fppm, new frequency = %.2fppm\n",
@@ -2632,7 +2632,7 @@ process_cmd_makestep(CMD_Request *msg, char *line)
if (*line) {
if (sscanf(line, "%lf %d", &threshold, &limit) != 2) {
- LOG(LOGS_ERR, LOGF_Client, "Bad syntax for makestep command");
+ LOG(LOGS_ERR, "Bad syntax for makestep command");
return 0;
}
msg->command = htons(REQ_MODIFY_MAKESTEP);
@@ -2781,7 +2781,7 @@ process_cmd_dns(const char *line)
} else if (!strcmp(line, "+n")) {
no_dns = 0;
} else {
- LOG(LOGS_ERR, LOGF_Client, "Unrecognized dns command");
+ LOG(LOGS_ERR, "Unrecognized dns command");
return 0;
}
return 1;
@@ -2796,7 +2796,7 @@ process_cmd_timeout(const char *line)
timeout = atoi(line);
if (timeout < 100) {
- LOG(LOGS_ERR, LOGF_Client, "Timeout %d is too short", timeout);
+ LOG(LOGS_ERR, "Timeout %d is too short", timeout);
return 0;
}
initial_timeout = timeout;
@@ -2811,8 +2811,8 @@ process_cmd_retries(const char *line)
int retries;
retries = atoi(line);
- if (retries < 0) {
- LOG(LOGS_ERR, LOGF_Client, "Invalid maximum number of retries");
+ if (retries < 0 || retries > 30) {
+ LOG(LOGS_ERR, "Invalid maximum number of retries");
return 0;
}
max_retries = retries;
@@ -2839,7 +2839,7 @@ process_cmd_keygen(char *line)
length = CLAMP(10, (bits + 7) / 8, sizeof (key));
if (HSH_GetHashId(hash_name) < 0) {
- LOG(LOGS_ERR, LOGF_Client, "Unknown hash function %s", hash_name);
+ LOG(LOGS_ERR, "Unknown hash function %s", hash_name);
return 0;
}
@@ -3031,11 +3031,11 @@ process_line(char *line)
} else if (!strcmp(command, "authhash") ||
!strcmp(command, "password")) {
/* Warn, but don't return error to not break scripts */
- LOG(LOGS_WARN, LOGF_Client, "Authentication is no longer supported");
+ LOG(LOGS_WARN, "Authentication is no longer supported");
do_normal_submit = 0;
ret = 1;
} else {
- LOG(LOGS_ERR, LOGF_Client, "Unrecognized command");
+ LOG(LOGS_ERR, "Unrecognized command");
do_normal_submit = 0;
}
@@ -3052,7 +3052,7 @@ process_line(char *line)
static int
process_args(int argc, char **argv, int multi)
{
- int total_length, i, ret;
+ int total_length, i, ret = 0;
char *line;
total_length = 0;
@@ -3107,54 +3107,80 @@ display_gpl(void)
/* ================================================== */
+static void
+print_help(const char *progname)
+{
+ printf("Usage: %s [-h HOST] [-p PORT] [-n] [-c] [-d] [-4|-6] [-m] [COMMAND]\n",
+ progname);
+}
+
+/* ================================================== */
+
+static void
+print_version(void)
+{
+ printf("chronyc (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYC_FEATURES);
+}
+
+/* ================================================== */
+
int
main(int argc, char **argv)
{
char *line;
const char *progname = argv[0];
const char *hostnames = NULL;
- int ret = 1, multi = 0, family = IPADDR_UNSPEC;
+ int opt, ret = 1, multi = 0, family = IPADDR_UNSPEC;
int port = DEFAULT_CANDM_PORT;
- /* Parse command line options */
- while (++argv, --argc) {
- if (!strcmp(*argv, "-h")) {
- ++argv, --argc;
- if (*argv) {
- hostnames = *argv;
- }
- } else if (!strcmp(*argv, "-p")) {
- ++argv, --argc;
- if (*argv) {
- port = atoi(*argv);
- }
- } else if (!strcmp(*argv, "-f")) {
- ++argv, --argc;
- /* For compatibility */
- } else if (!strcmp(*argv, "-a")) {
- /* For compatibility */
- } else if (!strcmp(*argv, "-c")) {
- csv_mode = 1;
- } else if (!strcmp(*argv, "-d")) {
- log_debug_enabled = 1;
- } else if (!strcmp(*argv, "-m")) {
- multi = 1;
- } else if (!strcmp(*argv, "-n")) {
- no_dns = 1;
- } else if (!strcmp(*argv, "-4")) {
- family = IPADDR_INET4;
- } else if (!strcmp(*argv, "-6")) {
- family = IPADDR_INET6;
- } else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
- printf("chronyc (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYC_FEATURES);
+ /* Parse (undocumented) long command-line options */
+ for (optind = 1; optind < argc; optind++) {
+ if (!strcmp("--help", argv[optind])) {
+ print_help(progname);
return 0;
- } else if (!strncmp(*argv, "-", 1)) {
- LOG(LOGS_ERR, LOGF_Client,
- "Usage: %s [-h HOST] [-p PORT] [-n] [-c] [-d] [-4|-6] [-m] [COMMAND]",
- progname);
- return 1;
- } else {
- break; /* And process remainder of line as a command */
+ } else if (!strcmp("--version", argv[optind])) {
+ print_version();
+ return 0;
+ }
+ }
+
+ optind = 1;
+
+ /* Parse short command-line options */
+ while ((opt = getopt(argc, argv, "+46acdf:h:mnp:v")) != -1) {
+ switch (opt) {
+ case '4':
+ case '6':
+ family = opt == '4' ? IPADDR_INET4 : IPADDR_INET6;
+ break;
+ case 'a':
+ case 'f':
+ /* For compatibility only */
+ break;
+ case 'c':
+ csv_mode = 1;
+ break;
+ case 'd':
+ log_debug_enabled = 1;
+ break;
+ case 'h':
+ hostnames = optarg;
+ break;
+ case 'm':
+ multi = 1;
+ break;
+ case 'n':
+ no_dns = 1;
+ break;
+ case 'p':
+ port = atoi(optarg);
+ break;
+ case 'v':
+ print_version();
+ return 0;
+ default:
+ print_help(progname);
+ return 1;
}
}
@@ -3162,7 +3188,7 @@ main(int argc, char **argv)
on_terminal = 1;
}
- if (on_terminal && (argc == 0)) {
+ if (on_terminal && optind == argc) {
display_gpl();
}
@@ -3177,10 +3203,10 @@ main(int argc, char **argv)
sockaddrs = get_sockaddrs(hostnames, port);
if (!open_io())
- LOG_FATAL(LOGF_Client, "Could not open connection to daemon");
+ LOG_FATAL("Could not open connection to daemon");
- if (argc > 0) {
- ret = process_args(argc, argv, multi);
+ if (optind < argc) {
+ ret = process_args(argc - optind, argv + optind, multi);
} else {
do {
line = read_line();
diff --git a/clientlog.c b/clientlog.c
index 0ace6d6..86962a7 100644
--- a/clientlog.c
+++ b/clientlog.c
@@ -3,7 +3,7 @@
**********************************************************************
* 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
* it under the terms of version 2 of the GNU General Public License as
@@ -128,6 +128,9 @@ static int cmd_leak_rate;
/* Flag indicating whether the last response was dropped */
#define FLAG_NTP_DROPPED 0x1
+/* NTP limit interval in log2 */
+static int ntp_limit_interval;
+
/* Flag indicating whether facility is turned on or not */
static int active;
@@ -294,7 +297,7 @@ set_bucket_params(int interval, int burst, uint16_t *max_tokens,
*tokens_per_packet = 1U << (TS_FRAC + interval - *token_shift);
*max_tokens = *tokens_per_packet * burst;
- DEBUG_LOG(LOGF_ClientLog, "Tokens max %d packet %d shift %d",
+ DEBUG_LOG("Tokens max %d packet %d shift %d",
*max_tokens, *tokens_per_packet, *token_shift);
}
@@ -309,11 +312,13 @@ CLG_Initialise(void)
ntp_tokens_per_packet = cmd_tokens_per_packet = 0;
ntp_token_shift = cmd_token_shift = 0;
ntp_leak_rate = cmd_leak_rate = 0;
+ ntp_limit_interval = MIN_LIMIT_INTERVAL;
if (CNF_GetNTPRateLimit(&interval, &burst, &leak_rate)) {
set_bucket_params(interval, burst, &max_ntp_tokens, &ntp_tokens_per_packet,
&ntp_token_shift);
ntp_leak_rate = CLAMP(MIN_LEAK_RATE, leak_rate, MAX_LEAK_RATE);
+ ntp_limit_interval = CLAMP(MIN_LIMIT_INTERVAL, interval, MAX_LIMIT_INTERVAL);
}
if (CNF_GetCommandRateLimit(&interval, &burst, &leak_rate)) {
@@ -325,7 +330,7 @@ CLG_Initialise(void)
active = !CNF_GetNoClientLog();
if (!active) {
if (ntp_leak_rate || cmd_leak_rate)
- LOG_FATAL(LOGF_ClientLog, "ratelimit cannot be used with noclientlog");
+ LOG_FATAL("ratelimit cannot be used with noclientlog");
return;
}
@@ -470,7 +475,7 @@ CLG_LogNTPAccess(IPAddr *client, struct timespec *now)
record->flags & FLAG_NTP_DROPPED ?
&record->ntp_timeout_rate : &record->ntp_rate);
- DEBUG_LOG(LOGF_ClientLog, "NTP hits %"PRIu32" rate %d trate %d tokens %d",
+ DEBUG_LOG("NTP hits %"PRIu32" rate %d trate %d tokens %d",
record->ntp_hits, record->ntp_rate, record->ntp_timeout_rate,
record->ntp_tokens);
@@ -494,7 +499,7 @@ CLG_LogCommandAccess(IPAddr *client, struct timespec *now)
&record->cmd_tokens, max_cmd_tokens, cmd_token_shift,
&record->cmd_rate);
- DEBUG_LOG(LOGF_ClientLog, "Cmd hits %"PRIu32" rate %d tokens %d",
+ DEBUG_LOG("Cmd hits %"PRIu32" rate %d tokens %d",
record->cmd_hits, record->cmd_rate, record->cmd_tokens);
return get_index(record);
@@ -607,6 +612,14 @@ void CLG_GetNtpTimestamps(int index, NTP_int64 **rx_ts, NTP_int64 **tx_ts)
/* ================================================== */
int
+CLG_GetNtpMinPoll(void)
+{
+ return ntp_limit_interval;
+}
+
+/* ================================================== */
+
+int
CLG_GetNumberOfIndices(void)
{
if (!active)
diff --git a/clientlog.h b/clientlog.h
index 337b4d8..552c767 100644
--- a/clientlog.h
+++ b/clientlog.h
@@ -39,6 +39,7 @@ extern int CLG_LogCommandAccess(IPAddr *client, struct timespec *now);
extern int CLG_LimitNTPResponseRate(int index);
extern int CLG_LimitCommandResponseRate(int index);
extern void CLG_GetNtpTimestamps(int index, NTP_int64 **rx_ts, NTP_int64 **tx_ts);
+extern int CLG_GetNtpMinPoll(void);
/* And some reporting functions, for use by chronyc. */
diff --git a/cmdmon.c b/cmdmon.c
index 00e9f4e..4ed2189 100644
--- a/cmdmon.c
+++ b/cmdmon.c
@@ -136,6 +136,8 @@ static const char permissions[] = {
PERMIT_AUTH, /* NTP_DATA */
PERMIT_AUTH, /* ADD_SERVER2 */
PERMIT_AUTH, /* ADD_PEER2 */
+ PERMIT_AUTH, /* ADD_SERVER3 */
+ PERMIT_AUTH, /* ADD_PEER3 */
};
/* ================================================== */
@@ -161,7 +163,7 @@ prepare_socket(int family, int port_number)
sock_fd = socket(family, SOCK_DGRAM, 0);
if (sock_fd < 0) {
- LOG(LOGS_ERR, LOGF_CmdMon, "Could not open %s command socket : %s",
+ LOG(LOGS_ERR, "Could not open %s command socket : %s",
UTI_SockaddrFamilyToString(family), strerror(errno));
return -1;
}
@@ -172,14 +174,14 @@ prepare_socket(int family, int port_number)
if (family != AF_UNIX) {
/* Allow reuse of port number */
if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on_off, sizeof(on_off)) < 0) {
- LOG(LOGS_ERR, LOGF_CmdMon, "Could not set reuseaddr socket options");
+ LOG(LOGS_ERR, "Could not set reuseaddr socket options");
/* Don't quit - we might survive anyway */
}
#ifdef IP_FREEBIND
/* Allow binding to address that doesn't exist yet */
if (setsockopt(sock_fd, IPPROTO_IP, IP_FREEBIND, (char *)&on_off, sizeof(on_off)) < 0) {
- LOG(LOGS_ERR, LOGF_CmdMon, "Could not set free bind socket option");
+ LOG(LOGS_ERR, "Could not set free bind socket option");
}
#endif
@@ -188,7 +190,7 @@ prepare_socket(int family, int port_number)
#ifdef IPV6_V6ONLY
/* Receive IPv6 packets only */
if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on_off, sizeof(on_off)) < 0) {
- LOG(LOGS_ERR, LOGF_CmdMon, "Could not request IPV6_V6ONLY socket option");
+ LOG(LOGS_ERR, "Could not request IPV6_V6ONLY socket option");
}
#endif
}
@@ -230,7 +232,7 @@ prepare_socket(int family, int port_number)
my_addr.un.sun_family = family;
if (snprintf(my_addr.un.sun_path, sizeof (my_addr.un.sun_path), "%s",
CNF_GetBindCommandPath()) >= sizeof (my_addr.un.sun_path))
- LOG_FATAL(LOGF_CmdMon, "Unix socket path too long");
+ LOG_FATAL("Unix socket path too long");
unlink(my_addr.un.sun_path);
break;
default:
@@ -238,7 +240,7 @@ prepare_socket(int family, int port_number)
}
if (bind(sock_fd, &my_addr.sa, my_addr_len) < 0) {
- LOG(LOGS_ERR, LOGF_CmdMon, "Could not bind %s command socket : %s",
+ LOG(LOGS_ERR, "Could not bind %s command socket : %s",
UTI_SockaddrFamilyToString(family), strerror(errno));
close(sock_fd);
return -1;
@@ -315,7 +317,7 @@ CAM_Initialise(int family)
&& sock_fd6 < 0
#endif
) {
- LOG_FATAL(LOGF_CmdMon, "Could not open any command socket");
+ LOG_FATAL("Could not open any command socket");
}
access_auth_table = ADF_CreateTable();
@@ -396,12 +398,12 @@ transmit_reply(CMD_Reply *msg, union sockaddr_all *where_to)
&where_to->sa, addrlen);
if (status < 0) {
- DEBUG_LOG(LOGF_CmdMon, "Could not send to %s fd %d : %s",
+ DEBUG_LOG("Could not send to %s fd %d : %s",
UTI_SockaddrToString(&where_to->sa), sock_fd, strerror(errno));
return;
}
- DEBUG_LOG(LOGF_CmdMon, "Sent %d bytes to %s fd %d", status,
+ DEBUG_LOG("Sent %d bytes to %s fd %d", status,
UTI_SockaddrToString(&where_to->sa), sock_fd);
}
@@ -568,14 +570,13 @@ static void
handle_settime(CMD_Request *rx_message, CMD_Reply *tx_message)
{
struct timespec ts;
- long offset_cs;
- double dfreq_ppm, new_afreq_ppm;
+ double offset, dfreq_ppm, new_afreq_ppm;
UTI_TimespecNetworkToHost(&rx_message->data.settime.ts, &ts);
if (!MNL_IsEnabled()) {
tx_message->status = htons(STT_NOTENABLED);
- } else if (MNL_AcceptTimestamp(&ts, &offset_cs, &dfreq_ppm, &new_afreq_ppm)) {
- tx_message->reply = htons(RPY_MANUAL_TIMESTAMP);
- tx_message->data.manual_timestamp.centiseconds = htonl((int32_t)offset_cs);
+ } else if (MNL_AcceptTimestamp(&ts, &offset, &dfreq_ppm, &new_afreq_ppm)) {
+ tx_message->reply = htons(RPY_MANUAL_TIMESTAMP2);
+ tx_message->data.manual_timestamp.offset = UTI_FloatHostToNetwork(offset);
tx_message->data.manual_timestamp.dfreq_ppm = UTI_FloatHostToNetwork(dfreq_ppm);
tx_message->data.manual_timestamp.new_afreq_ppm = UTI_FloatHostToNetwork(new_afreq_ppm);
} else {
@@ -792,6 +793,8 @@ 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);
params.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.online = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_ONLINE ? 1 : 0;
@@ -874,7 +877,7 @@ handle_dfreq(CMD_Request *rx_message, CMD_Reply *tx_message)
double dfreq;
dfreq = UTI_FloatNetworkToHost(rx_message->data.dfreq.dfreq);
LCL_AccumulateDeltaFrequency(dfreq * 1.0e-6);
- LOG(LOGS_INFO, LOGF_CmdMon, "Accumulated delta freq of %.3fppm", dfreq);
+ LOG(LOGS_INFO, "Accumulated delta freq of %.3fppm", dfreq);
}
/* ================================================== */
@@ -887,7 +890,7 @@ handle_doffset(CMD_Request *rx_message, CMD_Reply *tx_message)
sec = (int32_t)ntohl(rx_message->data.doffset.sec);
usec = (int32_t)ntohl(rx_message->data.doffset.usec);
doffset = (double) sec + 1.0e-6 * (double) usec;
- LOG(LOGS_INFO, LOGF_CmdMon, "Accumulated delta offset of %.6f seconds", doffset);
+ LOG(LOGS_INFO, "Accumulated delta offset of %.6f seconds", doffset);
LCL_AccumulateOffset(doffset, 0.0);
}
@@ -1258,14 +1261,14 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
&where_from.sa, &from_length);
if (status < 0) {
- LOG(LOGS_WARN, LOGF_CmdMon, "Error [%s] reading from control socket %d",
+ LOG(LOGS_WARN, "Error [%s] reading from control socket %d",
strerror(errno), sock_fd);
return;
}
if (from_length > sizeof (where_from) ||
from_length <= sizeof (where_from.sa.sa_family)) {
- DEBUG_LOG(LOGF_CmdMon, "Read command packet without source address");
+ DEBUG_LOG("Read command packet without source address");
return;
}
@@ -1300,7 +1303,7 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
assert(0);
}
- DEBUG_LOG(LOGF_CmdMon, "Received %d bytes from %s fd %d",
+ DEBUG_LOG("Received %d bytes from %s fd %d",
status, UTI_SockaddrToString(&where_from.sa), sock_fd);
if (!(localhost || ADF_IsAllowed(access_auth_table, &remote_ip))) {
@@ -1319,7 +1322,7 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
/* We don't know how to process anything like this or an error reply
would be larger than the request */
- DEBUG_LOG(LOGF_CmdMon, "Command packet dropped");
+ DEBUG_LOG("Command packet dropped");
return;
}
@@ -1341,7 +1344,7 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
tx_message.pad5 = 0;
if (rx_message.version != PROTO_VERSION_NUMBER) {
- DEBUG_LOG(LOGF_CmdMon, "Command packet has invalid version (%d != %d)",
+ DEBUG_LOG("Command packet has invalid version (%d != %d)",
rx_message.version, PROTO_VERSION_NUMBER);
if (rx_message.version >= PROTO_VERSION_MISMATCH_COMPAT_SERVER) {
@@ -1353,7 +1356,7 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
if (rx_command >= N_REQUEST_TYPES ||
expected_length < (int)offsetof(CMD_Request, data)) {
- DEBUG_LOG(LOGF_CmdMon, "Command packet has invalid command %d", rx_command);
+ DEBUG_LOG("Command packet has invalid command %d", rx_command);
tx_message.status = htons(STT_INVALID);
transmit_reply(&tx_message, &where_from);
@@ -1361,7 +1364,7 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
}
if (read_length < expected_length) {
- DEBUG_LOG(LOGF_CmdMon, "Command packet is too short (%d < %d)", read_length,
+ DEBUG_LOG("Command packet is too short (%d < %d)", read_length,
expected_length);
tx_message.status = htons(STT_BADPKTLENGTH);
@@ -1376,7 +1379,7 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
/* Don't reply to all requests from hosts other than localhost if the rate
is excessive */
if (!localhost && log_index >= 0 && CLG_LimitCommandResponseRate(log_index)) {
- DEBUG_LOG(LOGF_CmdMon, "Command packet discarded to limit response rate");
+ DEBUG_LOG("Command packet discarded to limit response rate");
return;
}
@@ -1526,11 +1529,11 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
handle_cmdaccheck(&rx_message, &tx_message);
break;
- case REQ_ADD_SERVER2:
+ case REQ_ADD_SERVER3:
handle_add_source(NTP_SERVER, &rx_message, &tx_message);
break;
- case REQ_ADD_PEER2:
+ case REQ_ADD_PEER3:
handle_add_source(NTP_PEER, &rx_message, &tx_message);
break;
@@ -1627,7 +1630,7 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
break;
default:
- DEBUG_LOG(LOGF_CmdMon, "Unhandled command %d", rx_command);
+ DEBUG_LOG("Unhandled command %d", rx_command);
tx_message.status = htons(STT_FAILED);
break;
}
diff --git a/cmdparse.c b/cmdparse.c
index 700da32..c4e26bf 100644
--- a/cmdparse.c
+++ b/cmdparse.c
@@ -64,6 +64,8 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
src->params.max_delay = SRC_DEFAULT_MAXDELAY;
src->params.max_delay_ratio = SRC_DEFAULT_MAXDELAYRATIO;
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;
hostname = line;
@@ -98,6 +100,9 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
if (sscanf(line, "%"SCNu32"%n", &src->params.authkey, &n) != 1 ||
src->params.authkey == INACTIVE_AUTHKEY)
return 0;
+ } else if (!strcasecmp(cmd, "asymmetry")) {
+ if (sscanf(line, "%lf%n", &src->params.asymmetry, &n) != 1)
+ return 0;
} else if (!strcasecmp(cmd, "maxdelay")) {
if (sscanf(line, "%lf%n", &src->params.max_delay, &n) != 1)
return 0;
@@ -116,6 +121,9 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "maxsources")) {
if (sscanf(line, "%d%n", &src->params.max_sources, &n) != 1)
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")) {
if (sscanf(line, "%d%n", &src->params.minpoll, &n) != 1)
return 0;
diff --git a/conf.c b/conf.c
index 9aa034c..232a890 100644
--- a/conf.c
+++ b/conf.c
@@ -79,7 +79,7 @@ static void parse_tempcomp(char *);
static int restarted = 0;
static char *rtc_device;
static int acquisition_port = -1;
-static int ntp_port = 123;
+static int ntp_port = NTP_PORT;
static char *keys_file = NULL;
static char *drift_file = NULL;
static char *rtc_file = NULL;
@@ -104,7 +104,6 @@ static int do_log_tracking = 0;
static int do_log_rtc = 0;
static int do_log_refclocks = 0;
static int do_log_tempcomp = 0;
-static int do_dump_on_exit = 0;
static int log_banner = 32;
static char *logdir;
static char *dumpdir;
@@ -271,7 +270,7 @@ static const char *processed_command;
static void
command_parse_error(void)
{
- LOG_FATAL(LOGF_Configure, "Could not parse %s directive at line %d%s%s",
+ LOG_FATAL("Could not parse %s directive at line %d%s%s",
processed_command, line_number, processed_file ? " in file " : "",
processed_file ? processed_file : "");
}
@@ -281,7 +280,7 @@ command_parse_error(void)
static void
other_parse_error(const char *message)
{
- LOG_FATAL(LOGF_Configure, "%s at line %d%s%s",
+ LOG_FATAL("%s at line %d%s%s",
message, line_number, processed_file ? " in file " : "",
processed_file ? processed_file : "");
}
@@ -314,7 +313,7 @@ check_number_of_args(char *line, int num)
num -= get_number_of_args(line);
if (num) {
- LOG_FATAL(LOGF_Configure, "%s arguments for %s directive at line %d%s%s",
+ LOG_FATAL("%s arguments for %s directive at line %d%s%s",
num > 0 ? "Missing" : "Too many",
processed_command, line_number, processed_file ? " in file " : "",
processed_file ? processed_file : "");
@@ -324,7 +323,7 @@ check_number_of_args(char *line, int num)
/* ================================================== */
void
-CNF_Initialise(int r)
+CNF_Initialise(int r, int client_only)
{
restarted = r;
@@ -340,11 +339,18 @@ CNF_Initialise(int r)
dumpdir = Strdup("");
logdir = Strdup("");
- bind_cmd_path = Strdup(DEFAULT_COMMAND_SOCKET);
- pidfile = Strdup(DEFAULT_PID_FILE);
rtc_device = Strdup(DEFAULT_RTC_DEVICE);
hwclock_file = Strdup(DEFAULT_HWCLOCK_FILE);
user = Strdup(DEFAULT_USER);
+
+ if (client_only) {
+ cmd_port = ntp_port = 0;
+ bind_cmd_path = Strdup("");
+ pidfile = Strdup("");
+ } else {
+ bind_cmd_path = Strdup(DEFAULT_COMMAND_SOCKET);
+ pidfile = Strdup(DEFAULT_PID_FILE);
+ }
}
/* ================================================== */
@@ -398,12 +404,12 @@ CNF_ReadFile(const char *filename)
in = fopen(filename, "r");
if (!in) {
- LOG_FATAL(LOGF_Configure, "Could not open configuration file %s : %s",
+ LOG_FATAL("Could not open configuration file %s : %s",
filename, strerror(errno));
return;
}
- DEBUG_LOG(LOGF_Configure, "Reading %s", filename);
+ DEBUG_LOG("Reading %s", filename);
for (i = 1; fgets(line, sizeof(line), in); i++) {
CNF_ParseLine(filename, i, line);
@@ -469,7 +475,7 @@ CNF_ParseLine(const char *filename, int number, char *line)
} else if (!strcasecmp(command, "dumpdir")) {
parse_string(p, &dumpdir);
} else if (!strcasecmp(command, "dumponexit")) {
- do_dump_on_exit = parse_null(p);
+ /* Silently ignored */
} else if (!strcasecmp(command, "fallbackdrift")) {
parse_fallbackdrift(p);
} else if (!strcasecmp(command, "hwclockfile")) {
@@ -569,7 +575,7 @@ CNF_ParseLine(const char *filename, int number, char *line)
!strcasecmp(command, "generatecommandkey") ||
!strcasecmp(command, "linux_freq_scale") ||
!strcasecmp(command, "linux_hz")) {
- LOG(LOGS_WARN, LOGF_Configure, "%s directive is no longer supported", command);
+ LOG(LOGS_WARN, "%s directive is no longer supported", command);
} else {
other_parse_error("Invalid command");
}
@@ -675,9 +681,9 @@ static void
parse_refclock(char *line)
{
int n, poll, dpoll, filter_length, pps_rate, min_samples, max_samples, sel_options;
- int max_lock_age;
+ int max_lock_age, pps_forced;
uint32_t ref_id, lock_ref_id;
- double offset, delay, precision, max_dispersion;
+ double offset, delay, precision, max_dispersion, pulse_width;
char *p, *cmd, *name, *param;
unsigned char ref[5];
RefclockParameters *refclock;
@@ -685,6 +691,7 @@ parse_refclock(char *line)
poll = 4;
dpoll = 0;
filter_length = 64;
+ pps_forced = 0;
pps_rate = 0;
min_samples = SRC_DEFAULT_MINSAMPLES;
max_samples = SRC_DEFAULT_MAXSAMPLES;
@@ -693,6 +700,7 @@ parse_refclock(char *line)
delay = 1e-9;
precision = 0.0;
max_dispersion = 0.0;
+ pulse_width = 0.0;
ref_id = 0;
max_lock_age = 2;
lock_ref_id = 0;
@@ -757,12 +765,18 @@ parse_refclock(char *line)
} else if (!strcasecmp(cmd, "delay")) {
if (sscanf(line, "%lf%n", &delay, &n) != 1)
break;
+ } else if (!strcasecmp(cmd, "pps")) {
+ n = 0;
+ pps_forced = 1;
} else if (!strcasecmp(cmd, "precision")) {
if (sscanf(line, "%lf%n", &precision, &n) != 1)
break;
} else if (!strcasecmp(cmd, "maxdispersion")) {
if (sscanf(line, "%lf%n", &max_dispersion, &n) != 1)
break;
+ } else if (!strcasecmp(cmd, "width")) {
+ if (sscanf(line, "%lf%n", &pulse_width, &n) != 1)
+ break;
} else if (!strcasecmp(cmd, "noselect")) {
n = 0;
sel_options |= SRC_SELECT_NOSELECT;
@@ -792,6 +806,7 @@ parse_refclock(char *line)
refclock->driver_poll = dpoll;
refclock->poll = poll;
refclock->filter_length = filter_length;
+ refclock->pps_forced = pps_forced;
refclock->pps_rate = pps_rate;
refclock->min_samples = min_samples;
refclock->max_samples = max_samples;
@@ -800,6 +815,7 @@ parse_refclock(char *line)
refclock->delay = delay;
refclock->precision = precision;
refclock->max_dispersion = max_dispersion;
+ refclock->pulse_width = pulse_width;
refclock->ref_id = ref_id;
refclock->max_lock_age = max_lock_age;
refclock->lock_ref_id = lock_ref_id;
@@ -878,7 +894,7 @@ parse_initstepslew(char *line)
if (DNS_Name2IPAddress(hostname, &ip_addr, 1) == DNS_Success) {
ARR_AppendElement(init_sources, &ip_addr);
} else {
- LOG(LOGS_WARN, LOGF_Configure, "Could not resolve address of initstepslew server %s", hostname);
+ LOG(LOGS_WARN, "Could not resolve address of initstepslew server %s", hostname);
}
}
}
@@ -1055,7 +1071,7 @@ parse_allow_deny(char *line, ARR_Instance restrictions, int allow)
}
} else {
- if (DNS_Name2IPAddress(p, &ip_addr, 1) == DNS_Success) {
+ if (!slashpos && DNS_Name2IPAddress(p, &ip_addr, 1) == DNS_Success) {
new_node = (AllowDeny *)ARR_GetNewElement(restrictions);
new_node->allow = allow;
new_node->all = all;
@@ -1170,7 +1186,7 @@ parse_broadcast(char *line)
}
} else {
/* default port */
- port = 123;
+ port = NTP_PORT;
}
destination = (NTP_Broadcast_Destination *)ARR_GetNewElement(broadcasts);
@@ -1250,7 +1266,7 @@ static void
parse_hwtimestamp(char *line)
{
CNF_HwTsInterface *iface;
- char *p;
+ char *p, filter[5];
int n;
if (!*line) {
@@ -1265,6 +1281,7 @@ parse_hwtimestamp(char *line)
iface->name = Strdup(p);
iface->minpoll = 0;
iface->nocrossts = 0;
+ iface->rxfilter = CNF_HWTS_RXFILTER_ANY;
iface->precision = 100.0e-9;
iface->tx_comp = 0.0;
iface->rx_comp = 0.0;
@@ -1284,6 +1301,17 @@ parse_hwtimestamp(char *line)
} else if (!strcasecmp(p, "txcomp")) {
if (sscanf(line, "%lf%n", &iface->tx_comp, &n) != 1)
break;
+ } else if (!strcasecmp(p, "rxfilter")) {
+ if (sscanf(line, "%4s%n", filter, &n) != 1)
+ break;
+ if (!strcasecmp(filter, "none"))
+ iface->rxfilter = CNF_HWTS_RXFILTER_NONE;
+ else if (!strcasecmp(filter, "ntp"))
+ iface->rxfilter = CNF_HWTS_RXFILTER_NTP;
+ else if (!strcasecmp(filter, "all"))
+ iface->rxfilter = CNF_HWTS_RXFILTER_ALL;
+ else
+ break;
} else if (!strcasecmp(p, "nocrossts")) {
n = 0;
iface->nocrossts = 1;
@@ -1303,11 +1331,19 @@ parse_include(char *line)
{
glob_t gl;
size_t i;
+ int r;
check_number_of_args(line, 1);
- if (glob(line, 0, NULL, &gl)) {
- DEBUG_LOG(LOGF_Configure, "glob of %s failed", line);
+ if ((r = glob(line,
+#ifdef GLOB_NOMAGIC
+ GLOB_NOMAGIC |
+#endif
+ GLOB_ERR, NULL, &gl)) != 0) {
+ if (r != GLOB_NOMATCH)
+ LOG_FATAL("Could not search for files matching %s", line);
+
+ DEBUG_LOG("glob of %s failed", line);
return;
}
@@ -1333,7 +1369,7 @@ CNF_CreateDirs(uid_t uid, gid_t gid)
existed. It MUST NOT be accessible by others as permissions on Unix
domain sockets are ignored on some systems (e.g. Solaris). */
if (!UTI_CheckDirPermissions(dir, 0770, uid, gid)) {
- LOG(LOGS_WARN, LOGF_Configure, "Disabled command socket %s", bind_cmd_path);
+ LOG(LOGS_WARN, "Disabled command socket %s", bind_cmd_path);
bind_cmd_path[0] = '\0';
}
@@ -1552,14 +1588,6 @@ CNF_GetRtcDevice(void)
/* ================================================== */
-int
-CNF_GetDumpOnExit(void)
-{
- return do_dump_on_exit;
-}
-
-/* ================================================== */
-
double
CNF_GetMaxUpdateSkew(void)
{
@@ -1740,7 +1768,7 @@ CNF_SetupAccessRestrictions(void)
node = ARR_GetElement(ntp_restrictions, i);
status = NCR_AddAccessRestriction(&node->ip, node->subnet_bits, node->allow, node->all);
if (!status) {
- LOG_FATAL(LOGF_Configure, "Bad subnet in %s/%d", UTI_IPToString(&node->ip), node->subnet_bits);
+ LOG_FATAL("Bad subnet in %s/%d", UTI_IPToString(&node->ip), node->subnet_bits);
}
}
@@ -1748,7 +1776,7 @@ CNF_SetupAccessRestrictions(void)
node = ARR_GetElement(cmd_restrictions, i);
status = CAM_AddAccessRestriction(&node->ip, node->subnet_bits, node->allow, node->all);
if (!status) {
- LOG_FATAL(LOGF_Configure, "Bad subnet in %s/%d", UTI_IPToString(&node->ip), node->subnet_bits);
+ LOG_FATAL("Bad subnet in %s/%d", UTI_IPToString(&node->ip), node->subnet_bits);
}
}
diff --git a/conf.h b/conf.h
index 7ff1dba..25c98e1 100644
--- a/conf.h
+++ b/conf.h
@@ -31,7 +31,7 @@
#include "addressing.h"
#include "reference.h"
-extern void CNF_Initialise(int restarted);
+extern void CNF_Initialise(int restarted, int client_only);
extern void CNF_Finalise(void);
extern char *CNF_GetRtcDevice(void);
@@ -60,7 +60,6 @@ extern int CNF_GetLogRefclocks(void);
extern int CNF_GetLogTempComp(void);
extern char *CNF_GetKeysFile(void);
extern char *CNF_GetRtcFile(void);
-extern int CNF_GetDumpOnExit(void);
extern int CNF_GetManualEnabled(void);
extern int CNF_GetCommandPort(void);
extern int CNF_GetRtcOnUtc(void);
@@ -119,10 +118,18 @@ extern char *CNF_GetHwclockFile(void);
extern int CNF_GetInitSources(void);
extern double CNF_GetInitStepThreshold(void);
+typedef enum {
+ CNF_HWTS_RXFILTER_ANY,
+ CNF_HWTS_RXFILTER_NONE,
+ CNF_HWTS_RXFILTER_NTP,
+ CNF_HWTS_RXFILTER_ALL,
+} CNF_HwTs_RxFilter;
+
typedef struct {
char *name;
int minpoll;
int nocrossts;
+ CNF_HwTs_RxFilter rxfilter;
double precision;
double tx_comp;
double rx_comp;
diff --git a/configure b/configure
index b4a33c3..45eddf1 100755
--- a/configure
+++ b/configure
@@ -428,6 +428,15 @@ case $OPERATINGSYSTEM in
add_def FEAT_PRIVDROP
priv_ops="ADJUSTTIME SETTIME BINDSOCKET"
fi
+ major=`echo $VERSION | cut -d. -f1`
+ # ntp_adjtime is not available in macOS 10.12 (Darwin 16.x.x) and earlier
+ if [ $major -gt "16" ]; then
+ add_def HAVE_MACOS_SYS_TIMEX
+ EXTRA_OBJECTS="$EXTRA_OBJECTS sys_generic.o sys_netbsd.o sys_timex.o"
+ if [ $feat_droproot = "1" ]; then
+ priv_ops="$priv_ops ADJUSTTIMEX"
+ fi
+ fi
echo "Configuring for macOS (" $SYSTEM "macOS version" $VERSION ")"
;;
SunOS)
@@ -490,14 +499,16 @@ MYCPPFLAGS="$CPPFLAGS"
MYLDFLAGS="$LDFLAGS"
if [ "x$MYCC" = "x" ]; then
- MYCC=gcc
- if ! test_code "$MYCC" '' '' '' ''; then
- MYCC=cc
- if ! test_code "$MYCC" '' '' '' ''; then
+ for cc in gcc clang cc ""; do
+ if [ "x$cc" = "x" ]; then
echo "error: no C compiler found"
exit 1
fi
- fi
+ MYCC=$cc
+ if test_code "$MYCC" '' '' '' ''; then
+ break
+ fi
+ done
else
if ! test_code "$MYCC" '' '' '' ''; then
echo "error: C compiler $MYCC cannot create executables"
@@ -507,9 +518,25 @@ fi
if [ "x$MYCFLAGS" = "x" ]; then
MYCFLAGS="-O2 -g"
+
+ TESTCFLAGS="-D_FORTIFY_SOURCE=2 -fPIE"
+ TESTLDFLAGS="-pie -Wl,-z,relro,-z,now"
+ if test_code 'hardening compiler options' '' "$TESTCFLAGS" "$TESTLDFLAGS" ''; then
+ MYCFLAGS="$MYCFLAGS $TESTCFLAGS"
+ MYLDFLAGS="$MYLDFLAGS $TESTLDFLAGS"
+ fi
+ TESTCFLAGS="-fstack-protector-strong --param=ssp-buffer-size=4"
+ if test_code '-fstack-protector-strong' '' "$TESTCFLAGS" '' ''; then
+ MYCFLAGS="$MYCFLAGS $TESTCFLAGS"
+ else
+ TESTCFLAGS="-fstack-protector --param=ssp-buffer-size=4"
+ if test_code '-fstack-protector' '' "$TESTCFLAGS" '' ''; then
+ MYCFLAGS="$MYCFLAGS $TESTCFLAGS"
+ fi
+ fi
fi
-if [ "x$MYCC" = "xgcc" ]; then
+if [ "x$MYCC" = "xgcc" ] || [ "x$MYCC" = "xclang" ]; then
MYCFLAGS="$MYCFLAGS -Wmissing-prototypes -Wall"
fi
@@ -631,6 +658,11 @@ if test_code 'arc4random_buf()' 'stdlib.h' '' '' 'arc4random_buf(NULL, 0);'; the
add_def HAVE_ARC4RANDOM
fi
+if test_code 'getrandom()' 'stdlib.h sys/random.h' '' '' \
+ 'return getrandom(NULL, 256, 0);'; then
+ add_def HAVE_GETRANDOM
+fi
+
RECVMMSG_CODE='
struct mmsghdr hdr;
return !recvmmsg(0, &hdr, 1, MSG_DONTWAIT, 0);'
@@ -658,6 +690,17 @@ if [ $feat_timestamping = "1" ] && [ $try_timestamping = "1" ] &&
then
add_def HAVE_LINUX_TIMESTAMPING
EXTRA_OBJECTS="$EXTRA_OBJECTS hwclock.o ntp_io_linux.o"
+
+ if test_code 'other timestamping options' \
+ 'sys/types.h sys/socket.h linux/net_tstamp.h' '' '' '
+ struct scm_ts_pktinfo pktinfo;
+ pktinfo.if_index = pktinfo.pkt_length = 0;
+ return pktinfo.if_index + pktinfo.pkt_length + HWTSTAMP_FILTER_NTP_ALL +
+ SOF_TIMESTAMPING_OPT_PKTINFO + SOF_TIMESTAMPING_OPT_TX_SWHW;'; then
+ add_def HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP 1
+ add_def HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO 1
+ add_def HAVE_LINUX_TIMESTAMPING_OPT_TX_SWHW 1
+ fi
fi
timepps_h=""
@@ -709,7 +752,7 @@ then
# NAME2IPADDRESS shouldn't be enabled with other operations as the helper
# process works on one request at the time and the async resolver could
# block the main thread
- priv_ops="NAME2IPADDRESS"
+ priv_ops="NAME2IPADDRESS RELOADDNS"
EXTRA_LIBS="$EXTRA_LIBS -lseccomp"
fi
@@ -734,6 +777,8 @@ if [ $feat_refclock = "1" ] && [ $feat_phc = "1" ] && [ $try_phc = "1" ] && \
test_code '<linux/ptp_clock.h>' 'sys/ioctl.h linux/ptp_clock.h' '' '' \
'ioctl(1, PTP_CLOCK_GETCAPS + PTP_SYS_OFFSET, 0);'
then
+ grep 'HAVE_LINUX_TIMESTAMPING' config.h > /dev/null ||
+ EXTRA_OBJECTS="$EXTRA_OBJECTS hwclock.o"
add_def FEAT_PHC
fi
diff --git a/doc/chrony.conf.adoc b/doc/chrony.conf.adoc
index 7a3bedb..5c85959 100644
--- a/doc/chrony.conf.adoc
+++ b/doc/chrony.conf.adoc
@@ -2,6 +2,7 @@
//
// Copyright (C) Richard P. Curnow 1997-2003
// Copyright (C) Stephen Wadeley 2016
+// Copyright (C) Bryan Christianson 2017
// Copyright (C) Miroslav Lichvar 2009-2017
//
// This program is free software; you can redistribute it and/or modify
@@ -115,13 +116,25 @@ round-trip delay of 0.3 seconds or more should be ignored. The default value is
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
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
-only in the *server* directive when not in the interleaved mode.
+maxdelayratio times the minimum delay, it will be rejected.
*maxdelaydevratio* _ratio_:::
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
the previous measurements that is greater than the specified ratio, it will be
rejected. The default is 10.0.
+*mindelay* _delay_:::
+This options 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 options 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_:::
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
@@ -178,10 +191,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
someone sending requests with a spoofed source address).
+
-With longer polling intervals, it is recommended to combine the *xleave* option
-with the *presend* option in order to shorten the interval in which the server
-has to keep the state to be able to respond in the interleaved mode. The
-shorter interval also improves accuracy of the measured offset and delay.
+The *xleave* option can be combined with the *presend* option in order to
+shorten the interval in which the server has to keep the state to be able to
+respond in the interleaved mode.
*polltarget* _target_:::
Target number of measurements to use for the regression algorithm which
*chronyd* will try to maintain by adjusting the polling interval between
@@ -344,46 +356,55 @@ for *initstepslew* to finish before exiting. This is useful to prevent programs
started in the boot sequence after *chronyd* from reading the clock before it
has been stepped.
-[[refclock]]*refclock* _driver_ _parameter_ [_option_]...::
+[[refclock]]*refclock* _driver_ _parameter_[:__option__,...] [_option_]...::
The *refclock* directive specifies a hardware reference clock to be used as a
time source. It has two mandatory parameters, a driver name and a
-driver-specific parameter.
+driver-specific parameter. The two parameters are followed by zero or more
+refclock options. Some drivers have special options, which can be appended to
+the driver-specific parameter (separated by the *:* and *,* characters).
+
-There are currently four drivers included:
+There are four drivers included in *chronyd*:
+
*PPS*:::
Driver for the kernel PPS (pulse per second) API. The parameter is the path to
-the PPS device (typically _/dev/pps?_). The assert events are used for
-synchronisation by default. String *:clear* can be appended to the path to use
-the clear events instead.
+the PPS device (typically _/dev/pps?_). As PPS refclocks do not supply full
+time, another time source (e.g. NTP server or non-PPS refclock) is needed to
+complete samples from the PPS refclock. An alternative is to enable the
+<<local,*local*>> directive to allow synchronisation with some unknown but
+constant offset. The driver supports the following option:
+
-As PPS refclocks don't supply full time, *chronyd* needs to be configured with
-another time source (NTP or non-PPS refclock) in order to complete samples from
-the PPS refclock. An alternative is to enable the <<local,*local*>> directive
-to allow synchronisation with some unknown but constant offset.
-For example:
+*clear*::::
+By default, the PPS refclock uses assert events (rising edge) for
+synchronisation. With this option, it will use clear events (falling edge)
+instead.
++
+:::
+Examples:
+
----
-refclock PPS /dev/pps0 lock NMEA
+refclock PPS /dev/pps0 lock NMEA refid GPS
refclock SHM 0 offset 0.5 delay 0.2 refid NMEA noselect
+refclock PPS /dev/pps1:clear refid GPS2
----
+
*SHM*:::
NTP shared memory driver. This driver uses a shared memory segment to receive
-samples from another process. The parameter is the number of the shared memory
-segment, typically 0, 1, 2 or 3. For example:
+samples from another process (e.g. *gpsd*). The parameter is the number of the
+shared memory segment, typically a small number like 0, 1, 2, or 3. The driver
+supports the following option:
+
-----
-refclock SHM 1 poll 3 refid GPS1
-----
+*perm*=_mode_::::
+This option specifies the permissions of the shared memory segment created by
+*chronyd*. They are specified as a numeric mode. The default value is 0600
+(read-write access for owner only).
+:::
+
-A driver option in form of *:perm=NNN* can be appended to the segment number to
-create the segment with permissions other than the default 0600.
+Examples:
+
-Examples of applications that can be used as SHM refclocks are
-http://www.catb.org/gpsd/[*gpsd*],
-http://www.buzzard.me.uk/jonathan/radioclock.html[*radioclk*], and
-https://www.vanheusden.com/time/omnisync/[*omnisync*].
+----
+refclock SHM 0 poll 3 refid GPS1
+refclock SHM 1:perm=0644 refid GPS2
+----
+
*SOCK*:::
Unix domain socket driver. It is similar to the SHM driver, but samples are
@@ -404,18 +425,44 @@ refclock SOCK /var/run/chrony.ttyS0.sock
+
*PHC*:::
PTP hardware clock (PHC) driver. The parameter is the path to the device of
-the PTP clock, which for example can be synchronised by *ptp4l* from
-http://linuxptp.sourceforge.net[*linuxptp*]. String *:nocrossts* can be
-appended to the path to disable use of precise cross timestamping. PTP clocks
-are typically kept in TAI instead of UTC, so the *offset* option should be used
-to compensate for the current UTC-TAI offset. For example:
-+
-----
-refclock PHC /dev/ptp0 poll 3 dpoll -2 offset -36
+the PTP clock which should be used as a time source. If the clock is kept in
+TAI instead of UTC (e.g. it is synchronised by a PTP daemon), the current
+UTC-TAI offset needs to be specified by the *offset* option. Alternatively, the
+*pps* refclock option can be enabled to treat the PHC as a PPS refclock, using
+only the sub-second offset for synchronisation. The driver supports the
+following options:
++
+*nocrossts*::::
+This option disables use of precise cross timestamping.
+*extpps*::::
+This option enables a PPS mode in which the PTP clock is timestamping pulses
+of an external PPS signal connected to the clock. The clock does not need to be
+synchronised, but another time source is needed to complete the PPS samples.
+Note that some PTP clocks cannot be configured to timestamp only assert or
+clear events, and it is necessary to use the *width* option to filter wrong
+PPS samples.
+*pin*=_index_::::
+This option specifies the index of the pin to which is connected the PPS
+signal. The default value is 0.
+*channel*=_index_::::
+This option specifies the index of the channel for the PPS mode. The default
+value is 0.
+*clear*::::
+This option enables timestamping of clear events (falling edge) instead of
+assert events (rising edge) in the PPS mode. This may not work with some
+clocks.
+:::
++
+Examples:
++
+----
+refclock PHC /dev/ptp0 poll 0 dpoll -2 offset -37
+refclock PHC /dev/ptp1:nocrossts poll 3 pps
+refclock PHC /dev/ptp2:extpps,pin=1 width 0.2 poll 2
----
+
::
-The *refclock* directive also supports a number of options:
+The *refclock* directive supports the following options:
+
*poll* _poll_:::
Timestamps produced by refclock drivers are not used immediately, but they are
@@ -448,6 +495,17 @@ This option specifies in number of pulses how old can be samples from the
refclock specified by the *lock* option to be paired with the pulses.
Increasing this value is useful when the samples are produced at a lower rate
than the pulses. The default is 2.
+*width* _width_:::
+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
+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
+preferred in order to maximise the allowed error.
+*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
+offset of a whole number of seconds (e.g. it uses TAI instead of UTC). Another
+time source is needed to complete samples from the refclock.
*offset* _offset_:::
This option can be used to compensate for a constant error. The specified
offset (in seconds) is applied to all samples produced by the reference clock.
@@ -459,9 +517,8 @@ 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
nanosecond).
*precision* _precision_:::
-This option sets the refclock precision (in seconds). The default is 1e-6 (1
-microsecond) for SHM refclock, and 1e-9 (1 nanosecond) for SOCK, PPS and PHC
-refclocks.
+This option sets the precision of the reference clock (in seconds). The default
+value is the estimated precision of the system clock.
*maxdispersion* _dispersion_:::
Maximum allowed dispersion for filtered samples (in seconds). Samples with
larger estimated dispersion are ignored. By default, this limit is disabled.
@@ -542,19 +599,18 @@ can be specified.
To compute the rate of gain or loss of time, *chronyd* has to store a
measurement history for each of the time sources it uses.
+
-Certain systems (Linux, FreeBSD, NetBSD, Solaris) have operating system support
-for setting the rate of gain or loss to compensate for known errors. (On Mac OS
-X, *chronyd* must simulate such a capability by periodically slewing the system
-clock forwards or backwards by a suitable amount to compensate for the error
-built up since the previous slew.)
+All supported systems, with the exception of macOS 10.12 and earlier, have
+operating system support for setting the rate of gain or loss to compensate for
+known errors.
+(On macOS 10.12 and earlier, *chronyd* must simulate such a capability by
+periodically slewing the system clock forwards or backwards by a suitable amount
+to compensate for the error built up since the previous slew.)
+
For such systems, it is possible to save the measurement history across
restarts of *chronyd* (assuming no changes are made to the system clock
-behaviour whilst it is not running). If this capability is to be used (via the
-*dumponexit* directive in the configuration file, or the
-<<chronyc.adoc#dump,*dump*>> command in *chronyc*), the *dumpdir* directive
-should be used to define the directory where the measurement histories are
-saved.
+behaviour whilst it is not running). The *dumpdir* directive defines the
+directory where the measurement histories are saved when *chronyd* exits,
+or the <<chronyc.adoc#dump,*dump*>> command in *chronyc* is issued.
+
An example of the directive is:
+
@@ -566,11 +622,6 @@ A source whose IP address is _1.2.3.4_ would have its measurement history saved
in the file _@CHRONYRUNDIR@/1.2.3.4.dat_. History of reference clocks is saved
to files named by their reference ID in form of _refid:XXXXXXXX.dat_.
-[[dumponexit]]*dumponexit*::
-If this directive is present, it indicates that *chronyd* should save the
-measurement history for each of its time sources recorded whenever the program
-exits. (See the <<dumpdir,*dumpdir*>> directive above.)
-
[[maxsamples]]*maxsamples* _samples_::
The *maxsamples* directive sets the default maximum number of samples that
*chronyd* should keep for each source. This setting can be overridden for
@@ -652,8 +703,9 @@ distances are in milliseconds.
[[corrtimeratio]]*corrtimeratio* _ratio_::
When *chronyd* is slewing the system clock to correct an offset, the rate at
-which it is slewing adds to the frequency error of the clock. On Linux,
-FreeBSD, NetBSD and Solaris this rate can be controlled.
+which it is slewing adds to the frequency error of the clock. On all supported
+systems, with the exception of macOS 12 and earlier, this rate can be
+controlled.
+
The *corrtimeratio* directive sets the ratio between the duration in which the
clock is slewed for an average correction according to the source history and
@@ -736,8 +788,8 @@ that error is corrected. There are four options:
When inserting a leap second, the kernel steps the system clock backwards by
one second when the clock gets to 00:00:00 UTC. When deleting a leap second, it
steps forward by one second when the clock gets to 23:59:59 UTC. This is the
-default mode when the system driver supports leap seconds (i.e. on Linux,
-FreeBSD, NetBSD and Solaris).
+default mode when the system driver supports leap seconds (i.e. all supported
+systems with the exception of macOS 12 and earlier).
*step*:::
This is similar to the *system* mode, except the clock is stepped by
*chronyd* instead of the kernel. It can be useful to avoid bugs in the kernel
@@ -792,15 +844,23 @@ clients to safely synchronise with multiple identically configured leap
smearing servers.
[[leapsectz]]*leapsectz* _timezone_::
-This directive is used to set the name of the timezone in the system tz
-database which *chronyd* can use to find out when will the next leap second
-occur. It will periodically check if the times 23:59:59 and 23:59:60 are valid
-on Jun 30 and Dec 31 in the timezone. This typically works with the *right/UTC*
-timezone.
+This directive specifies a timezone in the system tz database which *chronyd*
+can use to determine when will the next leap second occur and what is the
+current offset between TAI and UTC. It will periodically check if 23:59:59 and
+23:59:60 are valid times in the timezone. This typically works with the
+_right/UTC_ timezone.
++
+When a leap second is announced, the timezone needs to be updated at least 12
+hours before the leap second. It is not necessary to restart *chronyd*.
+
-This directive is mainly useful with reference clocks which do not provide
-leap second information. It is not necessary to restart *chronyd* if the tz
-database is updated with a new leap second at least 12 hours before the event.
+This directive is useful with reference clocks and other time sources which do
+not announce leap seconds, or announce them too late for an NTP server to
+forward them to its own clients. Clients of leap smearing servers must not
+use this directive.
++
+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
+kernel, i.e. <<leapsecmode,*leapsecmode*>> is set to *system*.
+
An example of the directive is:
+
@@ -872,7 +932,7 @@ This directive specifies the maximum assumed drift (frequency error) of the
system clock. It limits the frequency adjustment that *chronyd* is allowed to
use to correct the measured drift. It is an additional limit to the maximum
adjustment that can be set by the system driver (100000 ppm on Linux, 500 ppm
-on FreeBSD and NetBSD, 32500 ppm on Solaris).
+on FreeBSD, NetBSD, and macOS 10.13+, 32500 ppm on Solaris).
+
By default, the maximum assumed drift is 500000 ppm, i.e. the adjustment is
limited by the system driver rather than this directive.
@@ -907,14 +967,18 @@ The *maxslewrate* directive sets the maximum rate at which *chronyd* is allowed
to slew the time. It limits the slew rate controlled by the correction time
ratio (which can be set by the <<corrtimeratio,*corrtimeratio*>> directive) and
is effective only on systems where *chronyd* is able to control the rate (i.e.
-Linux, FreeBSD, NetBSD, Solaris).
+all supported systems with the exception of macOS 12 or earlier).
+
-For each system there is a maximum frequency offset of the clock that
-can be set by the driver. On Linux it is 100000 ppm, on FreeBSD and NetBSD
-it is 5000 ppm, and on Solaris it is 32500 ppm. Also, due to a kernel
-limitation, setting *maxslewrate* on FreeBSD and NetBSD to a value between 500
+For each system there is a maximum frequency offset of the clock that can be set
+by the driver. On Linux it is 100000 ppm, on FreeBSD, NetBSD and macOS 10.13+ it
+is 5000 ppm, and on Solaris it is 32500 ppm. Also, due to a kernel limitation,
+setting *maxslewrate* on FreeBSD, NetBSD, macOS 10.13+ to a value between 500
ppm and 5000 ppm will effectively set it to 500 ppm.
+
+In early beta releases of macOS 13 this capability is disabled because of a
+system kernel bug. When the kernel bug is fixed, chronyd will detect this and
+re-enable the capability (see above limitations) with no recompilation required.
++
By default, the maximum slew rate is set to 83333.333 ppm (one twelfth).
[[tempcomp]]
@@ -1559,7 +1623,7 @@ from the example line above):
. The root dispersion (_EPSILON_ in RFC 5905). [7.446e-03]
. Reference ID of the server's source as a hexadecimal number. [CB00717B]
. 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
(_D_=daemon, _K_=kernel, _H_=hardware). [D]
. Source of the local receive timestamp
@@ -1613,11 +1677,11 @@ from the example line above):
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.
[8]
-. The estimated asymmetry of network jitter on the path to the source which was
- used to correct the measured offsets. 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. [0.00,
- i.e. no correction for asymmetry]
+. The estimated or configured asymmetry of network jitter on the path to the
+ source which was used to correct the measured offsets. 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. [0.00, i.e. no correction for asymmetry]
+
*tracking*:::
This option logs changes to the estimate of the system's gain or loss rate, and
@@ -1626,33 +1690,42 @@ actually appears as a single line in the file) from the log file is shown
below.
+
----
-2015-02-23 05:40:50 203.0.113.15 3 340.529 1.606 1.046e-03 N \
- 4 6.849e-03 -4.670e-04
+2017-08-22 13:22:36 203.0.113.15 2 -3.541 0.075 -8.621e-06 N \
+ 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
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
- 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.
[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
- of UTC). [340.529]
-. The error bounds on the frequency (in ppm). [1.606]
-. The estimated local offset at the epoch (which is rapidly corrected by
- slewing the local clock. (In seconds, positive indicates the local system
- is fast of UTC). [1.046e-3]
+ of UTC). [-3.541]
+. The error bounds on the frequency (in ppm). [0.075]
+. The estimated local offset at the epoch, which is normally corrected by
+ slewing the local clock (in seconds, positive indicates the clock is fast of
+ UTC). [-8.621e-06]
. 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,
_?_ 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).
- [6.849e-03]
+ [2.940e-03]
. 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*:::
This option logs information about the system's real-time clock. An example
@@ -1813,17 +1886,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
timestamping, which can be verified with the *ethtool -T* command. The list of
capabilities should include _SOF_TIMESTAMPING_RAW_HARDWARE_,
-_SOF_TIMESTAMPING_TX_HARDWARE_, _SOF_TIMESTAMPING_RX_HARDWARE_, and the filter
-modes should have _HWTSTAMP_FILTER_ALL_. When *chronyd* is running, no other
-process should be working with the clock on the NIC. If no *hwtimestamp*
-directive is specified, *chronyd* will try to use software (kernel)
-timestamping. With both hardware and software timestamping there are
-some limitations on which packets can be actually timestamped, e.g. transmit
-timestamping does not currently work with IPv6 packets using IP options and
-hardware receive timestamping does not work with packets from bridged
-interfaces. The timestamping used in measurements is indicated in the
-_measurements.log_ file if enabled by the <<log,*log measurements*>> directive,
-and the <<chronyc.adoc#ntpdata,*ntpdata*>> report in *chronyc*.
+_SOF_TIMESTAMPING_TX_HARDWARE_, and _SOF_TIMESTAMPING_RX_HARDWARE_. Receive
+filter _HWTSTAMP_FILTER_ALL_, or _HWTSTAMP_FILTER_NTP_ALL_, is necessary for
+timestamping of received packets. Timestamping of packets received from bridged
+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
+interfaces. 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
on all available interfaces.
@@ -1851,6 +1925,22 @@ is 0.
*nocrossts*:::
Some hardware can precisely cross timestamp the NIC clock with the system
clock. This option disables the use of the cross timestamping.
+*rxfilter* _filter_:::
+This option selects the receive timestamping filter. The _filter_ can be one of
+the following:
+_all_::::
+Enables timestamping of all received packets.
+_ntp_::::
+Enables timestamping of received NTP packets.
+_none_::::
+Disables timestamping of received packets.
+:::
+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:
@@ -2178,8 +2268,7 @@ is made of the RTC error at a particular RTC second, and the rate at which the
RTC gains or loses time relative to true time.
When the computer is powered down, the measurement histories for all the NTP
-servers are saved to files (if the <<dumponexit,*dumponexit*>> directive is
-specified in the configuration file), and the RTC tracking information is also
+servers are saved to files, and the RTC tracking information is also
saved to a file (if the <<rtcfile,*rtcfile*>> directive has been specified).
These pieces of information are also saved if the <<chronyc.adoc#dump,*dump*>>
and <<chronyc.adoc#writertc,*writertc*>> commands respectively are issued
@@ -2232,7 +2321,6 @@ log statistics measurements tracking
driftfile @CHRONYVARDIR@/drift
makestep 1.0 3
maxupdateskew 100.0
-dumponexit
dumpdir @CHRONYVARDIR@
rtcfile @CHRONYVARDIR@/rtc
----
@@ -2276,7 +2364,7 @@ The amount of memory used for logging client accesses can be increased in order
to enable clients to use the interleaved mode even when the server has a large
number of clients, and better support rate limiting if it is enabled by the
<<ratelimit,*ratelimit*>> directive. The system timezone database, if it is
-kept up to date and includes the *right/UTC* timezone, can be used as a
+kept up to date and includes the _right/UTC_ timezone, can be used as a
reliable source to determine when a leap second will be applied to UTC. The
*-r* option with the <<dumpdir,*dumpdir*>> directive shortens the time in which
*chronyd* will not be able to serve time to its clients when it needs to be
@@ -2297,7 +2385,6 @@ clientloglimit 100000000
leapsectz right/UTC
driftfile @CHRONYVARDIR@/drift
dumpdir @CHRONYRUNDIR@
-dumponexit
----
== SEE ALSO
diff --git a/doc/chrony.conf.man.in b/doc/chrony.conf.man.in
index 2743a39..728897b 100644
--- a/doc/chrony.conf.man.in
+++ b/doc/chrony.conf.man.in
@@ -2,12 +2,12 @@
.\" Title: chrony.conf
.\" Author: [see the "AUTHORS" section]
.\" Generator: Asciidoctor 1.5.4
-.\" Date: 2017-01-31
+.\" Date: 2017-09-15
.\" Manual: Configuration Files
.\" Source: chrony @CHRONY_VERSION@
.\" Language: English
.\"
-.TH "CHRONY.CONF" "5" "2017-01-31" "chrony @CHRONY_VERSION@" "Configuration Files"
+.TH "CHRONY.CONF" "5" "2017-09-15" "chrony @CHRONY_VERSION@" "Configuration Files"
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.ss \n[.ss] 0
@@ -125,8 +125,7 @@ round\-trip delay of 0.3 seconds or more should be ignored. The default value is
This option is similar to the maxdelay option above. \fBchronyd\fP keeps a record
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
-maxdelayratio times the minimum delay, it will be rejected. This option works
-only in the \fBserver\fP directive when not in the interleaved mode.
+maxdelayratio times the minimum delay, it will be rejected.
.RE
.sp
\fBmaxdelaydevratio\fP \fIratio\fP
@@ -137,6 +136,25 @@ the previous measurements that is greater than the specified ratio, it will be
rejected. The default is 10.0.
.RE
.sp
+\fBmindelay\fP \fIdelay\fP
+.RS 4
+This options 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 \fBmaxdelayratio\fP and
+\fBmaxdelaydevratio\fP tests. The value should be set accurately in order to have a
+positive effect on the synchronisation.
+.RE
+.sp
+\fBasymmetry\fP \fIratio\fP
+.RS 4
+This options 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, \fBchronyd\fP estimates the asymmetry automatically.
+.RE
+.sp
\fBoffset\fP \fIoffset\fP
.RS 4
This option specifies a correction (in seconds) which will be applied to
@@ -221,10 +239,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
someone sending requests with a spoofed source address).
.sp
-With longer polling intervals, it is recommended to combine the \fBxleave\fP option
-with the \fBpresend\fP option in order to shorten the interval in which the server
-has to keep the state to be able to respond in the interleaved mode. The
-shorter interval also improves accuracy of the measured offset and delay.
+The \fBxleave\fP option can be combined with the \fBpresend\fP option in order to
+shorten the interval in which the server has to keep the state to be able to
+respond in the interleaved mode.
.RE
.sp
\fBpolltarget\fP \fItarget\fP
@@ -428,33 +445,44 @@ started in the boot sequence after \fBchronyd\fP from reading the clock before i
has been stepped.
.RE
.sp
-\fBrefclock\fP \fIdriver\fP \fIparameter\fP [\fIoption\fP]...
+\fBrefclock\fP \fIdriver\fP \fIparameter\fP[:\fIoption\fP,...] [\fIoption\fP]...
.RS 4
The \fBrefclock\fP directive specifies a hardware reference clock to be used as a
time source. It has two mandatory parameters, a driver name and a
-driver\-specific parameter.
+driver\-specific parameter. The two parameters are followed by zero or more
+refclock options. Some drivers have special options, which can be appended to
+the driver\-specific parameter (separated by the \fB:\fP and \fB,\fP characters).
.sp
-There are currently four drivers included:
+There are four drivers included in \fBchronyd\fP:
.sp
\fBPPS\fP
.RS 4
Driver for the kernel PPS (pulse per second) API. The parameter is the path to
-the PPS device (typically \fI/dev/pps?\fP). The assert events are used for
-synchronisation by default. String \fB:clear\fP can be appended to the path to use
-the clear events instead.
+the PPS device (typically \fI/dev/pps?\fP). As PPS refclocks do not supply full
+time, another time source (e.g. NTP server or non\-PPS refclock) is needed to
+complete samples from the PPS refclock. An alternative is to enable the
+\fBlocal\fP directive to allow synchronisation with some unknown but
+constant offset. The driver supports the following option:
+.sp
+\fBclear\fP
+.RS 4
+By default, the PPS refclock uses assert events (rising edge) for
+synchronisation. With this option, it will use clear events (falling edge)
+instead.
+.RE
+.RE
.sp
-As PPS refclocks don\(cqt supply full time, \fBchronyd\fP needs to be configured with
-another time source (NTP or non\-PPS refclock) in order to complete samples from
-the PPS refclock. An alternative is to enable the \fBlocal\fP directive
-to allow synchronisation with some unknown but constant offset.
-For example:
+
+.RS 4
+Examples:
.sp
.if n \{\
.RS 4
.\}
.nf
-refclock PPS /dev/pps0 lock NMEA
+refclock PPS /dev/pps0 lock NMEA refid GPS
refclock SHM 0 offset 0.5 delay 0.2 refid NMEA noselect
+refclock PPS /dev/pps1:clear refid GPS2
.fi
.if n \{\
.RE
@@ -464,27 +492,33 @@ refclock SHM 0 offset 0.5 delay 0.2 refid NMEA noselect
\fBSHM\fP
.RS 4
NTP shared memory driver. This driver uses a shared memory segment to receive
-samples from another process. The parameter is the number of the shared memory
-segment, typically 0, 1, 2 or 3. For example:
+samples from another process (e.g. \fBgpsd\fP). The parameter is the number of the
+shared memory segment, typically a small number like 0, 1, 2, or 3. The driver
+supports the following option:
+.sp
+\fBperm\fP=\fImode\fP
+.RS 4
+This option specifies the permissions of the shared memory segment created by
+\fBchronyd\fP. They are specified as a numeric mode. The default value is 0600
+(read\-write access for owner only).
+.RE
+.RE
+.sp
+
+.RS 4
+.sp
+Examples:
.sp
.if n \{\
.RS 4
.\}
.nf
-refclock SHM 1 poll 3 refid GPS1
+refclock SHM 0 poll 3 refid GPS1
+refclock SHM 1:perm=0644 refid GPS2
.fi
.if n \{\
.RE
.\}
-.sp
-A driver option in form of \fB:perm=NNN\fP can be appended to the segment number to
-create the segment with permissions other than the default 0600.
-.sp
-Examples of applications that can be used as SHM refclocks are
-.URL "http://www.catb.org/gpsd/" "\fBgpsd\fP" ","
-.URL "http://www.buzzard.me.uk/jonathan/radioclock.html" "\fBradioclk\fP" ","
-and
-.URL "https://www.vanheusden.com/time/omnisync/" "\fBomnisync\fP" "."
.RE
.sp
\fBSOCK\fP
@@ -515,18 +549,60 @@ refclock SOCK /var/run/chrony.ttyS0.sock
\fBPHC\fP
.RS 4
PTP hardware clock (PHC) driver. The parameter is the path to the device of
-the PTP clock, which for example can be synchronised by \fBptp4l\fP from
-.URL "http://linuxptp.sourceforge.net" "\fBlinuxptp\fP" "."
-String \fB:nocrossts\fP can be
-appended to the path to disable use of precise cross timestamping. PTP clocks
-are typically kept in TAI instead of UTC, so the \fBoffset\fP option should be used
-to compensate for the current UTC\-TAI offset. For example:
+the PTP clock which should be used as a time source. If the clock is kept in
+TAI instead of UTC (e.g. it is synchronised by a PTP daemon), the current
+UTC\-TAI offset needs to be specified by the \fBoffset\fP option. Alternatively, the
+\fBpps\fP refclock option can be enabled to treat the PHC as a PPS refclock, using
+only the sub\-second offset for synchronisation. The driver supports the
+following options:
+.sp
+\fBnocrossts\fP
+.RS 4
+This option disables use of precise cross timestamping.
+.RE
+.sp
+\fBextpps\fP
+.RS 4
+This option enables a PPS mode in which the PTP clock is timestamping pulses
+of an external PPS signal connected to the clock. The clock does not need to be
+synchronised, but another time source is needed to complete the PPS samples.
+Note that some PTP clocks cannot be configured to timestamp only assert or
+clear events, and it is necessary to use the \fBwidth\fP option to filter wrong
+PPS samples.
+.RE
+.sp
+\fBpin\fP=\fIindex\fP
+.RS 4
+This option specifies the index of the pin to which is connected the PPS
+signal. The default value is 0.
+.RE
+.sp
+\fBchannel\fP=\fIindex\fP
+.RS 4
+This option specifies the index of the channel for the PPS mode. The default
+value is 0.
+.RE
+.sp
+\fBclear\fP
+.RS 4
+This option enables timestamping of clear events (falling edge) instead of
+assert events (rising edge) in the PPS mode. This may not work with some
+clocks.
+.RE
+.RE
+.sp
+
+.RS 4
+.sp
+Examples:
.sp
.if n \{\
.RS 4
.\}
.nf
-refclock PHC /dev/ptp0 poll 3 dpoll \-2 offset \-36
+refclock PHC /dev/ptp0 poll 0 dpoll \-2 offset \-37
+refclock PHC /dev/ptp1:nocrossts poll 3 pps
+refclock PHC /dev/ptp2:extpps,pin=1 width 0.2 poll 2
.fi
.if n \{\
.RE
@@ -536,7 +612,7 @@ refclock PHC /dev/ptp0 poll 3 dpoll \-2 offset \-36
.sp
.RS 4
-The \fBrefclock\fP directive also supports a number of options:
+The \fBrefclock\fP directive supports the following options:
.sp
\fBpoll\fP \fIpoll\fP
.RS 4
@@ -587,6 +663,23 @@ Increasing this value is useful when the samples are produced at a lower rate
than the pulses. The default is 2.
.RE
.sp
+\fBwidth\fP \fIwidth\fP
+.RS 4
+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
+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
+preferred in order to maximise the allowed error.
+.RE
+.sp
+\fBpps\fP
+.RS 4
+This options forces \fBchronyd\fP 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
+offset of a whole number of seconds (e.g. it uses TAI instead of UTC). Another
+time source is needed to complete samples from the refclock.
+.RE
+.sp
\fBoffset\fP \fIoffset\fP
.RS 4
This option can be used to compensate for a constant error. The specified
@@ -605,9 +698,8 @@ nanosecond).
.sp
\fBprecision\fP \fIprecision\fP
.RS 4
-This option sets the refclock precision (in seconds). The default is 1e\-6 (1
-microsecond) for SHM refclock, and 1e\-9 (1 nanosecond) for SOCK, PPS and PHC
-refclocks.
+This option sets the precision of the reference clock (in seconds). The default
+value is the estimated precision of the system clock.
.RE
.sp
\fBmaxdispersion\fP \fIdispersion\fP
@@ -727,19 +819,18 @@ can be specified.
To compute the rate of gain or loss of time, \fBchronyd\fP has to store a
measurement history for each of the time sources it uses.
.sp
-Certain systems (Linux, FreeBSD, NetBSD, Solaris) have operating system support
-for setting the rate of gain or loss to compensate for known errors. (On Mac OS
-X, \fBchronyd\fP must simulate such a capability by periodically slewing the system
-clock forwards or backwards by a suitable amount to compensate for the error
-built up since the previous slew.)
+All supported systems, with the exception of macOS 10.12 and earlier, have
+operating system support for setting the rate of gain or loss to compensate for
+known errors.
+(On macOS 10.12 and earlier, \fBchronyd\fP must simulate such a capability by
+periodically slewing the system clock forwards or backwards by a suitable amount
+to compensate for the error built up since the previous slew.)
.sp
For such systems, it is possible to save the measurement history across
restarts of \fBchronyd\fP (assuming no changes are made to the system clock
-behaviour whilst it is not running). If this capability is to be used (via the
-\fBdumponexit\fP directive in the configuration file, or the
-\fBdump\fP command in \fBchronyc\fP), the \fBdumpdir\fP directive
-should be used to define the directory where the measurement histories are
-saved.
+behaviour whilst it is not running). The \fBdumpdir\fP directive defines the
+directory where the measurement histories are saved when \fBchronyd\fP exits,
+or the \fBdump\fP command in \fBchronyc\fP is issued.
.sp
An example of the directive is:
.sp
@@ -758,13 +849,6 @@ in the file \fI@CHRONYRUNDIR@/1.2.3.4.dat\fP. History of reference clocks is sav
to files named by their reference ID in form of \fIrefid:XXXXXXXX.dat\fP.
.RE
.sp
-\fBdumponexit\fP
-.RS 4
-If this directive is present, it indicates that \fBchronyd\fP should save the
-measurement history for each of its time sources recorded whenever the program
-exits. (See the \fBdumpdir\fP directive above.)
-.RE
-.sp
\fBmaxsamples\fP \fIsamples\fP
.RS 4
The \fBmaxsamples\fP directive sets the default maximum number of samples that
@@ -861,8 +945,9 @@ distances are in milliseconds.
\fBcorrtimeratio\fP \fIratio\fP
.RS 4
When \fBchronyd\fP is slewing the system clock to correct an offset, the rate at
-which it is slewing adds to the frequency error of the clock. On Linux,
-FreeBSD, NetBSD and Solaris this rate can be controlled.
+which it is slewing adds to the frequency error of the clock. On all supported
+systems, with the exception of macOS 12 and earlier, this rate can be
+controlled.
.sp
The \fBcorrtimeratio\fP directive sets the ratio between the duration in which the
clock is slewed for an average correction according to the source history and
@@ -964,8 +1049,8 @@ that error is corrected. There are four options:
When inserting a leap second, the kernel steps the system clock backwards by
one second when the clock gets to 00:00:00 UTC. When deleting a leap second, it
steps forward by one second when the clock gets to 23:59:59 UTC. This is the
-default mode when the system driver supports leap seconds (i.e. on Linux,
-FreeBSD, NetBSD and Solaris).
+default mode when the system driver supports leap seconds (i.e. all supported
+systems with the exception of macOS 12 and earlier).
.RE
.sp
\fBstep\fP
@@ -1041,15 +1126,23 @@ smearing servers.
.sp
\fBleapsectz\fP \fItimezone\fP
.RS 4
-This directive is used to set the name of the timezone in the system tz
-database which \fBchronyd\fP can use to find out when will the next leap second
-occur. It will periodically check if the times 23:59:59 and 23:59:60 are valid
-on Jun 30 and Dec 31 in the timezone. This typically works with the \fBright/UTC\fP
-timezone.
+This directive specifies a timezone in the system tz database which \fBchronyd\fP
+can use to determine when will the next leap second occur and what is the
+current offset between TAI and UTC. It will periodically check if 23:59:59 and
+23:59:60 are valid times in the timezone. This typically works with the
+\fIright/UTC\fP timezone.
.sp
-This directive is mainly useful with reference clocks which do not provide
-leap second information. It is not necessary to restart \fBchronyd\fP if the tz
-database is updated with a new leap second at least 12 hours before the event.
+When a leap second is announced, the timezone needs to be updated at least 12
+hours before the leap second. It is not necessary to restart \fBchronyd\fP.
+.sp
+This directive is useful with reference clocks and other time sources which do
+not announce leap seconds, or announce them too late for an NTP server to
+forward them to its own clients. Clients of leap smearing servers must not
+use this directive.
+.sp
+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
+kernel, i.e. \fBleapsecmode\fP is set to \fBsystem\fP.
.sp
An example of the directive is:
.sp
@@ -1153,7 +1246,7 @@ This directive specifies the maximum assumed drift (frequency error) of the
system clock. It limits the frequency adjustment that \fBchronyd\fP is allowed to
use to correct the measured drift. It is an additional limit to the maximum
adjustment that can be set by the system driver (100000 ppm on Linux, 500 ppm
-on FreeBSD and NetBSD, 32500 ppm on Solaris).
+on FreeBSD, NetBSD, and macOS 10.13+, 32500 ppm on Solaris).
.sp
By default, the maximum assumed drift is 500000 ppm, i.e. the adjustment is
limited by the system driver rather than this directive.
@@ -1192,14 +1285,18 @@ The \fBmaxslewrate\fP directive sets the maximum rate at which \fBchronyd\fP is
to slew the time. It limits the slew rate controlled by the correction time
ratio (which can be set by the \fBcorrtimeratio\fP directive) and
is effective only on systems where \fBchronyd\fP is able to control the rate (i.e.
-Linux, FreeBSD, NetBSD, Solaris).
+all supported systems with the exception of macOS 12 or earlier).
.sp
-For each system there is a maximum frequency offset of the clock that
-can be set by the driver. On Linux it is 100000 ppm, on FreeBSD and NetBSD
-it is 5000 ppm, and on Solaris it is 32500 ppm. Also, due to a kernel
-limitation, setting \fBmaxslewrate\fP on FreeBSD and NetBSD to a value between 500
+For each system there is a maximum frequency offset of the clock that can be set
+by the driver. On Linux it is 100000 ppm, on FreeBSD, NetBSD and macOS 10.13+ it
+is 5000 ppm, and on Solaris it is 32500 ppm. Also, due to a kernel limitation,
+setting \fBmaxslewrate\fP on FreeBSD, NetBSD, macOS 10.13+ to a value between 500
ppm and 5000 ppm will effectively set it to 500 ppm.
.sp
+In early beta releases of macOS 13 this capability is disabled because of a
+system kernel bug. When the kernel bug is fixed, chronyd will detect this and
+re\-enable the capability (see above limitations) with no recompilation required.
+.sp
By default, the maximum slew rate is set to 83333.333 ppm (one twelfth).
.RE
.sp
@@ -2260,7 +2357,7 @@ Reference ID of the server\(cqs source as a hexadecimal number. [CB00717B]
.IP " 18." 4.2
.\}
NTP mode of the received packet (\fI1\fP=active peer, \fI2\fP=passive peer,
-\fI3\fP=server, \fIB\fP=basic, \fII\fP=interleaved). [4B]
+\fI4\fP=server, \fIB\fP=basic, \fII\fP=interleaved). [4B]
.RE
.sp
.RS 4
@@ -2473,11 +2570,11 @@ tabulated. Values of approximately half the number of samples are expected.
.sp -1
.IP " 13." 4.2
.\}
-The estimated asymmetry of network jitter on the path to the source which was
-used to correct the measured offsets. 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. [0.00,
-i.e. no correction for asymmetry]
+The estimated or configured asymmetry of network jitter on the path to the
+source which was used to correct the measured offsets. 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. [0.00, i.e. no correction for asymmetry]
.RE
.RE
.sp
@@ -2492,8 +2589,8 @@ below.
.RS 4
.\}
.nf
-2015\-02\-23 05:40:50 203.0.113.15 3 340.529 1.606 1.046e\-03 N \(rs
- 4 6.849e\-03 \-4.670e\-04
+2017\-08\-22 13:22:36 203.0.113.15 2 \-3.541 0.075 \-8.621e\-06 N \(rs
+ 2 2.940e\-03 \-2.084e\-04 1.534e\-02 3.472e\-04 8.304e\-03
.fi
.if n \{\
.RE
@@ -2510,7 +2607,7 @@ values from the example line above) :
.sp -1
.IP " 1." 4.2
.\}
-Date [2015\-02\-03]
+Date [2017\-08\-22]
.RE
.sp
.RS 4
@@ -2522,7 +2619,7 @@ Date [2015\-02\-03]
.IP " 2." 4.2
.\}
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]
.RE
.sp
.RS 4
@@ -2545,7 +2642,7 @@ The IP address of the server or peer to which the local system is synchronised.
.sp -1
.IP " 4." 4.2
.\}
-The stratum of the local system. [3]
+The stratum of the local system. [2]
.RE
.sp
.RS 4
@@ -2557,7 +2654,7 @@ The stratum of the local system. [3]
.IP " 5." 4.2
.\}
The local system frequency (in ppm, positive means the local system runs fast
-of UTC). [340.529]
+of UTC). [\-3.541]
.RE
.sp
.RS 4
@@ -2568,7 +2665,7 @@ of UTC). [340.529]
.sp -1
.IP " 6." 4.2
.\}
-The error bounds on the frequency (in ppm). [1.606]
+The error bounds on the frequency (in ppm). [0.075]
.RE
.sp
.RS 4
@@ -2579,9 +2676,9 @@ The error bounds on the frequency (in ppm). [1.606]
.sp -1
.IP " 7." 4.2
.\}
-The estimated local offset at the epoch (which is rapidly corrected by
-slewing the local clock. (In seconds, positive indicates the local system
-is fast of UTC). [1.046e\-3]
+The estimated local offset at the epoch, which is normally corrected by
+slewing the local clock (in seconds, positive indicates the clock is fast of
+UTC). [\-8.621e\-06]
.RE
.sp
.RS 4
@@ -2605,7 +2702,7 @@ has 61 seconds, \fI\-\fP means that the last minute of the month has 59 seconds,
.sp -1
.IP " 9." 4.2
.\}
-The number of combined sources. [4]
+The number of combined sources. [2]
.RE
.sp
.RS 4
@@ -2617,7 +2714,7 @@ The number of combined sources. [4]
.IP " 10." 4.2
.\}
The estimated standard deviation of the combined offset (in seconds).
-[6.849e\-03]
+[2.940e\-03]
.RE
.sp
.RS 4
@@ -2629,7 +2726,46 @@ The estimated standard deviation of the combined offset (in seconds).
.IP " 11." 4.2
.\}
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]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 12.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 12." 4.2
+.\}
+The total of the network path delays to the reference clock to which
+the local clock is ultimately synchronised (in seconds). [1.534e\-02]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 13.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 13." 4.2
+.\}
+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]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 14.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 14." 4.2
+.\}
+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]
.RE
.RE
.sp
@@ -3068,17 +3204,18 @@ be enabled by the \fBxleave\fP option in the \fBserver\fP or the
This directive is supported on Linux 3.19 and newer. The NIC must support HW
timestamping, which can be verified with the \fBethtool \-T\fP command. The list of
capabilities should include \fISOF_TIMESTAMPING_RAW_HARDWARE\fP,
-\fISOF_TIMESTAMPING_TX_HARDWARE\fP, \fISOF_TIMESTAMPING_RX_HARDWARE\fP, and the filter
-modes should have \fIHWTSTAMP_FILTER_ALL\fP. When \fBchronyd\fP is running, no other
-process should be working with the clock on the NIC. If no \fBhwtimestamp\fP
-directive is specified, \fBchronyd\fP will try to use software (kernel)
-timestamping. With both hardware and software timestamping there are
-some limitations on which packets can be actually timestamped, e.g. transmit
-timestamping does not currently work with IPv6 packets using IP options and
-hardware receive timestamping does not work with packets from bridged
-interfaces. The timestamping used in measurements is indicated in the
-\fImeasurements.log\fP file if enabled by the \fBlog measurements\fP directive,
-and the \fBntpdata\fP report in \fBchronyc\fP.
+\fISOF_TIMESTAMPING_TX_HARDWARE\fP, and \fISOF_TIMESTAMPING_RX_HARDWARE\fP. Receive
+filter \fIHWTSTAMP_FILTER_ALL\fP, or \fIHWTSTAMP_FILTER_NTP_ALL\fP, is necessary for
+timestamping of received packets. Timestamping of packets received from bridged
+and bonded interfaces is supported on Linux 4.13 and newer. When \fBchronyd\fP is
+running, no other process (e.g. a PTP daemon) should be working with the NIC
+clock.
+.sp
+If the kernel supports software timestamping, it will be enabled for all
+interfaces. The source of timestamps (i.e. hardware, kernel, or daemon) is
+indicated in the \fImeasurements.log\fP file if enabled by the \fBlog
+measurements\fP directive, and the \fBntpdata\fP report in
+\fBchronyc\fP.
.sp
If the specified interface is \fI*\fP, \fBchronyd\fP will try to enable HW timestamping
on all available interfaces.
@@ -3120,6 +3257,37 @@ is 0.
Some hardware can precisely cross timestamp the NIC clock with the system
clock. This option disables the use of the cross timestamping.
.RE
+.sp
+\fBrxfilter\fP \fIfilter\fP
+.RS 4
+This option selects the receive timestamping filter. The \fIfilter\fP can be one of
+the following:
+.sp
+\fIall\fP
+.RS 4
+Enables timestamping of all received packets.
+.RE
+.sp
+\fIntp\fP
+.RS 4
+Enables timestamping of received NTP packets.
+.RE
+.sp
+\fInone\fP
+.RS 4
+Disables timestamping of received packets.
+.RE
+.RE
+.sp
+
+.RS 4
+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 \fInone\fP filter. Forcing timestamping of all packets
+with the \fIall\fP filter when the NIC supports both \fIall\fP and \fIntp\fP filters can be
+useful when packets are received from or on a non\-standard UDP port (e.g.
+specified by the \fBport\fP directive).
+.RE
.RE
.sp
@@ -3582,8 +3750,7 @@ is made of the RTC error at a particular RTC second, and the rate at which the
RTC gains or loses time relative to true time.
.sp
When the computer is powered down, the measurement histories for all the NTP
-servers are saved to files (if the \fBdumponexit\fP directive is
-specified in the configuration file), and the RTC tracking information is also
+servers are saved to files, and the RTC tracking information is also
saved to a file (if the \fBrtcfile\fP directive has been specified).
These pieces of information are also saved if the \fBdump\fP
and \fBwritertc\fP commands respectively are issued
@@ -3639,7 +3806,6 @@ log statistics measurements tracking
driftfile @CHRONYVARDIR@/drift
makestep 1.0 3
maxupdateskew 100.0
-dumponexit
dumpdir @CHRONYVARDIR@
rtcfile @CHRONYVARDIR@/rtc
.fi
@@ -3698,7 +3864,7 @@ The amount of memory used for logging client accesses can be increased in order
to enable clients to use the interleaved mode even when the server has a large
number of clients, and better support rate limiting if it is enabled by the
\fBratelimit\fP directive. The system timezone database, if it is
-kept up to date and includes the \fBright/UTC\fP timezone, can be used as a
+kept up to date and includes the \fIright/UTC\fP timezone, can be used as a
reliable source to determine when a leap second will be applied to UTC. The
\fB\-r\fP option with the \fBdumpdir\fP directive shortens the time in which
\fBchronyd\fP will not be able to serve time to its clients when it needs to be
@@ -3722,7 +3888,6 @@ clientloglimit 100000000
leapsectz right/UTC
driftfile @CHRONYVARDIR@/drift
dumpdir @CHRONYRUNDIR@
-dumponexit
.fi
.if n \{\
.RE
diff --git a/doc/chronyc.adoc b/doc/chronyc.adoc
index 5bda55c..9c5ac5c 100644
--- a/doc/chronyc.adoc
+++ b/doc/chronyc.adoc
@@ -2,7 +2,7 @@
//
// Copyright (C) Richard P. Curnow 1997-2003
// 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
// 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:
+
----
-clock_error <= root_dispersion + (0.5 * |root_delay|)
+clock_error <= |system_time_offset| + root_dispersion + (0.5 * root_delay)
----
*Update interval*:::
This is the interval between the last two clock updates.
@@ -1118,17 +1118,11 @@ purged. An example of how to do this is shown below.
[[dump]]*dump*::
The *dump* command causes *chronyd* to write its current history of
-measurements for each of its sources to dump files, either for inspection or to
-support the *-r* option when *chronyd* is restarted.
-+
-The *dump* command is somewhat equivalent to the
-<<chrony.conf.adoc#dumponexit,*dumponexit*>> directive in the configuration
-file.
-+
-To use the *dump* command, you might want to configure the name of the
-directory into which the dump files will be written. This can only be
-done in the configuration file with the <<chrony.conf.adoc#dumpdir,*dumpdir*>>
-directive.
+measurements for each of its sources to dump files in the directory specified
+in the configuration file by the <<chrony.conf.adoc#dumpdir,*dumpdir*>>
+directive. Note that *chronyd* does this automatically when it exits. This
+command is mainly useful for inspection of the history whilst *chronyd* is
+running.
[[rekey]]*rekey*::
The *rekey* command causes *chronyd* to re-read the key file specified in the
diff --git a/doc/chronyc.man.in b/doc/chronyc.man.in
index e8adbaa..8fe0060 100644
--- a/doc/chronyc.man.in
+++ b/doc/chronyc.man.in
@@ -2,12 +2,12 @@
.\" Title: chronyc
.\" Author: [see the "AUTHORS" section]
.\" Generator: Asciidoctor 1.5.4
-.\" Date: 2017-01-31
+.\" Date: 2017-09-15
.\" Manual: User manual
.\" Source: chrony @CHRONY_VERSION@
.\" Language: English
.\"
-.TH "CHRONYC" "1" "2017-01-31" "chrony @CHRONY_VERSION@" "User manual"
+.TH "CHRONYC" "1" "2017-09-15" "chrony @CHRONY_VERSION@" "User manual"
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.ss \n[.ss] 0
@@ -269,7 +269,7 @@ computer is correct) is given by:
.RS 4
.\}
.nf
-clock_error <= root_dispersion + (0.5 * |root_delay|)
+clock_error <= |system_time_offset| + root_dispersion + (0.5 * root_delay)
.fi
.if n \{\
.RE
@@ -1775,17 +1775,11 @@ purged. An example of how to do this is shown below.
\fBdump\fP
.RS 4
The \fBdump\fP command causes \fBchronyd\fP to write its current history of
-measurements for each of its sources to dump files, either for inspection or to
-support the \fB\-r\fP option when \fBchronyd\fP is restarted.
-.sp
-The \fBdump\fP command is somewhat equivalent to the
-\fBdumponexit\fP directive in the configuration
-file.
-.sp
-To use the \fBdump\fP command, you might want to configure the name of the
-directory into which the dump files will be written. This can only be
-done in the configuration file with the \fBdumpdir\fP
-directive.
+measurements for each of its sources to dump files in the directory specified
+in the configuration file by the \fBdumpdir\fP
+directive. Note that \fBchronyd\fP does this automatically when it exits. This
+command is mainly useful for inspection of the history whilst \fBchronyd\fP is
+running.
.RE
.sp
\fBrekey\fP
diff --git a/doc/chronyd.adoc b/doc/chronyd.adoc
index 9cb8eff..7b00865 100644
--- a/doc/chronyd.adoc
+++ b/doc/chronyd.adoc
@@ -1,7 +1,7 @@
// This file is part of chrony
//
// 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
// it under the terms of version 2 of the GNU General Public License as
@@ -62,17 +62,22 @@ When run in this mode, the program will not detach itself from the terminal.
*-d*::
When run in this mode, the program will not detach itself from the terminal,
-and all messages will be sent to the terminal instead of to syslog. When
+and all messages will be written to the terminal instead of syslog. When
*chronyd* was compiled with debugging support, this option can be used twice to
print also debugging messages.
+*-l* _file_::
+This option specifies a file which should be used for logging instead of syslog
+or terminal.
+
*-q*::
When run in this mode, *chronyd* will set the system clock once and exit. It
will not detach from the terminal.
*-Q*::
-This option is similar to *-q*, but it will only print the offset without any
-corrections of the clock.
+This option is similar to the *-q* option, except it only prints the offset
+without making any corrections of the clock and it allows *chronyd* to be
+started without root privileges.
*-r*::
This option will try to reload and then delete files containing sample
@@ -82,8 +87,8 @@ histories are created by using the <<chronyc.adoc#dump,*dump*>> command in
directive in the configuration file. This option is useful if you want to stop
and restart *chronyd* briefly for any reason, e.g. to install a new version.
However, it should be used only on systems where the kernel can maintain clock
-compensation whilst not under *chronyd*'s control (i.e. Linux, FreeBSD, NetBSD
-and Solaris).
+compensation whilst not under *chronyd*'s control (i.e. Linux, FreeBSD, NetBSD,
+Solaris, and macOS 10.13 or later).
*-R*::
When this option is used, the <<chrony.conf.adoc#initstepslew,*initstepslew*>>
@@ -151,6 +156,13 @@ support this option.
This option will lock *chronyd* into RAM so that it will never be paged out.
This mode is only supported on Linux.
+*-x*::
+This option disables the control of the system clock. *chronyd* will not make
+any adjustments of the clock, but it will still track its offset and frequency
+relative to the estimated true time, and be able to operate as an NTP server.
+This allows *chronyd* to run without the capability to adjust or set the system
+clock (e.g. in some containers).
+
*-v*::
With this option *chronyd* will print version number to the terminal and exit.
diff --git a/doc/chronyd.man.in b/doc/chronyd.man.in
index bc017c8..4f0b4ac 100644
--- a/doc/chronyd.man.in
+++ b/doc/chronyd.man.in
@@ -2,12 +2,12 @@
.\" Title: chronyd
.\" Author: [see the "AUTHORS" section]
.\" Generator: Asciidoctor 1.5.4
-.\" Date: 2017-01-31
+.\" Date: 2017-09-15
.\" Manual: System Administration
.\" Source: chrony @CHRONY_VERSION@
.\" Language: English
.\"
-.TH "CHRONYD" "8" "2017-01-31" "chrony @CHRONY_VERSION@" "System Administration"
+.TH "CHRONYD" "8" "2017-09-15" "chrony @CHRONY_VERSION@" "System Administration"
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.ss \n[.ss] 0
@@ -64,11 +64,17 @@ When run in this mode, the program will not detach itself from the terminal.
\fB\-d\fP
.RS 4
When run in this mode, the program will not detach itself from the terminal,
-and all messages will be sent to the terminal instead of to syslog. When
+and all messages will be written to the terminal instead of syslog. When
\fBchronyd\fP was compiled with debugging support, this option can be used twice to
print also debugging messages.
.RE
.sp
+\fB\-l\fP \fIfile\fP
+.RS 4
+This option specifies a file which should be used for logging instead of syslog
+or terminal.
+.RE
+.sp
\fB\-q\fP
.RS 4
When run in this mode, \fBchronyd\fP will set the system clock once and exit. It
@@ -77,8 +83,9 @@ will not detach from the terminal.
.sp
\fB\-Q\fP
.RS 4
-This option is similar to \fB\-q\fP, but it will only print the offset without any
-corrections of the clock.
+This option is similar to the \fB\-q\fP option, except it only prints the offset
+without making any corrections of the clock and it allows \fBchronyd\fP to be
+started without root privileges.
.RE
.sp
\fB\-r\fP
@@ -90,8 +97,8 @@ histories are created by using the \fBdump\fP command in
directive in the configuration file. This option is useful if you want to stop
and restart \fBchronyd\fP briefly for any reason, e.g. to install a new version.
However, it should be used only on systems where the kernel can maintain clock
-compensation whilst not under \fBchronyd\fP\(cqs control (i.e. Linux, FreeBSD, NetBSD
-and Solaris).
+compensation whilst not under \fBchronyd\fP\(cqs control (i.e. Linux, FreeBSD, NetBSD,
+Solaris, and macOS 10.13 or later).
.RE
.sp
\fB\-R\fP
@@ -174,6 +181,15 @@ This option will lock \fBchronyd\fP into RAM so that it will never be paged out.
This mode is only supported on Linux.
.RE
.sp
+\fB\-x\fP
+.RS 4
+This option disables the control of the system clock. \fBchronyd\fP will not make
+any adjustments of the clock, but it will still track its offset and frequency
+relative to the estimated true time, and be able to operate as an NTP server.
+This allows \fBchronyd\fP to run without the capability to adjust or set the system
+clock (e.g. in some containers).
+.RE
+.sp
\fB\-v\fP
.RS 4
With this option \fBchronyd\fP will print version number to the terminal and exit.
diff --git a/doc/faq.adoc b/doc/faq.adoc
index 8b2d43f..0b76dfe 100644
--- a/doc/faq.adoc
+++ b/doc/faq.adoc
@@ -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
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.
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.
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
system time is periodically copied to the RTC. It is supported on Linux and
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)?
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.
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
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
-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.
The other option is to use the `rtcfile` directive, which tells `chronyd` to
diff --git a/examples/chrony.conf.example2 b/examples/chrony.conf.example2
index cbd065e..21be153 100644
--- a/examples/chrony.conf.example2
+++ b/examples/chrony.conf.example2
@@ -28,6 +28,9 @@ rtcsync
# Specify file containing keys for NTP authentication.
#keyfile /etc/chrony.keys
+# Get TAI-UTC offset and leap seconds from the system tz database.
+#leapsectz right/UTC
+
# Specify directory for log files.
logdir /var/log/chrony
diff --git a/examples/chrony.conf.example3 b/examples/chrony.conf.example3
index fdc656a..05a4e98 100644
--- a/examples/chrony.conf.example3
+++ b/examples/chrony.conf.example3
@@ -97,6 +97,12 @@ driftfile /var/lib/chrony/drift
! 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
# This option is useful to quickly correct the clock on start if it's
diff --git a/examples/chrony.nm-dispatcher b/examples/chrony.nm-dispatcher
index 084aed6..51d7fa2 100644
--- a/examples/chrony.nm-dispatcher
+++ b/examples/chrony.nm-dispatcher
@@ -1,17 +1,35 @@
#!/bin/sh
# 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
-if [ "$2" = "up" ]; then
- /sbin/ip route list dev "$1" | grep -q '^default' &&
- /usr/bin/chronyc online > /dev/null 2>&1
-fi
+# Check if there is a default route
-if [ "$2" = "down" ]; then
- /sbin/ip route list | grep -q '^default' ||
- /usr/bin/chronyc offline > /dev/null 2>&1
+if /sbin/ip route list 2> /dev/null | grep -q '^default'; then
+ chronyc online > /dev/null 2>&1
+ exit 0
fi
+sources=$(chronyc -c -n sources 2> /dev/null)
+
+[ $? -ne 0 ] && exit 0
+
+# 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
diff --git a/examples/chrony.spec b/examples/chrony.spec
index acbad98..7daef26 100644
--- a/examples/chrony.spec
+++ b/examples/chrony.spec
@@ -1,4 +1,4 @@
-%global chrony_version 3.1
+%global chrony_version 3.2
%if 0%(echo %{chrony_version} | grep -q pre && echo 1)
%global prerelease %(echo %{chrony_version} | sed 's/.*-//')
%endif
diff --git a/hwclock.c b/hwclock.c
index e6f26fd..007d19d 100644
--- a/hwclock.c
+++ b/hwclock.c
@@ -2,7 +2,7 @@
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
* it under the terms of version 2 of the GNU General Public License as
@@ -39,6 +39,9 @@
/* Maximum number of samples per clock */
#define MAX_SAMPLES 16
+/* Maximum acceptable frequency offset of the clock */
+#define MAX_FREQ_OFFSET (2.0 / 3.0)
+
struct HCL_Instance_Record {
/* HW and local reference timestamp */
struct timespec hw_ref;
@@ -143,7 +146,7 @@ HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
if (hw_delta <= 0.0 || local_delta < clock->min_separation / 2.0) {
clock->n_samples = 0;
- DEBUG_LOG(LOGF_HwClocks, "HW clock reset interval=%f", local_delta);
+ DEBUG_LOG("HW clock reset interval=%f", local_delta);
}
for (i = MAX_SAMPLES - clock->n_samples; i < MAX_SAMPLES; i++) {
@@ -161,11 +164,11 @@ HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
clock->valid_coefs =
RGR_FindBestRobustRegression(clock->x_data + MAX_SAMPLES - clock->n_samples,
clock->y_data + MAX_SAMPLES - clock->n_samples,
- clock->n_samples, 1.0e-9, &clock->offset, &raw_freq,
+ clock->n_samples, 1.0e-10, &clock->offset, &raw_freq,
&n_runs, &best_start);
if (!clock->valid_coefs) {
- DEBUG_LOG(LOGF_HwClocks, "HW clock needs more samples");
+ DEBUG_LOG("HW clock needs more samples");
return;
}
@@ -174,16 +177,17 @@ HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
/* Drop unneeded samples */
clock->n_samples -= best_start;
- /* If the fit doesn't cross the error interval of the last sample, throw away
- all previous samples and keep only the frequency estimate */
- if (fabs(clock->offset) > err) {
- DEBUG_LOG(LOGF_HwClocks, "HW clock reset offset=%e", clock->offset);
- clock->offset = 0.0;
- clock->n_samples = 1;
+ /* If the fit doesn't cross the error interval of the last sample,
+ or the frequency is not sane, drop all samples and start again */
+ if (fabs(clock->offset) > err ||
+ fabs(clock->frequency - 1.0) > MAX_FREQ_OFFSET) {
+ DEBUG_LOG("HW clock reset");
+ clock->n_samples = 0;
+ clock->valid_coefs = 0;
}
- DEBUG_LOG(LOGF_HwClocks, "HW clock samples=%d offset=%e freq=%.9e raw_freq=%.9e err=%e ref_diff=%e",
- clock->n_samples, clock->offset, clock->frequency, raw_freq, err,
+ 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 - 1.0, raw_freq - 1.0, err,
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;
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);
/* Fow now, just return the error of the last sample */
diff --git a/keys.c b/keys.c
index 09b27bc..74b57c4 100644
--- a/keys.c
+++ b/keys.c
@@ -122,7 +122,7 @@ determine_hash_delay(uint32_t key_id)
/* Add on a bit extra to allow for copying, conversions etc */
nsecs = 1.0625e9 * min_diff;
- DEBUG_LOG(LOGF_Keys, "authentication delay for key %"PRIu32": %d nsecs", key_id, nsecs);
+ DEBUG_LOG("authentication delay for key %"PRIu32": %d nsecs", key_id, nsecs);
return nsecs;
}
@@ -200,7 +200,7 @@ KEY_Reload(void)
in = fopen(key_file, "r");
if (!in) {
- LOG(LOGS_WARN, LOGF_Keys, "Could not open keyfile %s", key_file);
+ LOG(LOGS_WARN, "Could not open keyfile %s", key_file);
return;
}
@@ -212,19 +212,19 @@ KEY_Reload(void)
continue;
if (!CPS_ParseKey(line, &key_id, &hashname, &keyval)) {
- LOG(LOGS_WARN, LOGF_Keys, "Could not parse key at line %d in file %s", line_number, key_file);
+ LOG(LOGS_WARN, "Could not parse key at line %d in file %s", line_number, key_file);
continue;
}
key.hash_id = HSH_GetHashId(hashname);
if (key.hash_id < 0) {
- LOG(LOGS_WARN, LOGF_Keys, "Unknown hash function in key %"PRIu32, key_id);
+ LOG(LOGS_WARN, "Unknown hash function in key %"PRIu32, key_id);
continue;
}
key.len = decode_password(keyval);
if (!key.len) {
- LOG(LOGS_WARN, LOGF_Keys, "Could not decode password in key %"PRIu32, key_id);
+ LOG(LOGS_WARN, "Could not decode password in key %"PRIu32, key_id);
continue;
}
@@ -244,7 +244,7 @@ KEY_Reload(void)
/* Check for duplicates */
for (i = 1; i < ARR_GetSize(keys); i++) {
if (get_key(i - 1)->id == get_key(i)->id)
- LOG(LOGS_WARN, LOGF_Keys, "Detected duplicate key %"PRIu32, get_key(i - 1)->id);
+ LOG(LOGS_WARN, "Detected duplicate key %"PRIu32, get_key(i - 1)->id);
}
/* Erase any passwords from stack */
diff --git a/local.c b/local.c
index 5e75624..b4baaac 100644
--- a/local.c
+++ b/local.c
@@ -146,7 +146,7 @@ calculate_sys_precision(void)
assert(precision_log >= -30);
- DEBUG_LOG(LOGF_Local, "Clock precision %.9f (%d)", precision_quantum, precision_log);
+ DEBUG_LOG("Clock precision %.9f (%d)", precision_quantum, precision_log);
}
/* ================================================== */
@@ -358,12 +358,12 @@ LCL_ReadRawTime(struct timespec *ts)
{
#if HAVE_CLOCK_GETTIME
if (clock_gettime(CLOCK_REALTIME, ts) < 0)
- LOG_FATAL(LOGF_Local, "clock_gettime() failed : %s", strerror(errno));
+ LOG_FATAL("clock_gettime() failed : %s", strerror(errno));
#else
struct timeval tv;
if (gettimeofday(&tv, NULL) < 0)
- LOG_FATAL(LOGF_Local, "gettimeofday() failed : %s", strerror(errno));
+ LOG_FATAL("gettimeofday() failed : %s", strerror(errno));
UTI_TimevalToTimespec(&tv, ts);
#endif
@@ -426,7 +426,7 @@ clamp_freq(double freq)
if (freq <= max_freq_ppm && freq >= -max_freq_ppm)
return freq;
- LOG(LOGS_WARN, LOGF_Local, "Frequency %.1f ppm exceeds allowed maximum", freq);
+ LOG(LOGS_WARN, "Frequency %.1f ppm exceeds allowed maximum", freq);
return CLAMP(-max_freq_ppm, freq, max_freq_ppm);
}
@@ -440,7 +440,7 @@ check_offset(struct timespec *now, double offset)
if (UTI_IsTimeOffsetSane(now, -offset))
return 1;
- LOG(LOGS_WARN, LOGF_Local, "Adjustment of %.1f seconds is invalid", -offset);
+ LOG(LOGS_WARN, "Adjustment of %.1f seconds is invalid", -offset);
return 0;
}
@@ -546,7 +546,7 @@ LCL_ApplyStepOffset(double offset)
return 0;
if (!(*drv_apply_step_offset)(offset)) {
- LOG(LOGS_ERR, LOGF_Local, "Could not step clock");
+ LOG(LOGS_ERR, "Could not step system clock");
return 0;
}
@@ -613,7 +613,7 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
current_freq_ppm = clamp_freq(current_freq_ppm);
- DEBUG_LOG(LOGF_Local, "old_freq=%.3fppm new_freq=%.3fppm offset=%.6fsec",
+ DEBUG_LOG("old_freq=%.3fppm new_freq=%.3fppm offset=%.6fsec",
old_freq_ppm, current_freq_ppm, doffset);
/* Call the system-specific driver for setting the frequency */
@@ -660,7 +660,7 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
current_freq_ppm = (*drv_read_freq)();
- DEBUG_LOG(LOGF_Local, "Local freq=%.3fppm", current_freq_ppm);
+ DEBUG_LOG("Local freq=%.3fppm", current_freq_ppm);
}
/* ================================================== */
@@ -684,7 +684,7 @@ LCL_MakeStep(void)
if (!LCL_ApplyStepOffset(-correction))
return 0;
- LOG(LOGS_WARN, LOGF_Local, "System clock was stepped by %.6f seconds", correction);
+ LOG(LOGS_WARN, "System clock was stepped by %.6f seconds", correction);
return 1;
}
@@ -700,10 +700,10 @@ LCL_CanSystemLeap(void)
/* ================================================== */
void
-LCL_SetSystemLeap(int leap)
+LCL_SetSystemLeap(int leap, int tai_offset)
{
if (drv_set_leap) {
- (drv_set_leap)(leap);
+ (drv_set_leap)(leap, tai_offset);
}
}
diff --git a/local.h b/local.h
index 618a0bd..7ceb76a 100644
--- a/local.h
+++ b/local.h
@@ -201,10 +201,11 @@ extern int LCL_MakeStep(void);
does something */
extern int LCL_CanSystemLeap(void);
-/* Routine to set the system clock to correct itself for a leap second if
- supported. Leap second will be inserted at the end of the day if the
- argument is positive, deleted if negative, and zero resets the setting. */
-extern void LCL_SetSystemLeap(int leap);
+/* Routine to set the system clock to correct itself for a leap second and also
+ set its TAI-UTC offset. If supported, leap second will be inserted at the
+ end of the day if the argument is positive, deleted if negative, and zero
+ resets the setting. */
+extern void LCL_SetSystemLeap(int leap, int tai_offset);
/* Routine to set a frequency correction (in ppm) that should be applied
to local clock to compensate for temperature changes. A positive
diff --git a/localp.h b/localp.h
index fbbeb3e..6f65e43 100644
--- a/localp.h
+++ b/localp.h
@@ -54,8 +54,8 @@ typedef int (*lcl_ApplyStepOffsetDriver)(double offset);
raw time to get the corrected time */
typedef void (*lcl_OffsetCorrectionDriver)(struct timespec *raw, double *corr, double *err);
-/* System driver to schedule leap second */
-typedef void (*lcl_SetLeapDriver)(int leap);
+/* System driver to schedule leap seconds and set TAI-UTC offset */
+typedef void (*lcl_SetLeapDriver)(int leap, int tai_offset);
/* System driver to set the synchronisation status */
typedef void (*lcl_SetSyncStatusDriver)(int synchronised, double est_error, double max_error);
diff --git a/logging.c b/logging.c
index e09203a..b39c4d5 100644
--- a/logging.c
+++ b/logging.c
@@ -40,6 +40,7 @@ int log_debug_enabled = 0;
/* Flag indicating we have initialised */
static int initialised = 0;
+static FILE *file_log;
static int system_log = 0;
static int parent_fd = 0;
@@ -69,6 +70,7 @@ void
LOG_Initialise(void)
{
initialised = 1;
+ file_log = stderr;
}
/* ================================================== */
@@ -79,6 +81,8 @@ LOG_Finalise(void)
{
if (system_log) {
closelog();
+ } else {
+ fclose(file_log);
}
LOG_CycleLogFiles();
@@ -113,7 +117,7 @@ static void log_message(int fatal, LOG_Severity severity, const char *message)
}
syslog(priority, fatal ? "Fatal error : %s" : "%s", message);
} else {
- fprintf(stderr, fatal ? "Fatal error : %s\n" : "%s\n", message);
+ fprintf(file_log, fatal ? "Fatal error : %s\n" : "%s\n", message);
}
}
@@ -121,8 +125,7 @@ static void log_message(int fatal, LOG_Severity severity, const char *message)
void LOG_Message(LOG_Severity severity,
#if DEBUG > 0
- LOG_Facility facility, int line_number,
- const char *filename, const char *function_name,
+ int line_number, const char *filename, const char *function_name,
#endif
const char *format, ...)
{
@@ -136,10 +139,10 @@ void LOG_Message(LOG_Severity severity,
time(&t);
stm = *gmtime(&t);
strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", &stm);
- fprintf(stderr, "%s ", buf);
+ fprintf(file_log, "%s ", buf);
#if DEBUG > 0
if (debug_level >= DEBUG_LEVEL_PRINT_FUNCTION)
- fprintf(stderr, "%s:%d:(%s) ", filename, line_number, function_name);
+ fprintf(file_log, "%s:%d:(%s) ", filename, line_number, function_name);
#endif
}
@@ -177,6 +180,24 @@ void LOG_Message(LOG_Severity severity,
/* ================================================== */
void
+LOG_OpenFileLog(const char *log_file)
+{
+ FILE *f;
+
+ f = fopen(log_file, "a");
+ if (!f)
+ LOG_FATAL("Could not open log file %s", log_file);
+
+ /* Enable line buffering */
+ setvbuf(f, NULL, _IOLBF, BUFSIZ);
+
+ file_log = f;
+}
+
+
+/* ================================================== */
+
+void
LOG_OpenSystemLog(void)
{
system_log = 1;
@@ -241,7 +262,7 @@ LOG_FileWrite(LOG_FileID id, const char *format, ...)
char filename[512], *logdir = CNF_GetLogDir();
if (logdir[0] == '\0') {
- LOG(LOGS_WARN, LOGF_Logging, "logdir not specified");
+ LOG(LOGS_WARN, "logdir not specified");
logfiles[id].name = NULL;
return;
}
@@ -249,7 +270,7 @@ LOG_FileWrite(LOG_FileID id, const char *format, ...)
if (snprintf(filename, sizeof(filename), "%s/%s.log",
logdir, logfiles[id].name) >= sizeof (filename) ||
!(logfiles[id].file = fopen(filename, "a"))) {
- LOG(LOGS_WARN, LOGF_Logging, "Could not open log file %s", filename);
+ LOG(LOGS_WARN, "Could not open log file %s", filename);
logfiles[id].name = NULL;
return;
}
diff --git a/logging.h b/logging.h
index cc8beee..c50bcf5 100644
--- a/logging.h
+++ b/logging.h
@@ -46,26 +46,26 @@ extern int log_debug_enabled;
#endif
#if DEBUG > 0
-#define LOG_MESSAGE(severity, facility, ...) \
- LOG_Message(severity, facility, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__)
+#define LOG_MESSAGE(severity, ...) \
+ LOG_Message(severity, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__)
#else
-#define LOG_MESSAGE(severity, facility, ...) \
+#define LOG_MESSAGE(severity, ...) \
LOG_Message(severity, __VA_ARGS__)
#endif
-#define DEBUG_LOG(facility, ...) \
+#define DEBUG_LOG(...) \
do { \
if (DEBUG && log_debug_enabled) \
- LOG_MESSAGE(LOGS_DEBUG, facility, __VA_ARGS__); \
+ LOG_MESSAGE(LOGS_DEBUG, __VA_ARGS__); \
} while (0)
-#define LOG_FATAL(facility, ...) \
+#define LOG_FATAL(...) \
do { \
- LOG_MESSAGE(LOGS_FATAL, facility, __VA_ARGS__); \
+ LOG_MESSAGE(LOGS_FATAL, __VA_ARGS__); \
exit(1); \
} while (0)
-#define LOG(severity, facility, ...) LOG_MESSAGE(severity, facility, __VA_ARGS__)
+#define LOG(severity, ...) LOG_MESSAGE(severity, __VA_ARGS__)
/* Definition of severity */
typedef enum {
@@ -76,50 +76,6 @@ typedef enum {
LOGS_DEBUG
} LOG_Severity;
-/* Definition of facility. Each message is tagged with who generated
- it, so that the user can customise what level of reporting he gets
- for each area of the software */
-typedef enum {
- LOGF_Reference,
- LOGF_NtpIO,
- LOGF_NtpIOLinux,
- LOGF_NtpCore,
- LOGF_NtpSignd,
- LOGF_NtpSources,
- LOGF_Scheduler,
- LOGF_SourceStats,
- LOGF_Sources,
- LOGF_Local,
- LOGF_Util,
- LOGF_Main,
- LOGF_Memory,
- LOGF_Client,
- LOGF_ClientLog,
- LOGF_Configure,
- LOGF_CmdMon,
- LOGF_Acquire,
- LOGF_Manual,
- LOGF_Keys,
- LOGF_Logging,
- LOGF_Nameserv,
- LOGF_PrivOps,
- LOGF_Rtc,
- LOGF_Regress,
- LOGF_Sys,
- LOGF_SysGeneric,
- LOGF_SysLinux,
- LOGF_SysMacOSX,
- LOGF_SysNetBSD,
- LOGF_SysSolaris,
- LOGF_SysTimex,
- LOGF_SysWinnt,
- LOGF_TempComp,
- LOGF_RtcLinux,
- LOGF_Refclock,
- LOGF_HwClocks,
- LOGF_Smooth,
-} LOG_Facility;
-
/* Init function */
extern void LOG_Initialise(void);
@@ -128,9 +84,8 @@ extern void LOG_Finalise(void);
/* Line logging function */
#if DEBUG > 0
-FORMAT_ATTRIBUTE_PRINTF(6, 7)
-extern void LOG_Message(LOG_Severity severity, LOG_Facility facility,
- int line_number, const char *filename,
+FORMAT_ATTRIBUTE_PRINTF(5, 6)
+extern void LOG_Message(LOG_Severity severity, int line_number, const char *filename,
const char *function_name, const char *format, ...);
#else
FORMAT_ATTRIBUTE_PRINTF(2, 3)
@@ -144,6 +99,9 @@ extern void LOG_Message(LOG_Severity severity, const char *format, ...);
*/
extern void LOG_SetDebugLevel(int level);
+/* Log messages to a file instead of stderr */
+extern void LOG_OpenFileLog(const char *log_file);
+
/* Log messages to syslog instead of stderr */
extern void LOG_OpenSystemLog(void);
diff --git a/main.c b/main.c
index 1daa158..ab1b71a 100644
--- a/main.c
+++ b/main.c
@@ -4,7 +4,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* 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
* it under the terms of version 2 of the GNU General Public License as
@@ -86,6 +86,10 @@ static void
delete_pidfile(void)
{
const char *pidfile = CNF_GetPidFile();
+
+ if (!pidfile[0])
+ return;
+
/* Don't care if this fails, there's not a lot we can do */
unlink(pidfile);
}
@@ -97,7 +101,7 @@ MAI_CleanupAndExit(void)
{
if (!initialised) exit(exit_status);
- if (CNF_GetDumpOnExit()) {
+ if (CNF_GetDumpDir()[0] != '\0') {
SRC_DumpSources();
}
@@ -127,9 +131,8 @@ MAI_CleanupAndExit(void)
delete_pidfile();
CNF_Finalise();
- LOG_Finalise();
-
HSH_Finalise();
+ LOG_Finalise();
exit(exit_status);
}
@@ -242,55 +245,45 @@ post_init_rtc_hook(void *anything)
}
/* ================================================== */
-/* Return 1 if the process exists on the system. */
-
-static int
-does_process_exist(int pid)
-{
- int status;
- status = getsid(pid);
- if (status >= 0) {
- return 1;
- } else {
- return 0;
- }
-}
-
-/* ================================================== */
-static int
-maybe_another_chronyd_running(int *other_pid)
+static void
+check_pidfile(void)
{
const char *pidfile = CNF_GetPidFile();
FILE *in;
int pid, count;
- *other_pid = 0;
-
in = fopen(pidfile, "r");
- if (!in) return 0;
+ if (!in)
+ return;
count = fscanf(in, "%d", &pid);
fclose(in);
- if (count != 1) return 0;
+ if (count != 1)
+ return;
- *other_pid = pid;
- return does_process_exist(pid);
-
+ if (getsid(pid) < 0)
+ return;
+
+ LOG_FATAL("Another chronyd may already be running (pid=%d), check %s",
+ pid, pidfile);
}
/* ================================================== */
static void
-write_lockfile(void)
+write_pidfile(void)
{
const char *pidfile = CNF_GetPidFile();
FILE *out;
+ if (!pidfile[0])
+ return;
+
out = fopen(pidfile, "w");
if (!out) {
- LOG_FATAL(LOGF_Main, "could not open lockfile %s for writing", pidfile);
+ LOG_FATAL("Could not open %s : %s", pidfile, strerror(errno));
} else {
fprintf(out, "%d\n", (int)getpid());
fclose(out);
@@ -307,14 +300,14 @@ go_daemon(void)
/* Create pipe which will the daemon use to notify the grandparent
when it's initialised or send an error message */
if (pipe(pipefd)) {
- LOG_FATAL(LOGF_Main, "Could not detach, pipe failed : %s", strerror(errno));
+ LOG_FATAL("pipe() failed : %s", strerror(errno));
}
/* Does this preserve existing signal handlers? */
pid = fork();
if (pid < 0) {
- LOG_FATAL(LOGF_Main, "Could not detach, fork failed : %s", strerror(errno));
+ LOG_FATAL("fork() failed : %s", strerror(errno));
} else if (pid > 0) {
/* In the 'grandparent' */
char message[1024];
@@ -340,7 +333,7 @@ go_daemon(void)
pid = fork();
if (pid < 0) {
- LOG_FATAL(LOGF_Main, "Could not detach, fork failed : %s", strerror(errno));
+ LOG_FATAL("fork() failed : %s", strerror(errno));
} else if (pid > 0) {
exit(0); /* In the 'parent' */
} else {
@@ -348,7 +341,7 @@ go_daemon(void)
/* Change current directory to / */
if (chdir("/") < 0) {
- LOG_FATAL(LOGF_Main, "Could not chdir to / : %s", strerror(errno));
+ LOG_FATAL("chdir() failed : %s", strerror(errno));
}
/* Don't keep stdin/out/err from before. But don't close
@@ -365,142 +358,176 @@ go_daemon(void)
/* ================================================== */
+static void
+print_help(const char *progname)
+{
+ printf("Usage: %s [-4|-6] [-n|-d] [-q|-Q] [-r] [-R] [-s] [-t TIMEOUT] [-f FILE|COMMAND...]\n",
+ progname);
+}
+
+/* ================================================== */
+
+static void
+print_version(void)
+{
+ printf("chronyd (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYD_FEATURES);
+}
+
+/* ================================================== */
+
+static int
+parse_int_arg(const char *arg)
+{
+ int i;
+
+ if (sscanf(arg, "%d", &i) != 1)
+ LOG_FATAL("Invalid argument %s", arg);
+ return i;
+}
+
+/* ================================================== */
+
int main
(int argc, char **argv)
{
const char *conf_file = DEFAULT_CONF_FILE;
const char *progname = argv[0];
- char *user = NULL;
+ char *user = NULL, *log_file = NULL;
struct passwd *pw;
- int debug = 0, nofork = 0, address_family = IPADDR_UNSPEC;
- int do_init_rtc = 0, restarted = 0, timeout = 0;
- int other_pid;
+ int opt, debug = 0, nofork = 0, address_family = IPADDR_UNSPEC;
+ int do_init_rtc = 0, restarted = 0, client_only = 0, timeout = 0;
int scfilter_level = 0, lock_memory = 0, sched_priority = 0;
- int system_log = 1;
+ int clock_control = 1, system_log = 1;
int config_args = 0;
do_platform_checks();
LOG_Initialise();
- /* Parse command line options */
- while (++argv, (--argc)>0) {
-
- if (!strcmp("-f", *argv)) {
- ++argv, --argc;
- conf_file = *argv;
- } else if (!strcmp("-P", *argv)) {
- ++argv, --argc;
- if (argc == 0 || sscanf(*argv, "%d", &sched_priority) != 1) {
- LOG_FATAL(LOGF_Main, "Bad scheduler priority");
- }
- } else if (!strcmp("-m", *argv)) {
- lock_memory = 1;
- } else if (!strcmp("-r", *argv)) {
- reload = 1;
- } else if (!strcmp("-R", *argv)) {
- restarted = 1;
- } else if (!strcmp("-u", *argv)) {
- ++argv, --argc;
- if (argc == 0) {
- LOG_FATAL(LOGF_Main, "Missing user name");
- } else {
- user = *argv;
- }
- } else if (!strcmp("-F", *argv)) {
- ++argv, --argc;
- if (argc == 0 || sscanf(*argv, "%d", &scfilter_level) != 1)
- LOG_FATAL(LOGF_Main, "Bad syscall filter level");
- } else if (!strcmp("-s", *argv)) {
- do_init_rtc = 1;
- } else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
- /* This write to the terminal is OK, it comes before we turn into a daemon */
- printf("chronyd (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYD_FEATURES);
+ /* Parse (undocumented) long command-line options */
+ for (optind = 1; optind < argc; optind++) {
+ if (!strcmp("--help", argv[optind])) {
+ print_help(progname);
return 0;
- } else if (!strcmp("-n", *argv)) {
- nofork = 1;
- } else if (!strcmp("-d", *argv)) {
- debug++;
- nofork = 1;
- system_log = 0;
- } else if (!strcmp("-q", *argv)) {
- ref_mode = REF_ModeUpdateOnce;
- nofork = 1;
- system_log = 0;
- } else if (!strcmp("-Q", *argv)) {
- ref_mode = REF_ModePrintOnce;
- nofork = 1;
- system_log = 0;
- } else if (!strcmp("-t", *argv)) {
- ++argv, --argc;
- if (argc == 0 || sscanf(*argv, "%d", &timeout) != 1 || timeout <= 0)
- LOG_FATAL(LOGF_Main, "Bad timeout");
- } else if (!strcmp("-4", *argv)) {
- address_family = IPADDR_INET4;
- } else if (!strcmp("-6", *argv)) {
- address_family = IPADDR_INET6;
- } else if (!strcmp("-h", *argv) || !strcmp("--help", *argv)) {
- printf("Usage: %s [-4|-6] [-n|-d] [-q|-Q] [-r] [-R] [-s] [-t TIMEOUT] [-f FILE|COMMAND...]\n",
- progname);
+ } else if (!strcmp("--version", argv[optind])) {
+ print_version();
return 0;
- } else if (*argv[0] == '-') {
- LOG_FATAL(LOGF_Main, "Unrecognized command line option [%s]", *argv);
- } else {
- /* Process remaining arguments and configuration lines */
- config_args = argc;
- break;
}
}
- if (getuid() != 0) {
- /* This write to the terminal is OK, it comes before we turn into a daemon */
- fprintf(stderr,"Not superuser\n");
- return 1;
+ optind = 1;
+
+ /* Parse short command-line options */
+ while ((opt = getopt(argc, argv, "46df:F:hl:mnP:qQrRst:u:vx")) != -1) {
+ switch (opt) {
+ case '4':
+ case '6':
+ address_family = opt == '4' ? IPADDR_INET4 : IPADDR_INET6;
+ break;
+ case 'd':
+ debug++;
+ nofork = 1;
+ system_log = 0;
+ break;
+ case 'f':
+ conf_file = optarg;
+ break;
+ case 'F':
+ scfilter_level = parse_int_arg(optarg);
+ break;
+ case 'l':
+ log_file = optarg;
+ break;
+ case 'm':
+ lock_memory = 1;
+ break;
+ case 'n':
+ nofork = 1;
+ break;
+ case 'P':
+ sched_priority = parse_int_arg(optarg);
+ break;
+ case 'q':
+ ref_mode = REF_ModeUpdateOnce;
+ nofork = 1;
+ client_only = 0;
+ system_log = 0;
+ break;
+ case 'Q':
+ ref_mode = REF_ModePrintOnce;
+ nofork = 1;
+ client_only = 1;
+ clock_control = 0;
+ system_log = 0;
+ break;
+ case 'r':
+ reload = 1;
+ break;
+ case 'R':
+ restarted = 1;
+ break;
+ case 's':
+ do_init_rtc = 1;
+ break;
+ case 't':
+ timeout = parse_int_arg(optarg);
+ break;
+ case 'u':
+ user = optarg;
+ break;
+ case 'v':
+ print_version();
+ return 0;
+ case 'x':
+ clock_control = 0;
+ break;
+ default:
+ print_help(progname);
+ return opt != 'h';
+ }
}
+ if (getuid() && !client_only)
+ LOG_FATAL("Not superuser");
+
/* Turn into a daemon */
if (!nofork) {
go_daemon();
}
- if (system_log) {
+ if (log_file) {
+ LOG_OpenFileLog(log_file);
+ } else if (system_log) {
LOG_OpenSystemLog();
}
LOG_SetDebugLevel(debug);
- LOG(LOGS_INFO, LOGF_Main, "chronyd version %s starting (%s)",
- CHRONY_VERSION, CHRONYD_FEATURES);
+ LOG(LOGS_INFO, "chronyd version %s starting (%s)", CHRONY_VERSION, CHRONYD_FEATURES);
DNS_SetAddressFamily(address_family);
- CNF_Initialise(restarted);
+ CNF_Initialise(restarted, client_only);
/* Parse the config file or the remaining command line arguments */
+ config_args = argc - optind;
if (!config_args) {
CNF_ReadFile(conf_file);
} else {
- do {
- CNF_ParseLine(NULL, config_args - argc + 1, *argv);
- } while (++argv, --argc);
+ for (; optind < argc; optind++)
+ CNF_ParseLine(NULL, config_args + optind - argc + 1, argv[optind]);
}
- /* Check whether another chronyd may already be running. Do this after
- * forking, so that message logging goes to the right place (i.e. syslog), in
- * case this chronyd is being run from a boot script. */
- if (maybe_another_chronyd_running(&other_pid)) {
- LOG_FATAL(LOGF_Main, "Another chronyd may already be running (pid=%d), check lockfile (%s)",
- other_pid, CNF_GetPidFile());
- }
+ /* Check whether another chronyd may already be running */
+ check_pidfile();
- /* Write our lockfile to prevent other chronyds running. This has *GOT* to
- * be done *AFTER* the daemon-creation fork() */
- write_lockfile();
+ /* Write our pidfile to prevent other chronyds running */
+ write_pidfile();
PRV_Initialise();
LCL_Initialise();
SCH_Initialise();
- SYS_Initialise();
+ SYS_Initialise(clock_control);
RTC_Initialise(do_init_rtc);
SRC_Initialise();
RCL_Initialise();
@@ -529,13 +556,13 @@ int main
}
if ((pw = getpwnam(user)) == NULL)
- LOG_FATAL(LOGF_Main, "Could not get %s uid/gid", user);
+ 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 user has non-zero uid or gid */
- if (pw->pw_uid || pw->pw_gid)
+ /* Drop root privileges if the specified user has a non-zero UID */
+ if (!geteuid() && (pw->pw_uid || pw->pw_gid))
SYS_DropRoot(pw->pw_uid, pw->pw_gid);
REF_Initialise();
@@ -564,7 +591,7 @@ int main
REF_SetModeEndHandler(reference_mode_end);
REF_SetMode(ref_mode);
- if (timeout)
+ if (timeout > 0)
SCH_AddTimeoutByDelay(timeout, quit_timeout, NULL);
if (do_init_rtc) {
@@ -577,7 +604,7 @@ int main
the scheduler. */
SCH_MainLoop();
- LOG(LOGS_INFO, LOGF_Main, "chronyd exiting");
+ LOG(LOGS_INFO, "chronyd exiting");
MAI_CleanupAndExit();
diff --git a/manual.c b/manual.c
index 4124234..bf52d14 100644
--- a/manual.c
+++ b/manual.c
@@ -97,7 +97,8 @@ MNL_Finalise(void)
/* ================================================== */
static void
-estimate_and_set_system(struct timespec *now, int offset_provided, double offset, long *offset_cs, double *dfreq_ppm, double *new_afreq_ppm)
+estimate_and_set_system(struct timespec *now, int offset_provided, double offset,
+ double *reg_offset, double *dfreq_ppm, double *new_afreq_ppm)
{
double agos[MAX_SAMPLES], offsets[MAX_SAMPLES];
double b0, b1;
@@ -108,32 +109,26 @@ estimate_and_set_system(struct timespec *now, int offset_provided, double offset
int found_freq;
double slew_by;
+ b0 = offset_provided ? offset : 0.0;
+ b1 = freq = 0.0;
+ found_freq = 0;
+
if (n_samples > 1) {
for (i=0; i<n_samples; i++) {
agos[i] = UTI_DiffTimespecsToDouble(&samples[n_samples - 1].when, &samples[i].when);
offsets[i] = samples[i].offset;
}
- RGR_FindBestRobustRegression(agos, offsets, n_samples,
- 1.0e-8, /* 0.01ppm easily good enough for this! */
- &b0, &b1, &n_runs, &best_start);
-
-
- /* Ignore b0 from regression; treat offset as being the most
- recently entered value. (If the administrator knows he's put
- an outlier in, he will rerun the settime operation.) However,
- the frequency estimate comes from the regression. */
-
- freq = -b1;
- found_freq = 1;
- } else {
- if (offset_provided) {
- b0 = offset;
- } else {
- b0 = 0.0;
+ if (RGR_FindBestRobustRegression(agos, offsets, n_samples, 1.0e-8,
+ &b0, &b1, &n_runs, &best_start)) {
+ /* Ignore b0 from regression; treat offset as being the most
+ recently entered value. (If the administrator knows he's put
+ an outlier in, he will rerun the settime operation.) However,
+ the frequency estimate comes from the regression. */
+ freq = -b1;
+ found_freq = 1;
}
- b1 = freq = 0.0;
- found_freq = 0;
+ } else {
agos[0] = 0.0;
offsets[0] = b0;
}
@@ -145,21 +140,20 @@ estimate_and_set_system(struct timespec *now, int offset_provided, double offset
}
if (found_freq) {
- LOG(LOGS_INFO, LOGF_Manual,
- "Making a frequency change of %.3f ppm and a slew of %.6f",
+ LOG(LOGS_INFO, "Making a frequency change of %.3f ppm and a slew of %.6f",
1.0e6 * freq, slew_by);
REF_SetManualReference(now,
slew_by,
freq, skew);
} else {
- LOG(LOGS_INFO, LOGF_Manual, "Making a slew of %.6f", slew_by);
+ LOG(LOGS_INFO, "Making a slew of %.6f", slew_by);
REF_SetManualReference(now,
slew_by,
0.0, skew);
}
- if (offset_cs) *offset_cs = (long)(0.5 + 100.0 * b0);
+ if (reg_offset) *reg_offset = b0;
if (dfreq_ppm) *dfreq_ppm = 1.0e6 * freq;
if (new_afreq_ppm) *new_afreq_ppm = LCL_ReadAbsoluteFrequency();
@@ -173,7 +167,7 @@ estimate_and_set_system(struct timespec *now, int offset_provided, double offset
/* ================================================== */
int
-MNL_AcceptTimestamp(struct timespec *ts, long *offset_cs, double *dfreq_ppm, double *new_afreq_ppm)
+MNL_AcceptTimestamp(struct timespec *ts, double *reg_offset, double *dfreq_ppm, double *new_afreq_ppm)
{
struct timespec now;
double offset, diff;
@@ -210,7 +204,7 @@ MNL_AcceptTimestamp(struct timespec *ts, long *offset_cs, double *dfreq_ppm, dou
samples[n_samples].orig_offset = offset;
++n_samples;
- estimate_and_set_system(&now, 1, offset, offset_cs, dfreq_ppm, new_afreq_ppm);
+ estimate_and_set_system(&now, 1, offset, reg_offset, dfreq_ppm, new_afreq_ppm);
return 1;
diff --git a/manual.h b/manual.h
index 06a5d02..7f3d0b2 100644
--- a/manual.h
+++ b/manual.h
@@ -33,7 +33,7 @@
extern void MNL_Initialise(void);
extern void MNL_Finalise(void);
-extern int MNL_AcceptTimestamp(struct timespec *ts, long *offset_cs, double *dfreq_ppm, double *new_afreq_ppm);
+extern int MNL_AcceptTimestamp(struct timespec *ts, double *reg_offset, double *dfreq_ppm, double *new_afreq_ppm);
extern void MNL_Enable(void);
extern void MNL_Disable(void);
diff --git a/memory.c b/memory.c
index 7ad27d4..03366e5 100644
--- a/memory.c
+++ b/memory.c
@@ -2,7 +2,7 @@
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
* it under the terms of version 2 of the GNU General Public License as
@@ -37,7 +37,7 @@ Malloc(size_t size)
r = malloc(size);
if (!r && size)
- LOG_FATAL(LOGF_Memory, "Could not allocate memory");
+ LOG_FATAL("Could not allocate memory");
return r;
}
@@ -49,11 +49,37 @@ Realloc(void *ptr, size_t size)
r = realloc(ptr, size);
if (!r && size)
- LOG_FATAL(LOGF_Memory, "Could not allocate memory");
+ LOG_FATAL("Could not allocate memory");
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 *
Strdup(const char *s)
{
@@ -61,7 +87,7 @@ Strdup(const char *s)
r = strdup(s);
if (!r)
- LOG_FATAL(LOGF_Memory, "Could not allocate memory");
+ LOG_FATAL("Could not allocate memory");
return r;
}
diff --git a/memory.h b/memory.h
index 3ec0f04..110cf6a 100644
--- a/memory.h
+++ b/memory.h
@@ -30,12 +30,14 @@
/* Wrappers checking for errors */
extern void *Malloc(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);
/* Convenient macros */
#define MallocNew(T) ((T *) Malloc(sizeof(T)))
-#define MallocArray(T, n) ((T *) Malloc((n) * sizeof(T)))
-#define ReallocArray(T,n,x) ((T *) Realloc((void *)(x), (n)*sizeof(T)))
+#define MallocArray(T, n) ((T *) Malloc2(n, sizeof(T)))
+#define ReallocArray(T, n, x) ((T *) Realloc2((void *)(x), n, sizeof(T)))
#define Free(x) free(x)
#endif /* GOT_MEMORY_H */
diff --git a/nameserv_async.c b/nameserv_async.c
index 3e29674..9ad3d17 100644
--- a/nameserv_async.c
+++ b/nameserv_async.c
@@ -78,7 +78,7 @@ end_resolving(int fd, int event, void *anything)
int i;
if (pthread_join(inst->thread, NULL)) {
- LOG_FATAL(LOGF_Nameserv, "pthread_join() failed");
+ LOG_FATAL("pthread_join() failed");
}
resolving_threads--;
@@ -110,7 +110,7 @@ DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *
inst->status = DNS_Failure;
if (pipe(inst->pipe)) {
- LOG_FATAL(LOGF_Nameserv, "pipe() failed");
+ LOG_FATAL("pipe() failed");
}
UTI_FdSetCloexec(inst->pipe[0]);
@@ -120,7 +120,7 @@ DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *
assert(resolving_threads <= 1);
if (pthread_create(&inst->thread, NULL, start_resolving, inst)) {
- LOG_FATAL(LOGF_Nameserv, "pthread_create() failed");
+ LOG_FATAL("pthread_create() failed");
}
SCH_AddFileHandler(inst->pipe[0], SCH_FILE_INPUT, end_resolving, inst);
diff --git a/ntp.h b/ntp.h
index e2abd84..801f264 100644
--- a/ntp.h
+++ b/ntp.h
@@ -38,6 +38,9 @@ typedef struct {
typedef uint32_t NTP_int32;
+/* The UDP port number used by NTP */
+#define NTP_PORT 123
+
/* The NTP protocol version that we support */
#define NTP_VERSION 4
diff --git a/ntp_core.c b/ntp_core.c
index cb38af6..d73111f 100644
--- a/ntp_core.c
+++ b/ntp_core.c
@@ -139,9 +139,8 @@ struct NCR_Instance_Record {
uint32_t auth_key_id; /* The ID of the authentication key to
use. */
- /* Count of how many packets we have transmitted since last successful
- receive from this peer */
- int tx_count;
+ /* Count of transmitted packets since last valid response */
+ unsigned int tx_count;
/* Flag indicating a valid response was received since last request */
int valid_rx;
@@ -179,6 +178,11 @@ struct NCR_Instance_Record {
NTP_int64 local_ntp_tx;
NTP_Local_Timestamp local_tx;
+ /* Previous values of some variables needed in interleaved mode */
+ NTP_Local_Timestamp prev_local_tx;
+ int prev_local_poll;
+ unsigned int prev_tx_count;
+
/* The instance record in the main source management module. This
performs the statistical analysis on the samples we generate */
@@ -261,6 +265,17 @@ static ARR_Instance broadcasts;
/* Maximum poll interval set by KoD RATE */
#define MAX_KOD_RATE_POLL SRC_DEFAULT_MAXPOLL
+/* Maximum number of missed responses to follow peer's polling interval */
+#define MAX_PEER_POLL_TX 8
+
+/* Maximum number of missed responses to accept samples using old timestamps
+ in the interleaved client/server mode */
+#define MAX_CLIENT_INTERLEAVED_TX 4
+
+/* Maximum ratio of local intervals in the timestamp selection of the
+ interleaved mode to prefer a sample using previous timestamps */
+#define MAX_INTERLEAVED_L2L_RATIO 0.1
+
/* Invalid socket, different from the one in ntp_io.c */
#define INVALID_SOCK_FD -2
@@ -336,18 +351,26 @@ do_time_checks(void)
LCL_ReadRawTime(&now);
if (ts2.tv_sec - now.tv_sec < warning_advance)
- LOG(LOGS_WARN, LOGF_NtpCore, "Assumed NTP time ends at %s!",
- UTI_TimeToLogForm(ts2.tv_sec));
+ LOG(LOGS_WARN, "Assumed NTP time ends at %s!", UTI_TimeToLogForm(ts2.tv_sec));
#else
LCL_ReadRawTime(&now);
if (now.tv_sec > 0x7fffffff - warning_advance)
- LOG(LOGS_WARN, LOGF_NtpCore, "System time ends at %s!",
- UTI_TimeToLogForm(0x7fffffff));
+ LOG(LOGS_WARN, "System time ends at %s!", UTI_TimeToLogForm(0x7fffffff));
#endif
}
/* ================================================== */
+static void
+zero_local_timestamp(NTP_Local_Timestamp *ts)
+{
+ UTI_ZeroTimespec(&ts->ts);
+ ts->err = 0.0;
+ ts->source = NTP_TS_DAEMON;
+}
+
+/* ================================================== */
+
void
NCR_Initialise(void)
{
@@ -404,7 +427,8 @@ restart_timeout(NCR_Instance inst, double delay)
/* Start new timer for transmission */
inst->tx_timeout_id = SCH_AddTimeoutInClass(delay, get_separation(inst->local_poll),
SAMPLING_RANDOMNESS,
- SCH_NtpSamplingClass,
+ inst->mode == MODE_CLIENT ?
+ SCH_NtpClientClass : SCH_NtpPeerClass,
transmit_timeout, (void *)inst);
}
@@ -539,11 +563,11 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
result->auth_mode = AUTH_SYMMETRIC;
result->auth_key_id = params->authkey;
if (!KEY_KeyKnown(result->auth_key_id)) {
- LOG(LOGS_WARN, LOGF_NtpCore, "Key %"PRIu32" used by source %s is %s",
+ LOG(LOGS_WARN, "Key %"PRIu32" used by source %s is %s",
result->auth_key_id, UTI_IPToString(&result->remote_addr.ip_addr),
"missing");
} else if (!KEY_CheckKeyLength(result->auth_key_id)) {
- LOG(LOGS_WARN, LOGF_NtpCore, "Key %"PRIu32" used by source %s is %s",
+ LOG(LOGS_WARN, "Key %"PRIu32" used by source %s is %s",
result->auth_key_id, UTI_IPToString(&result->remote_addr.ip_addr),
"too short");
}
@@ -561,7 +585,8 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
result->source = SRC_CreateNewInstance(UTI_IPToRefid(&remote_addr->ip_addr),
SRC_NTP, params->sel_options,
&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->tx_timeout_id = 0;
@@ -569,9 +594,7 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
result->opmode = params->online ? MD_ONLINE : MD_OFFLINE;
result->local_poll = result->minpoll;
result->poll_score = 0.0;
- UTI_ZeroTimespec(&result->local_tx.ts);
- result->local_tx.err = 0.0;
- result->local_tx.source = NTP_TS_DAEMON;
+ zero_local_timestamp(&result->local_tx);
result->burst_good_samples_to_go = 0;
result->burst_total_samples_to_go = 0;
memset(&result->report, 0, sizeof (result->report));
@@ -634,9 +657,11 @@ NCR_ResetInstance(NCR_Instance instance)
UTI_ZeroNtp64(&instance->remote_ntp_tx);
UTI_ZeroNtp64(&instance->local_ntp_rx);
UTI_ZeroNtp64(&instance->local_ntp_tx);
- UTI_ZeroTimespec(&instance->local_rx.ts);
- instance->local_rx.err = 0.0;
- instance->local_rx.source = NTP_TS_DAEMON;
+ zero_local_timestamp(&instance->local_rx);
+
+ zero_local_timestamp(&instance->prev_local_tx);
+ instance->prev_local_poll = 0;
+ instance->prev_tx_count = 0;
}
/* ================================================== */
@@ -710,19 +735,12 @@ static double
get_poll_adj(NCR_Instance inst, double error_in_estimate, double peer_distance)
{
double poll_adj;
+ int samples;
if (error_in_estimate > peer_distance) {
- int shift = 0;
- unsigned long temp = (int)(error_in_estimate / peer_distance);
- do {
- shift++;
- temp>>=1;
- } while (temp);
-
- poll_adj = -shift - inst->poll_score + 0.5;
-
+ poll_adj = -log(error_in_estimate / peer_distance) / log(2.0);
} else {
- int samples = SST_Samples(SRC_GetSourcestats(inst->source));
+ samples = SST_Samples(SRC_GetSourcestats(inst->source));
/* Adjust polling interval so that the number of sourcestats samples
remains close to the target value */
@@ -739,6 +757,24 @@ get_poll_adj(NCR_Instance inst, double error_in_estimate, double peer_distance)
/* ================================================== */
+static int
+get_transmit_poll(NCR_Instance inst)
+{
+ int poll;
+
+ poll = inst->local_poll;
+
+ /* In symmetric mode, if the peer is responding, use shorter of the local
+ and remote poll interval, but not shorter than the minimum */
+ if (inst->mode == MODE_ACTIVE && poll > inst->remote_poll &&
+ inst->tx_count < MAX_PEER_POLL_TX)
+ poll = MAX(inst->remote_poll, inst->minpoll);
+
+ return poll;
+}
+
+/* ================================================== */
+
static double
get_transmit_delay(NCR_Instance inst, int on_tx, double last_tx)
{
@@ -757,45 +793,26 @@ get_transmit_delay(NCR_Instance inst, int on_tx, double last_tx)
we're in client/server mode, we don't care what poll interval the
server responded with last time. */
+ poll_to_use = get_transmit_poll(inst);
+ delay_time = UTI_Log2ToDouble(poll_to_use);
+
switch (inst->opmode) {
case MD_OFFLINE:
assert(0);
break;
case MD_ONLINE:
- /* Normal processing, depending on whether we're in
- client/server or symmetric mode */
-
switch(inst->mode) {
case MODE_CLIENT:
- /* Client/server association - aim at some randomised time
- approx the poll interval away */
- poll_to_use = inst->local_poll;
-
- delay_time = UTI_Log2ToDouble(poll_to_use);
if (inst->presend_done)
delay_time = WARM_UP_DELAY;
-
break;
case MODE_ACTIVE:
- /* Symmetric active association - aim at some randomised time approx
- the poll interval away since the last transmit */
-
- /* Use shorter of the local and remote poll interval, but not shorter
- than the allowed minimum */
- poll_to_use = inst->local_poll;
- if (poll_to_use > inst->remote_poll)
- poll_to_use = inst->remote_poll;
- if (poll_to_use < inst->minpoll)
- poll_to_use = inst->minpoll;
-
- delay_time = UTI_Log2ToDouble(poll_to_use);
-
- /* If the remote stratum is higher than ours, try to lock on the
- peer's polling to minimize our response time by slightly extending
- our delay or waiting for the peer to catch up with us as the
- random part in the actual interval is reduced. If the remote
- stratum is equal to ours, try to interleave evenly with the peer. */
+ /* If the remote stratum is higher than ours, wait a bit for the next
+ packet before responding in order to minimize the delay of the
+ measurement and its error for the peer which has higher stratum.
+ If the remote stratum is equal to ours, try to interleave packets
+ evenly with the peer. */
stratum_diff = inst->remote_stratum - REF_GetOurStratum();
if ((stratum_diff > 0 && last_tx * PEER_SAMPLING_ADJ < delay_time) ||
(!on_tx && !stratum_diff &&
@@ -852,7 +869,7 @@ receive_timeout(void *arg)
{
NCR_Instance inst = (NCR_Instance)arg;
- DEBUG_LOG(LOGF_NtpCore, "Receive timeout for [%s:%d]",
+ DEBUG_LOG("Receive timeout for [%s:%d]",
UTI_IPToString(&inst->remote_addr.ip_addr), inst->remote_addr.port);
inst->rx_timeout_id = 0;
@@ -966,17 +983,24 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
UTI_TimespecToNtp64(&our_ref_time, &message.reference_ts, NULL);
- /* Originate - this comes from the last packet the source sent us */
- message.originate_ts = interleaved ? *remote_ntp_rx : *remote_ntp_tx;
+ /* Don't reveal timestamps which are not necessary for the protocol */
- /* Prepare random bits which will be added to the receive timestamp */
- UTI_GetNtp64Fuzz(&ts_fuzz, precision);
+ if (my_mode != MODE_CLIENT || interleaved) {
+ /* 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.
- 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);
+ /* Prepare random bits which will be added to the receive timestamp */
+ UTI_GetNtp64Fuzz(&ts_fuzz, precision);
+
+ /* 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);
+ } else {
+ UTI_ZeroNtp64(&message.originate_ts);
+ UTI_ZeroNtp64(&message.receive_ts);
+ }
do {
/* Prepare random bits which will be added to the transmit timestamp */
@@ -1009,7 +1033,7 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
(unsigned char *)&message.auth_data,
sizeof (message.auth_data));
if (!auth_len) {
- DEBUG_LOG(LOGF_NtpCore, "Could not generate auth data with key %"PRIu32, key_id);
+ DEBUG_LOG("Could not generate auth data with key %"PRIu32, key_id);
return 0;
}
@@ -1060,7 +1084,7 @@ transmit_timeout(void *arg)
{
NCR_Instance inst = (NCR_Instance) arg;
NTP_Local_Address local_addr;
- int sent;
+ int interleaved, sent;
inst->tx_timeout_id = 0;
@@ -1085,7 +1109,7 @@ transmit_timeout(void *arg)
return;
}
- DEBUG_LOG(LOGF_NtpCore, "Transmit timeout for [%s:%d]",
+ DEBUG_LOG("Transmit timeout for [%s:%d]",
UTI_IPToString(&inst->remote_addr.ip_addr), inst->remote_addr.port);
/* Open new client socket */
@@ -1100,18 +1124,31 @@ transmit_timeout(void *arg)
local_addr.if_index = INVALID_IF_INDEX;
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));
+
/* 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
primed or whether we need to send two packets first to ensure a
server in the interleaved mode has a fresh timestamp for us. */
if (inst->presend_minpoll <= inst->local_poll && !inst->presend_done &&
!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) {
inst->presend_done--;
}
- sent = transmit_packet(inst->mode, inst->interleaved, inst->local_poll,
+ sent = transmit_packet(inst->mode, interleaved, inst->local_poll,
inst->version,
inst->auth_mode, inst->auth_key_id,
&inst->remote_ntp_rx, &inst->remote_ntp_tx,
@@ -1175,12 +1212,12 @@ check_packet_format(NTP_Packet *message, int length)
version = NTP_LVM_TO_VERSION(message->lvm);
if (version < NTP_MIN_COMPAT_VERSION || version > NTP_MAX_COMPAT_VERSION) {
- DEBUG_LOG(LOGF_NtpCore, "NTP packet has invalid version %d", version);
+ DEBUG_LOG("NTP packet has invalid version %d", version);
return 0;
}
if (length < NTP_NORMAL_PACKET_LENGTH || (unsigned int)length % 4) {
- DEBUG_LOG(LOGF_NtpCore, "NTP packet has invalid length %d", length);
+ DEBUG_LOG("NTP packet has invalid length %d", length);
return 0;
}
@@ -1289,6 +1326,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
receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
NTP_Local_Timestamp *rx_ts, NTP_Packet *message, int length)
{
@@ -1341,9 +1439,9 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
measurement in seconds */
double error_in_estimate;
- double remote_interval, local_interval, server_interval;
+ NTP_Local_Timestamp local_receive, local_transmit;
+ double remote_interval, local_interval, response_time;
double delay_time, precision;
- NTP_Timestamp_Source sample_rx_tss;
/* ==================== */
@@ -1413,39 +1511,49 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
if (synced_packet && (!interleaved_packet || inst->valid_timestamps)) {
/* These are the timespec equivalents of the remote and local epochs */
- struct timespec remote_receive, remote_transmit, prev_remote_receive;
- struct timespec local_average, remote_average;
- double rx_ts_err;
+ struct timespec remote_receive, remote_transmit, remote_request_receive;
+ struct timespec local_average, remote_average, prev_remote_transmit;
+ double prev_remote_poll_interval;
- precision = LCL_GetSysPrecisionAsQuantum() +
- UTI_Log2ToDouble(message->precision);
-
- SST_GetFrequencyRange(stats, &source_freq_lo, &source_freq_hi);
-
- UTI_Ntp64ToTimespec(&message->receive_ts, &remote_receive);
- UTI_Ntp64ToTimespec(&message->transmit_ts, &remote_transmit);
-
- /* Calculate intervals between remote and local timestamps */
+ /* Select remote and local timestamps for the new sample */
if (interleaved_packet) {
- UTI_Ntp64ToTimespec(&inst->remote_ntp_rx, &prev_remote_receive);
- UTI_AverageDiffTimespecs(&remote_transmit, &remote_receive,
- &remote_average, &remote_interval);
- UTI_AverageDiffTimespecs(&inst->local_rx.ts, &inst->local_tx.ts,
- &local_average, &local_interval);
- server_interval = UTI_DiffTimespecsToDouble(&remote_transmit,
- &prev_remote_receive);
- rx_ts_err = inst->local_rx.err;
- sample_rx_tss = inst->local_rx.source;
+ /* Prefer previous local TX and remote RX timestamps if it will make
+ the intervals significantly shorter in order to improve the accuracy
+ of the measured delay */
+ if (!UTI_IsZeroTimespec(&inst->prev_local_tx.ts) &&
+ MAX_INTERLEAVED_L2L_RATIO *
+ UTI_DiffTimespecsToDouble(&inst->local_tx.ts, &inst->local_rx.ts) >
+ UTI_DiffTimespecsToDouble(&inst->local_rx.ts, &inst->prev_local_tx.ts)) {
+ UTI_Ntp64ToTimespec(&inst->remote_ntp_rx, &remote_receive);
+ remote_request_receive = remote_receive;
+ local_transmit = inst->prev_local_tx;
+ } else {
+ UTI_Ntp64ToTimespec(&message->receive_ts, &remote_receive);
+ UTI_Ntp64ToTimespec(&inst->remote_ntp_rx, &remote_request_receive);
+ local_transmit = inst->local_tx;
+ }
+ UTI_Ntp64ToTimespec(&message->transmit_ts, &remote_transmit);
+ UTI_Ntp64ToTimespec(&inst->remote_ntp_tx, &prev_remote_transmit);
+ local_receive = inst->local_rx;
} else {
- UTI_AverageDiffTimespecs(&remote_receive, &remote_transmit,
- &remote_average, &remote_interval);
- UTI_AverageDiffTimespecs(&inst->local_tx.ts, &rx_ts->ts,
- &local_average, &local_interval);
- server_interval = remote_interval;
- rx_ts_err = rx_ts->err;
- sample_rx_tss = rx_ts->source;
+ UTI_Ntp64ToTimespec(&message->receive_ts, &remote_receive);
+ UTI_Ntp64ToTimespec(&message->transmit_ts, &remote_transmit);
+ UTI_ZeroTimespec(&prev_remote_transmit);
+ remote_request_receive = remote_receive;
+ local_receive = *rx_ts;
+ local_transmit = inst->local_tx;
}
+ /* Calculate intervals between remote and local timestamps */
+ UTI_AverageDiffTimespecs(&remote_receive, &remote_transmit,
+ &remote_average, &remote_interval);
+ UTI_AverageDiffTimespecs(&local_transmit.ts, &local_receive.ts,
+ &local_average, &local_interval);
+ response_time = fabs(UTI_DiffTimespecsToDouble(&remote_transmit,
+ &remote_request_receive));
+
+ precision = LCL_GetSysPrecisionAsQuantum() + UTI_Log2ToDouble(message->precision);
+
/* Calculate delay */
delay = fabs(local_interval - remote_interval);
if (delay < precision)
@@ -1465,49 +1573,58 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
sample pair. */
sample_time = local_average;
+ SST_GetFrequencyRange(stats, &source_freq_lo, &source_freq_hi);
+
/* Calculate skew */
skew = (source_freq_hi - source_freq_lo) / 2.0;
/* and then calculate peer dispersion */
- dispersion = MAX(precision, MAX(inst->local_tx.err, rx_ts_err)) +
+ dispersion = MAX(precision, MAX(local_transmit.err, local_receive.err)) +
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 */
/* Test A requires that the minimum estimate of the peer delay is not
- larger than the configured maximum, in client mode that the server
- processing time is sane, and in the interleaved symmetric mode that
- the delay is not longer than half of the remote polling interval to
- detect missed packets */
+ larger than the configured maximum, in both client modes that the server
+ processing time is sane, and in interleaved symmetric mode that the
+ measured delay and intervals between remote timestamps don't indicate
+ a missed response */
testA = delay - dispersion <= inst->max_delay && precision <= inst->max_delay &&
- !(inst->mode == MODE_CLIENT && server_interval > MAX_SERVER_INTERVAL) &&
+ !(inst->mode == MODE_CLIENT && response_time > MAX_SERVER_INTERVAL) &&
!(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
- trip delay to the minimum one currently in the stats data register is
- less than an administrator-defined value */
- testB = inst->max_delay_ratio <= 1.0 ||
- !(inst->mode == MODE_CLIENT && !interleaved_packet &&
- (delay - dispersion) / SST_MinRoundTripDelay(stats) > inst->max_delay_ratio);
+ /* Test B requires in client mode that the ratio of the round trip delay
+ to the minimum one currently in the stats data register is less than an
+ administrator-defined value */
+ testB = check_delay_ratio(inst, stats, &sample_time, delay);
/* 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
in the register is less than an administrator-defined value or the
difference between measured offset and predicted offset is larger than
the increase in delay */
- testC = SST_IsGoodSample(stats, -offset, delay, inst->max_delay_dev_ratio,
- LCL_GetMaxClockError(), &sample_time);
+ testC = check_delay_dev_ratio(inst, stats, &sample_time, offset, delay);
/* Test D requires that the remote peer is not synchronised to us to
prevent a synchronisation loop */
testD = message->stratum <= 1 || REF_GetMode() != REF_ModeNormal ||
pkt_refid != UTI_IPToRefid(&local_addr->ip_addr);
} else {
- remote_interval = local_interval = server_interval = 0.0;
+ remote_interval = local_interval = response_time = 0.0;
offset = delay = dispersion = 0.0;
sample_time = rx_ts->ts;
- sample_rx_tss = rx_ts->source;
+ local_receive = *rx_ts;
+ local_transmit = inst->local_tx;
testA = testB = testC = testD = 0;
}
@@ -1536,6 +1653,12 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
inst->local_rx = *rx_ts;
inst->valid_timestamps = synced_packet;
inst->updated_timestamps = 1;
+
+ /* Don't use the same set of timestamps for the next sample */
+ if (interleaved_packet)
+ inst->prev_local_tx = inst->local_tx;
+ else
+ zero_local_timestamp(&inst->prev_local_tx);
}
/* Accept at most one response per request. The NTP specification recommends
@@ -1553,36 +1676,39 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
inst->valid_rx = 1;
}
- if ((int)sample_rx_tss < 0 || sample_rx_tss >= sizeof (tss_chars) ||
- (int)inst->local_tx.source < 0 || inst->local_tx.source >= sizeof (tss_chars))
+ if ((unsigned int)local_receive.source >= sizeof (tss_chars) ||
+ (unsigned int)local_transmit.source >= sizeof (tss_chars))
assert(0);
- DEBUG_LOG(LOGF_NtpCore, "NTP packet lvm=%o stratum=%d poll=%d prec=%d root_delay=%f root_disp=%f refid=%"PRIx32" [%s]",
+ DEBUG_LOG("NTP packet lvm=%o stratum=%d poll=%d prec=%d root_delay=%f root_disp=%f refid=%"PRIx32" [%s]",
message->lvm, message->stratum, message->poll, message->precision,
pkt_root_delay, pkt_root_dispersion, pkt_refid,
message->stratum == NTP_INVALID_STRATUM ? UTI_RefidToString(pkt_refid) : "");
- DEBUG_LOG(LOGF_NtpCore, "reference=%s origin=%s receive=%s transmit=%s",
+ DEBUG_LOG("reference=%s origin=%s receive=%s transmit=%s",
UTI_Ntp64ToString(&message->reference_ts),
UTI_Ntp64ToString(&message->originate_ts),
UTI_Ntp64ToString(&message->receive_ts),
UTI_Ntp64ToString(&message->transmit_ts));
- DEBUG_LOG(LOGF_NtpCore, "offset=%.9f delay=%.9f dispersion=%f root_delay=%f root_dispersion=%f",
+ DEBUG_LOG("offset=%.9f delay=%.9f dispersion=%f root_delay=%f root_dispersion=%f",
offset, delay, dispersion, root_delay, root_dispersion);
- DEBUG_LOG(LOGF_NtpCore, "remote_interval=%.9f local_interval=%.9f server_interval=%.9f txs=%c rxs=%c",
- remote_interval, local_interval, server_interval,
- tss_chars[inst->local_tx.source], tss_chars[sample_rx_tss]);
- DEBUG_LOG(LOGF_NtpCore, "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("remote_interval=%.9f local_interval=%.9f response_time=%.9f txs=%c rxs=%c",
+ remote_interval, local_interval, response_time,
+ 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",
test1, test2, test3, test5, test6, test7, testA, testB, testC, testD,
kod_rate, interleaved_packet, inst->presend_done, valid_packet, good_packet,
!UTI_CompareTimespecs(&inst->local_rx.ts, &rx_ts->ts));
if (valid_packet) {
- if (synced_packet) {
- inst->remote_poll = message->poll;
- inst->remote_stratum = message->stratum;
- inst->tx_count = 0;
- SRC_UpdateReachability(inst->source, 1);
- }
+ inst->remote_poll = message->poll;
+ inst->remote_stratum = message->stratum != NTP_INVALID_STRATUM ?
+ message->stratum : NTP_MAX_STRATUM;
+
+ inst->prev_local_poll = inst->local_poll;
+ inst->prev_tx_count = inst->tx_count;
+ inst->tx_count = 0;
+
+ SRC_UpdateReachability(inst->source, synced_packet);
if (good_packet) {
/* Do this before we accumulate a new sample into the stats registers, obviously */
@@ -1622,7 +1748,7 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
default:
break;
}
- } else if (synced_packet) {
+ } else {
/* Slowly increase the polling interval if we can't get good packet */
adjust_poll(inst, 0.1);
}
@@ -1641,7 +1767,7 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
UTI_DiffTimespecsToDouble(&inst->local_rx.ts, &inst->local_tx.ts));
if (kod_rate) {
- LOG(LOGS_WARN, LOGF_NtpCore, "Received KoD RATE from %s",
+ LOG(LOGS_WARN, "Received KoD RATE from %s",
UTI_IPToString(&inst->remote_addr.ip_addr));
/* Back off for a while and stop ongoing burst */
@@ -1674,15 +1800,15 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
inst->report.offset = offset;
inst->report.peer_delay = delay;
inst->report.peer_dispersion = dispersion;
- inst->report.response_time = server_interval;
+ inst->report.response_time = response_time;
inst->report.jitter_asymmetry = SST_GetJitterAsymmetry(stats);
inst->report.tests = ((((((((test1 << 1 | test2) << 1 | test3) << 1 |
test5) << 1 | test6) << 1 | test7) << 1 |
testA) << 1 | testB) << 1 | testC) << 1 | testD;
inst->report.interleaved = interleaved_packet;
inst->report.authenticated = inst->auth_mode != AUTH_NONE;
- inst->report.tx_tss_char = tss_chars[inst->local_tx.source];
- inst->report.rx_tss_char = tss_chars[sample_rx_tss];
+ inst->report.tx_tss_char = tss_chars[local_transmit.source];
+ inst->report.rx_tss_char = tss_chars[local_receive.source];
inst->report.total_valid_count++;
}
@@ -1700,8 +1826,8 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
offset, delay, dispersion,
pkt_root_delay, pkt_root_dispersion, pkt_refid,
NTP_LVM_TO_MODE(message->lvm), interleaved_packet ? 'I' : 'B',
- tss_chars[inst->local_tx.source],
- tss_chars[sample_rx_tss]);
+ tss_chars[local_transmit.source],
+ tss_chars[local_receive.source]);
}
return good_packet;
@@ -1829,15 +1955,14 @@ NCR_ProcessRxKnown(NCR_Instance inst, NTP_Local_Address *local_addr,
if (proc_packet) {
/* Check if the reply was received by the socket that sent the request */
if (local_addr->sock_fd != inst->local_addr.sock_fd) {
- DEBUG_LOG(LOGF_NtpCore,
- "Packet received by wrong socket %d (expected %d)",
+ DEBUG_LOG("Packet received by wrong socket %d (expected %d)",
local_addr->sock_fd, inst->local_addr.sock_fd);
return 0;
}
/* Ignore packets from offline sources */
if (inst->opmode == MD_OFFLINE || inst->tx_suspended) {
- DEBUG_LOG(LOGF_NtpCore, "Packet from offline source");
+ DEBUG_LOG("Packet from offline source");
return 0;
}
@@ -1847,8 +1972,7 @@ NCR_ProcessRxKnown(NCR_Instance inst, NTP_Local_Address *local_addr,
/* It's not a reply to our request, don't return success */
return 0;
} else {
- DEBUG_LOG(LOGF_NtpCore, "NTP packet discarded pkt_mode=%d our_mode=%d",
- pkt_mode, inst->mode);
+ DEBUG_LOG("NTP packet discarded pkt_mode=%d our_mode=%d", pkt_mode, inst->mode);
return 0;
}
}
@@ -1864,14 +1988,13 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
NTP_Mode pkt_mode, my_mode;
NTP_int64 *local_ntp_rx, *local_ntp_tx;
NTP_Local_Timestamp local_tx, *tx_ts;
- int valid_auth, log_index, interleaved;
+ int valid_auth, log_index, interleaved, poll;
AuthenticationMode auth_mode;
uint32_t key_id;
/* Ignore the packet if it wasn't received by server socket */
if (!NIO_IsServerSocket(local_addr->sock_fd)) {
- DEBUG_LOG(LOGF_NtpCore, "NTP request packet received by client socket %d",
- local_addr->sock_fd);
+ DEBUG_LOG("NTP request packet received by client socket %d", local_addr->sock_fd);
return;
}
@@ -1879,7 +2002,7 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
return;
if (!ADF_IsAllowed(access_auth_table, &remote_addr->ip_addr)) {
- DEBUG_LOG(LOGF_NtpCore, "NTP packet received from unauthorised host %s port %d",
+ DEBUG_LOG("NTP packet received from unauthorised host %s port %d",
UTI_IPToString(&remote_addr->ip_addr),
remote_addr->port);
return;
@@ -1898,7 +2021,7 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
break;
default:
/* Discard */
- DEBUG_LOG(LOGF_NtpCore, "NTP packet discarded pkt_mode=%d", pkt_mode);
+ DEBUG_LOG("NTP packet discarded pkt_mode=%d", pkt_mode);
return;
}
@@ -1906,7 +2029,7 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
/* Don't reply to all requests if the rate is excessive */
if (log_index >= 0 && CLG_LimitNTPResponseRate(log_index)) {
- DEBUG_LOG(LOGF_NtpCore, "NTP packet discarded to limit response rate");
+ DEBUG_LOG("NTP packet discarded to limit response rate");
return;
}
@@ -1924,7 +2047,7 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
break;
default:
/* Discard packets in other modes */
- DEBUG_LOG(LOGF_NtpCore, "NTP packet discarded auth_mode=%d", auth_mode);
+ DEBUG_LOG("NTP packet discarded auth_mode=%d", auth_mode);
return;
}
}
@@ -1952,8 +2075,13 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
}
}
+ /* Suggest the client to increase its polling interval if it indicates
+ the interval is shorter than the rate limiting interval */
+ poll = CLG_GetNtpMinPoll();
+ poll = MAX(poll, message->poll);
+
/* Send a reply */
- transmit_packet(my_mode, interleaved, message->poll, NTP_LVM_TO_VERSION(message->lvm),
+ transmit_packet(my_mode, interleaved, poll, NTP_LVM_TO_VERSION(message->lvm),
auth_mode, key_id, &message->receive_ts, &message->transmit_ts,
rx_ts, tx_ts, local_ntp_rx, NULL, remote_addr, local_addr);
@@ -1971,27 +2099,27 @@ update_tx_timestamp(NTP_Local_Timestamp *tx_ts, NTP_Local_Timestamp *new_tx_ts,
double delay;
if (UTI_IsZeroTimespec(&tx_ts->ts)) {
- DEBUG_LOG(LOGF_NtpCore, "Unexpected TX update");
+ DEBUG_LOG("Unexpected TX update");
return;
}
/* Check if this is the last packet that was sent */
if ((local_ntp_rx && UTI_CompareNtp64(&message->receive_ts, local_ntp_rx)) ||
(local_ntp_tx && UTI_CompareNtp64(&message->transmit_ts, local_ntp_tx))) {
- DEBUG_LOG(LOGF_NtpCore, "RX/TX timestamp mismatch");
+ DEBUG_LOG("RX/TX timestamp mismatch");
return;
}
delay = UTI_DiffTimespecsToDouble(&new_tx_ts->ts, &tx_ts->ts);
if (delay < 0.0 || delay > MAX_TX_DELAY) {
- DEBUG_LOG(LOGF_NtpCore, "Unacceptable TX delay %.9f", delay);
+ DEBUG_LOG("Unacceptable TX delay %.9f", delay);
return;
}
*tx_ts = *new_tx_ts;
- DEBUG_LOG(LOGF_NtpCore, "Updated TX timestamp delay=%.9f", delay);
+ DEBUG_LOG("Updated TX timestamp delay=%.9f", delay);
}
/* ================================================== */
@@ -2058,6 +2186,9 @@ NCR_SlewTimes(NCR_Instance inst, struct timespec *when, double dfreq, double dof
UTI_AdjustTimespec(&inst->local_rx.ts, when, &inst->local_rx.ts, &delta, dfreq, doffset);
if (!UTI_IsZeroTimespec(&inst->local_tx.ts))
UTI_AdjustTimespec(&inst->local_tx.ts, when, &inst->local_tx.ts, &delta, dfreq, doffset);
+ if (!UTI_IsZeroTimespec(&inst->prev_local_tx.ts))
+ UTI_AdjustTimespec(&inst->prev_local_tx.ts, when, &inst->prev_local_tx.ts, &delta, dfreq,
+ doffset);
}
/* ================================================== */
@@ -2070,7 +2201,7 @@ NCR_TakeSourceOnline(NCR_Instance inst)
/* Nothing to do */
break;
case MD_OFFLINE:
- LOG(LOGS_INFO, LOGF_NtpCore, "Source %s online", UTI_IPToString(&inst->remote_addr.ip_addr));
+ LOG(LOGS_INFO, "Source %s online", UTI_IPToString(&inst->remote_addr.ip_addr));
inst->opmode = MD_ONLINE;
NCR_ResetInstance(inst);
start_initial_timeout(inst);
@@ -2080,7 +2211,7 @@ NCR_TakeSourceOnline(NCR_Instance inst)
break;
case MD_BURST_WAS_OFFLINE:
inst->opmode = MD_BURST_WAS_ONLINE;
- LOG(LOGS_INFO, LOGF_NtpCore, "Source %s online", UTI_IPToString(&inst->remote_addr.ip_addr));
+ LOG(LOGS_INFO, "Source %s online", UTI_IPToString(&inst->remote_addr.ip_addr));
break;
}
}
@@ -2092,14 +2223,14 @@ NCR_TakeSourceOffline(NCR_Instance inst)
{
switch (inst->opmode) {
case MD_ONLINE:
- LOG(LOGS_INFO, LOGF_NtpCore, "Source %s offline", UTI_IPToString(&inst->remote_addr.ip_addr));
+ LOG(LOGS_INFO, "Source %s offline", UTI_IPToString(&inst->remote_addr.ip_addr));
take_offline(inst);
break;
case MD_OFFLINE:
break;
case MD_BURST_WAS_ONLINE:
inst->opmode = MD_BURST_WAS_OFFLINE;
- LOG(LOGS_INFO, LOGF_NtpCore, "Source %s offline", UTI_IPToString(&inst->remote_addr.ip_addr));
+ LOG(LOGS_INFO, "Source %s offline", UTI_IPToString(&inst->remote_addr.ip_addr));
break;
case MD_BURST_WAS_OFFLINE:
break;
@@ -2115,7 +2246,7 @@ NCR_ModifyMinpoll(NCR_Instance inst, int new_minpoll)
if (new_minpoll < MIN_MINPOLL || new_minpoll > MAX_POLL)
return;
inst->minpoll = new_minpoll;
- LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new minpoll %d", UTI_IPToString(&inst->remote_addr.ip_addr), new_minpoll);
+ LOG(LOGS_INFO, "Source %s new minpoll %d", UTI_IPToString(&inst->remote_addr.ip_addr), new_minpoll);
if (inst->maxpoll < inst->minpoll)
NCR_ModifyMaxpoll(inst, inst->minpoll);
}
@@ -2128,7 +2259,7 @@ NCR_ModifyMaxpoll(NCR_Instance inst, int new_maxpoll)
if (new_maxpoll < MIN_MAXPOLL || new_maxpoll > MAX_POLL)
return;
inst->maxpoll = new_maxpoll;
- LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new maxpoll %d", UTI_IPToString(&inst->remote_addr.ip_addr), new_maxpoll);
+ LOG(LOGS_INFO, "Source %s new maxpoll %d", UTI_IPToString(&inst->remote_addr.ip_addr), new_maxpoll);
if (inst->minpoll > inst->maxpoll)
NCR_ModifyMinpoll(inst, inst->maxpoll);
}
@@ -2139,7 +2270,7 @@ void
NCR_ModifyMaxdelay(NCR_Instance inst, double new_max_delay)
{
inst->max_delay = CLAMP(0.0, new_max_delay, MAX_MAXDELAY);
- LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new max delay %f",
+ LOG(LOGS_INFO, "Source %s new max delay %f",
UTI_IPToString(&inst->remote_addr.ip_addr), inst->max_delay);
}
@@ -2149,7 +2280,7 @@ void
NCR_ModifyMaxdelayratio(NCR_Instance inst, double new_max_delay_ratio)
{
inst->max_delay_ratio = CLAMP(0.0, new_max_delay_ratio, MAX_MAXDELAYRATIO);
- LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new max delay ratio %f",
+ LOG(LOGS_INFO, "Source %s new max delay ratio %f",
UTI_IPToString(&inst->remote_addr.ip_addr), inst->max_delay_ratio);
}
@@ -2159,7 +2290,7 @@ void
NCR_ModifyMaxdelaydevratio(NCR_Instance inst, double new_max_delay_dev_ratio)
{
inst->max_delay_dev_ratio = CLAMP(0.0, new_max_delay_dev_ratio, MAX_MAXDELAYDEVRATIO);
- LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new max delay dev ratio %f",
+ LOG(LOGS_INFO, "Source %s new max delay dev ratio %f",
UTI_IPToString(&inst->remote_addr.ip_addr), inst->max_delay_dev_ratio);
}
@@ -2169,7 +2300,7 @@ void
NCR_ModifyMinstratum(NCR_Instance inst, int new_min_stratum)
{
inst->min_stratum = new_min_stratum;
- LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new minstratum %d",
+ LOG(LOGS_INFO, "Source %s new minstratum %d",
UTI_IPToString(&inst->remote_addr.ip_addr), new_min_stratum);
}
@@ -2179,7 +2310,7 @@ void
NCR_ModifyPolltarget(NCR_Instance inst, int new_poll_target)
{
inst->poll_target = new_poll_target;
- LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new polltarget %d",
+ LOG(LOGS_INFO, "Source %s new polltarget %d",
UTI_IPToString(&inst->remote_addr.ip_addr), new_poll_target);
}
@@ -2224,7 +2355,7 @@ NCR_InitiateSampleBurst(NCR_Instance inst, int n_good_samples, int n_total_sampl
void
NCR_ReportSource(NCR_Instance inst, RPT_SourceReport *report, struct timespec *now)
{
- report->poll = inst->local_poll;
+ report->poll = get_transmit_poll(inst);
switch (inst->mode) {
case MODE_CLIENT:
@@ -2370,9 +2501,7 @@ broadcast_timeout(void *arg)
poll = log(destination->interval) / log(2.0) + 0.5;
UTI_ZeroNtp64(&orig_ts);
- UTI_ZeroTimespec(&recv_ts.ts);
- recv_ts.source = NTP_TS_DAEMON;
- recv_ts.err = 0.0;
+ zero_local_timestamp(&recv_ts);
transmit_packet(MODE_BROADCAST, 0, poll, NTP_VERSION, 0, 0, &orig_ts, &orig_ts, &recv_ts,
NULL, NULL, NULL, &destination->addr, &destination->local_addr);
diff --git a/ntp_io.c b/ntp_io.c
index 84dcd42..c93e52f 100644
--- a/ntp_io.c
+++ b/ntp_io.c
@@ -130,10 +130,10 @@ prepare_socket(int family, int port_number, int client_only)
if (sock_fd < 0) {
if (!client_only) {
- LOG(LOGS_ERR, LOGF_NtpIO, "Could not open %s NTP socket : %s",
+ LOG(LOGS_ERR, "Could not open %s NTP socket : %s",
UTI_SockaddrFamilyToString(family), strerror(errno));
} else {
- DEBUG_LOG(LOGF_NtpIO, "Could not open %s NTP socket : %s",
+ DEBUG_LOG("Could not open %s NTP socket : %s",
UTI_SockaddrFamilyToString(family), strerror(errno));
}
return INVALID_SOCK_FD;
@@ -193,38 +193,35 @@ prepare_socket(int family, int port_number, int client_only)
/* Make the socket capable of re-using an old address if binding to a specific port */
if (port_number &&
setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on_off, sizeof(on_off)) < 0) {
- LOG(LOGS_ERR, LOGF_NtpIO, "Could not set %s socket option", "SO_REUSEADDR");
+ LOG(LOGS_ERR, "Could not set %s socket option", "SO_REUSEADDR");
/* Don't quit - we might survive anyway */
}
/* Make the socket capable of sending broadcast pkts - needed for NTP broadcast mode */
if (!client_only &&
setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, (char *)&on_off, sizeof(on_off)) < 0) {
- LOG(LOGS_ERR, LOGF_NtpIO, "Could not set %s socket option", "SO_BROADCAST");
+ LOG(LOGS_ERR, "Could not set %s socket option", "SO_BROADCAST");
/* Don't quit - we might survive anyway */
}
-#ifdef SO_TIMESTAMP
- /* Enable receiving of timestamp control messages */
-#ifdef SO_TIMESTAMPNS
- /* Try nanosecond resolution first */
- if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPNS, (char *)&on_off, sizeof(on_off)) < 0)
+ /* Enable kernel/HW timestamping of packets */
+#ifdef HAVE_LINUX_TIMESTAMPING
+ if (!NIO_Linux_SetTimestampSocketOptions(sock_fd, client_only, &events))
#endif
- if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMP, (char *)&on_off, sizeof(on_off)) < 0) {
- LOG(LOGS_ERR, LOGF_NtpIO, "Could not set %s socket option", "SO_TIMESTAMP");
- /* Don't quit - we might survive anyway */
- }
+#ifdef SO_TIMESTAMPNS
+ if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPNS, (char *)&on_off, sizeof(on_off)) < 0)
#endif
-
-#ifdef HAVE_LINUX_TIMESTAMPING
- NIO_Linux_SetTimestampSocketOptions(sock_fd, client_only, &events);
+#ifdef SO_TIMESTAMP
+ if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMP, (char *)&on_off, sizeof(on_off)) < 0)
+ LOG(LOGS_ERR, "Could not set %s socket option", "SO_TIMESTAMP");
#endif
+ ;
#ifdef IP_FREEBIND
/* Allow binding to address that doesn't exist yet */
if (my_addr_len > 0 &&
setsockopt(sock_fd, IPPROTO_IP, IP_FREEBIND, (char *)&on_off, sizeof(on_off)) < 0) {
- LOG(LOGS_ERR, LOGF_NtpIO, "Could not set %s socket option", "IP_FREEBIND");
+ LOG(LOGS_ERR, "Could not set %s socket option", "IP_FREEBIND");
}
#endif
@@ -232,7 +229,7 @@ prepare_socket(int family, int port_number, int client_only)
#ifdef HAVE_IN_PKTINFO
/* We want the local IP info on server sockets */
if (setsockopt(sock_fd, IPPROTO_IP, IP_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
- LOG(LOGS_ERR, LOGF_NtpIO, "Could not set %s socket option", "IP_PKTINFO");
+ LOG(LOGS_ERR, "Could not set %s socket option", "IP_PKTINFO");
/* Don't quit - we might survive anyway */
}
#endif
@@ -242,18 +239,18 @@ prepare_socket(int family, int port_number, int client_only)
#ifdef IPV6_V6ONLY
/* Receive IPv6 packets only */
if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on_off, sizeof(on_off)) < 0) {
- LOG(LOGS_ERR, LOGF_NtpIO, "Could not set %s socket option", "IPV6_V6ONLY");
+ LOG(LOGS_ERR, "Could not set %s socket option", "IPV6_V6ONLY");
}
#endif
#ifdef HAVE_IN6_PKTINFO
#ifdef IPV6_RECVPKTINFO
if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
- LOG(LOGS_ERR, LOGF_NtpIO, "Could not set %s socket option", "IPV6_RECVPKTINFO");
+ LOG(LOGS_ERR, "Could not set %s socket option", "IPV6_RECVPKTINFO");
}
#else
if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
- LOG(LOGS_ERR, LOGF_NtpIO, "Could not set %s socket option", "IPV6_PKTINFO");
+ LOG(LOGS_ERR, "Could not set %s socket option", "IPV6_PKTINFO");
}
#endif
#endif
@@ -262,7 +259,7 @@ prepare_socket(int family, int port_number, int client_only)
/* Bind the socket if a port or address was specified */
if (my_addr_len > 0 && PRV_BindSocket(sock_fd, &my_addr.u, my_addr_len) < 0) {
- LOG(LOGS_ERR, LOGF_NtpIO, "Could not bind %s NTP socket : %s",
+ LOG(LOGS_ERR, "Could not bind %s NTP socket : %s",
UTI_SockaddrFamilyToString(family), strerror(errno));
close(sock_fd);
return INVALID_SOCK_FD;
@@ -304,7 +301,7 @@ connect_socket(int sock_fd, NTP_Remote_Address *remote_addr)
assert(addr_len);
if (connect(sock_fd, &addr.u, addr_len) < 0) {
- DEBUG_LOG(LOGF_NtpIO, "Could not connect NTP socket to %s:%d : %s",
+ DEBUG_LOG("Could not connect NTP socket to %s:%d : %s",
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
strerror(errno));
return 0;
@@ -367,7 +364,7 @@ NIO_Initialise(int family)
if (1) {
CNF_HwTsInterface *conf_iface;
if (CNF_GetHwTsInterface(0, &conf_iface))
- LOG_FATAL(LOGF_NtpIO, "HW timestamping not supported");
+ LOG_FATAL("HW timestamping not supported");
}
#endif
@@ -430,7 +427,7 @@ NIO_Initialise(int family)
&& client_sock_fd6 == INVALID_SOCK_FD
#endif
)) {
- LOG_FATAL(LOGF_NtpIO, "Could not open NTP sockets");
+ LOG_FATAL("Could not open NTP sockets");
}
}
@@ -584,7 +581,7 @@ process_message(struct msghdr *hdr, int length, int sock_fd)
sched_ts = local_ts.ts;
if (hdr->msg_namelen > sizeof (union sockaddr_in46)) {
- DEBUG_LOG(LOGF_NtpIO, "Truncated source address");
+ DEBUG_LOG("Truncated source address");
return;
}
@@ -601,13 +598,13 @@ process_message(struct msghdr *hdr, int length, int sock_fd)
local_addr.sock_fd = sock_fd;
if (hdr->msg_flags & MSG_TRUNC) {
- DEBUG_LOG(LOGF_NtpIO, "Received truncated message from %s:%d",
+ DEBUG_LOG("Received truncated message from %s:%d",
UTI_IPToString(&remote_addr.ip_addr), remote_addr.port);
return;
}
if (hdr->msg_flags & MSG_CTRUNC) {
- DEBUG_LOG(LOGF_NtpIO, "Truncated control message");
+ DEBUG_LOG("Truncated control message");
/* Continue */
}
@@ -663,7 +660,7 @@ process_message(struct msghdr *hdr, int length, int sock_fd)
return;
#endif
- DEBUG_LOG(LOGF_NtpIO, "Received %d bytes from %s:%d to %s fd=%d if=%d tss=%d delay=%.9f",
+ DEBUG_LOG("Received %d bytes from %s:%d to %s fd=%d if=%d tss=%d delay=%.9f",
length, UTI_IPToString(&remote_addr.ip_addr), remote_addr.port,
UTI_IPToString(&local_addr.ip_addr), local_addr.sock_fd, local_addr.if_index,
local_ts.source, UTI_DiffTimespecsToDouble(&sched_ts, &local_ts.ts));
@@ -712,7 +709,7 @@ read_from_socket(int sock_fd, int event, void *anything)
#endif
if (status < 0) {
- DEBUG_LOG(LOGF_NtpIO, "Could not receive from fd %d : %s", sock_fd,
+ DEBUG_LOG("Could not receive from fd %d : %s", sock_fd,
strerror(errno));
return;
}
@@ -743,7 +740,7 @@ NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr,
assert(initialised);
if (local_addr->sock_fd == INVALID_SOCK_FD) {
- DEBUG_LOG(LOGF_NtpIO, "No socket to send to %s:%d",
+ DEBUG_LOG("No socket to send to %s:%d",
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port);
return 0;
}
@@ -819,14 +816,14 @@ NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr,
msg.msg_control = NULL;
if (sendmsg(local_addr->sock_fd, &msg, 0) < 0) {
- DEBUG_LOG(LOGF_NtpIO, "Could not send to %s:%d from %s fd %d : %s",
+ DEBUG_LOG("Could not send to %s:%d from %s fd %d : %s",
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
UTI_IPToString(&local_addr->ip_addr), local_addr->sock_fd,
strerror(errno));
return 0;
}
- DEBUG_LOG(LOGF_NtpIO, "Sent %d bytes to %s:%d from %s fd %d", length,
+ DEBUG_LOG("Sent %d bytes to %s:%d from %s fd %d", length,
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
UTI_IPToString(&local_addr->ip_addr), local_addr->sock_fd);
diff --git a/ntp_io_linux.c b/ntp_io_linux.c
index 4a18fec..00caed0 100644
--- a/ntp_io_linux.c
+++ b/ntp_io_linux.c
@@ -32,7 +32,6 @@
#include <linux/errqueue.h>
#include <linux/ethtool.h>
#include <linux/net_tstamp.h>
-#include <linux/ptp_clock.h>
#include <linux/sockios.h>
#include <net/if.h>
@@ -127,7 +126,7 @@ add_interface(CNF_HwTsInterface *conf_iface)
}
if (ioctl(sock_fd, SIOCGIFINDEX, &req)) {
- DEBUG_LOG(LOGF_NtpIOLinux, "ioctl(%s) failed : %s", "SIOCGIFINDEX", strerror(errno));
+ DEBUG_LOG("ioctl(%s) failed : %s", "SIOCGIFINDEX", strerror(errno));
close(sock_fd);
return 0;
}
@@ -138,7 +137,7 @@ add_interface(CNF_HwTsInterface *conf_iface)
req.ifr_data = (char *)&ts_info;
if (ioctl(sock_fd, SIOCETHTOOL, &req)) {
- DEBUG_LOG(LOGF_NtpIOLinux, "ioctl(%s) failed : %s", "SIOCETHTOOL", strerror(errno));
+ DEBUG_LOG("ioctl(%s) failed : %s", "SIOCETHTOOL", strerror(errno));
close(sock_fd);
return 0;
}
@@ -146,18 +145,43 @@ add_interface(CNF_HwTsInterface *conf_iface)
req_hwts_flags = SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RAW_HARDWARE;
if ((ts_info.so_timestamping & req_hwts_flags) != req_hwts_flags) {
- DEBUG_LOG(LOGF_NtpIOLinux, "HW timestamping not supported on %s", req.ifr_name);
+ DEBUG_LOG("HW timestamping not supported on %s", req.ifr_name);
close(sock_fd);
return 0;
}
ts_config.flags = 0;
ts_config.tx_type = HWTSTAMP_TX_ON;
- ts_config.rx_filter = HWTSTAMP_FILTER_ALL;
+
+ 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:
+ ts_config.rx_filter = HWTSTAMP_FILTER_NONE;
+ break;
+#ifdef HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP
+ case CNF_HWTS_RXFILTER_NTP:
+ ts_config.rx_filter = HWTSTAMP_FILTER_NTP_ALL;
+ break;
+#endif
+ default:
+ ts_config.rx_filter = HWTSTAMP_FILTER_ALL;
+ break;
+ }
+
req.ifr_data = (char *)&ts_config;
if (ioctl(sock_fd, SIOCSHWTSTAMP, &req)) {
- DEBUG_LOG(LOGF_NtpIOLinux, "ioctl(%s) failed : %s", "SIOCSHWTSTAMP", strerror(errno));
+ DEBUG_LOG("ioctl(%s) failed : %s", "SIOCSHWTSTAMP", strerror(errno));
close(sock_fd);
return 0;
}
@@ -187,7 +211,8 @@ add_interface(CNF_HwTsInterface *conf_iface)
iface->clock = HCL_CreateInstance(UTI_Log2ToDouble(MAX(conf_iface->minpoll, MIN_PHC_POLL)));
- LOG(LOGS_INFO, LOGF_NtpIOLinux, "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;
}
@@ -204,7 +229,7 @@ add_all_interfaces(CNF_HwTsInterface *conf_iface_all)
conf_iface = *conf_iface_all;
if (getifaddrs(&ifaddr)) {
- DEBUG_LOG(LOGF_NtpIOLinux, "getifaddrs() failed : %s", strerror(errno));
+ DEBUG_LOG("getifaddrs() failed : %s", strerror(errno));
return 0;
}
@@ -241,7 +266,7 @@ update_interface_speed(struct Interface *iface)
req.ifr_data = (char *)&cmd;
if (ioctl(sock_fd, SIOCETHTOOL, &req)) {
- DEBUG_LOG(LOGF_NtpIOLinux, "ioctl(%s) failed : %s", "SIOCETHTOOL", strerror(errno));
+ DEBUG_LOG("ioctl(%s) failed : %s", "SIOCETHTOOL", strerror(errno));
close(sock_fd);
return;
}
@@ -253,6 +278,29 @@ update_interface_speed(struct Interface *iface)
/* ================================================== */
+#if defined(HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO) || defined(HAVE_LINUX_TIMESTAMPING_OPT_TX_SWHW)
+static int
+check_timestamping_option(int option)
+{
+ int sock_fd;
+
+ sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock_fd < 0)
+ return 0;
+
+ if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPING, &option, sizeof (option)) < 0) {
+ DEBUG_LOG("Could not enable timestamping option %x", option);
+ close(sock_fd);
+ return 0;
+ }
+
+ close(sock_fd);
+ return 1;
+}
+#endif
+
+/* ================================================== */
+
void
NIO_Linux_Initialise(void)
{
@@ -269,7 +317,7 @@ NIO_Linux_Initialise(void)
if (!strcmp("*", conf_iface->name))
continue;
if (!add_interface(conf_iface))
- LOG_FATAL(LOGF_NtpIO, "Could not enable HW timestamping on %s", conf_iface->name);
+ LOG_FATAL("Could not enable HW timestamping on %s", conf_iface->name);
hwts = 1;
}
@@ -281,12 +329,20 @@ NIO_Linux_Initialise(void)
break;
}
+ ts_flags = SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_RX_SOFTWARE;
+ ts_tx_flags = SOF_TIMESTAMPING_TX_SOFTWARE;
+
if (hwts) {
- ts_flags = SOF_TIMESTAMPING_RAW_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE;
- ts_tx_flags = SOF_TIMESTAMPING_TX_HARDWARE;
- } else {
- ts_flags = SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_RX_SOFTWARE;
- ts_tx_flags = SOF_TIMESTAMPING_TX_SOFTWARE;
+ ts_flags |= SOF_TIMESTAMPING_RAW_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE;
+ ts_tx_flags |= SOF_TIMESTAMPING_TX_HARDWARE;
+#ifdef HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO
+ if (check_timestamping_option(SOF_TIMESTAMPING_OPT_PKTINFO))
+ ts_flags |= SOF_TIMESTAMPING_OPT_PKTINFO;
+#endif
+#ifdef HAVE_LINUX_TIMESTAMPING_OPT_TX_SWHW
+ if (check_timestamping_option(SOF_TIMESTAMPING_OPT_TX_SWHW))
+ ts_flags |= SOF_TIMESTAMPING_OPT_TX_SWHW;
+#endif
}
/* Enable IP_PKTINFO in messages looped back to the error queue */
@@ -333,13 +389,13 @@ NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events)
flags |= ts_tx_flags;
if (setsockopt(sock_fd, SOL_SOCKET, SO_SELECT_ERR_QUEUE, &val, sizeof (val)) < 0) {
- LOG(LOGS_ERR, LOGF_NtpIOLinux, "Could not set %s socket option", "SO_SELECT_ERR_QUEUE");
+ LOG(LOGS_ERR, "Could not set %s socket option", "SO_SELECT_ERR_QUEUE");
ts_flags = 0;
return 0;
}
if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPING, &flags, sizeof (flags)) < 0) {
- LOG(LOGS_ERR, LOGF_NtpIOLinux, "Could not set %s socket option", "SO_TIMESTAMPING");
+ LOG(LOGS_ERR, "Could not set %s socket option", "SO_TIMESTAMPING");
ts_flags = 0;
return 0;
}
@@ -371,53 +427,56 @@ get_interface(int if_index)
static void
process_hw_timestamp(struct Interface *iface, struct timespec *hw_ts,
- NTP_Local_Timestamp *local_ts, int rx_ntp_length, int family)
+ NTP_Local_Timestamp *local_ts, int rx_ntp_length, int family,
+ int l2_length)
{
struct timespec sample_phc_ts, sample_sys_ts, sample_local_ts, ts;
- double rx_correction, ts_delay, err;
- int l2_length;
+ double rx_correction, ts_delay, phc_err, local_err;
if (HCL_NeedsNewSample(iface->clock, &local_ts->ts)) {
if (!SYS_Linux_GetPHCSample(iface->phc_fd, iface->phc_nocrossts, iface->precision,
- &iface->phc_mode, &sample_phc_ts, &sample_sys_ts, &err))
+ &iface->phc_mode, &sample_phc_ts, &sample_sys_ts,
+ &phc_err))
return;
- LCL_CookTime(&sample_sys_ts, &sample_local_ts, NULL);
- HCL_AccumulateSample(iface->clock, &sample_phc_ts, &sample_local_ts, err);
+ LCL_CookTime(&sample_sys_ts, &sample_local_ts, &local_err);
+ HCL_AccumulateSample(iface->clock, &sample_phc_ts, &sample_local_ts,
+ phc_err + local_err);
update_interface_speed(iface);
}
/* We need to transpose RX timestamps as hardware timestamps are normally
preamble timestamps and RX timestamps in NTP are supposed to be trailer
- timestamps. Without raw sockets we don't know the length of the packet
- at layer 2, so we make an assumption that UDP data start at the same
- position as in the last transmitted packet which had a HW TX timestamp. */
+ timestamps. If we don't know the length of the packet at layer 2, we
+ make an assumption that UDP data start at the same position as in the
+ last transmitted packet which had a HW TX timestamp. */
if (rx_ntp_length && iface->link_speed) {
- l2_length = (family == IPADDR_INET4 ? iface->l2_udp4_ntp_start :
- iface->l2_udp6_ntp_start) + rx_ntp_length + 4;
+ if (!l2_length)
+ l2_length = (family == IPADDR_INET4 ? iface->l2_udp4_ntp_start :
+ iface->l2_udp6_ntp_start) + rx_ntp_length + 4;
rx_correction = l2_length / (1.0e6 / 8 * iface->link_speed);
UTI_AddDoubleToTimespec(hw_ts, rx_correction, hw_ts);
}
+ if (!HCL_CookTime(iface->clock, hw_ts, &ts, &local_err))
+ return;
+
if (!rx_ntp_length && iface->tx_comp)
- UTI_AddDoubleToTimespec(hw_ts, iface->tx_comp, hw_ts);
+ UTI_AddDoubleToTimespec(&ts, iface->tx_comp, &ts);
else if (rx_ntp_length && iface->rx_comp)
- UTI_AddDoubleToTimespec(hw_ts, -iface->rx_comp, hw_ts);
-
- if (!HCL_CookTime(iface->clock, hw_ts, &ts, &err))
- return;
+ UTI_AddDoubleToTimespec(&ts, -iface->rx_comp, &ts);
ts_delay = UTI_DiffTimespecsToDouble(&local_ts->ts, &ts);
if (fabs(ts_delay) > MAX_TS_DELAY) {
- DEBUG_LOG(LOGF_NtpIOLinux, "Unacceptable timestamp delay %.9f", ts_delay);
+ DEBUG_LOG("Unacceptable timestamp delay %.9f", ts_delay);
return;
}
local_ts->ts = ts;
- local_ts->err = err;
+ local_ts->err = local_err;
local_ts->source = NTP_TS_HARDWARE;
}
@@ -462,14 +521,43 @@ extract_udp_data(unsigned char *msg, NTP_Remote_Address *remote_addr, int len)
len -= ihl + 8, msg += ihl + 8;
#ifdef FEAT_IPV6
} else if (len >= 48 && msg[0] >> 4 == 6) {
- /* IPv6 extension headers are not supported */
- if (msg[6] != 17)
- return 0;
+ int eh_len, next_header = msg[6];
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;
- len -= 48, msg += 48;
+ len -= 8, msg += 8;
#endif
} else {
return 0;
@@ -492,30 +580,47 @@ NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *loc
{
struct Interface *iface;
struct cmsghdr *cmsg;
- int is_tx, l2_length;
+ int is_tx, ts_if_index, l2_length;
is_tx = hdr->msg_flags & MSG_ERRQUEUE;
iface = NULL;
+ ts_if_index = local_addr->if_index;
+ l2_length = 0;
for (cmsg = CMSG_FIRSTHDR(hdr); cmsg; cmsg = CMSG_NXTHDR(hdr, cmsg)) {
+#ifdef HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO
+ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPING_PKTINFO) {
+ struct scm_ts_pktinfo ts_pktinfo;
+
+ memcpy(&ts_pktinfo, CMSG_DATA(cmsg), sizeof (ts_pktinfo));
+
+ ts_if_index = ts_pktinfo.if_index;
+ l2_length = ts_pktinfo.pkt_length;
+
+ DEBUG_LOG("Received HW timestamp info if=%d length=%d", ts_if_index, l2_length);
+ }
+#endif
+
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPING) {
struct scm_timestamping ts3;
memcpy(&ts3, CMSG_DATA(cmsg), sizeof (ts3));
- if (!UTI_IsZeroTimespec(&ts3.ts[0])) {
- LCL_CookTime(&ts3.ts[0], &local_ts->ts, &local_ts->err);
- local_ts->source = NTP_TS_KERNEL;
- } else if (!UTI_IsZeroTimespec(&ts3.ts[2])) {
- iface = get_interface(local_addr->if_index);
+ if (!UTI_IsZeroTimespec(&ts3.ts[2])) {
+ iface = get_interface(ts_if_index);
if (iface) {
process_hw_timestamp(iface, &ts3.ts[2], local_ts, !is_tx ? length : 0,
- remote_addr->ip_addr.family);
+ remote_addr->ip_addr.family, l2_length);
} else {
- DEBUG_LOG(LOGF_NtpIOLinux, "HW clock not found for interface %d",
- local_addr->if_index);
+ DEBUG_LOG("HW clock not found for interface %d", ts_if_index);
}
}
+
+ if (local_ts->source == NTP_TS_DAEMON && !UTI_IsZeroTimespec(&ts3.ts[0]) &&
+ (!is_tx || UTI_IsZeroTimespec(&ts3.ts[2]))) {
+ LCL_CookTime(&ts3.ts[0], &local_ts->ts, &local_ts->err);
+ local_ts->source = NTP_TS_KERNEL;
+ }
}
if ((cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) ||
@@ -526,7 +631,7 @@ NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *loc
if (err.ee_errno != ENOMSG || err.ee_info != SCM_TSTAMP_SND ||
err.ee_origin != SO_EE_ORIGIN_TIMESTAMPING) {
- DEBUG_LOG(LOGF_NtpIOLinux, "Unknown extended error");
+ DEBUG_LOG("Unknown extended error");
/* Drop the message */
return 1;
}
@@ -543,7 +648,7 @@ NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *loc
l2_length = length;
length = extract_udp_data(hdr->msg_iov[0].iov_base, remote_addr, length);
- DEBUG_LOG(LOGF_NtpIOLinux, "Received %d (%d) bytes from error queue for %s:%d fd=%d if=%d tss=%d",
+ DEBUG_LOG("Received %d (%d) bytes from error queue for %s:%d fd=%d if=%d tss=%d",
l2_length, length, UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
local_addr->sock_fd, local_addr->if_index, local_ts->source);
@@ -555,9 +660,9 @@ NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *loc
iface->l2_udp6_ntp_start = l2_length - length;
}
- /* Drop the message if HW timestamp is missing or its processing failed */
- if ((ts_flags & SOF_TIMESTAMPING_RAW_HARDWARE) && local_ts->source != NTP_TS_HARDWARE) {
- DEBUG_LOG(LOGF_NtpIOLinux, "Missing HW timestamp");
+ /* Drop the message if it has no timestamp or its processing failed */
+ if (local_ts->source == NTP_TS_DAEMON) {
+ DEBUG_LOG("Missing TX timestamp");
return 1;
}
diff --git a/ntp_signd.c b/ntp_signd.c
index 1469668..0d88d7b 100644
--- a/ntp_signd.c
+++ b/ntp_signd.c
@@ -135,7 +135,7 @@ open_socket(void)
sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock_fd < 0) {
- DEBUG_LOG(LOGF_NtpSignd, "Could not open signd socket : %s", strerror(errno));
+ DEBUG_LOG("Could not open signd socket : %s", strerror(errno));
return 0;
}
@@ -145,18 +145,18 @@ open_socket(void)
s.sun_family = AF_UNIX;
if (snprintf(s.sun_path, sizeof (s.sun_path), "%s/socket",
CNF_GetNtpSigndSocket()) >= sizeof (s.sun_path)) {
- DEBUG_LOG(LOGF_NtpSignd, "signd socket path too long");
+ DEBUG_LOG("signd socket path too long");
close_socket();
return 0;
}
if (connect(sock_fd, (struct sockaddr *)&s, sizeof (s)) < 0) {
- DEBUG_LOG(LOGF_NtpSignd, "Could not connect to signd : %s", strerror(errno));
+ DEBUG_LOG("Could not connect to signd : %s", strerror(errno));
close_socket();
return 0;
}
- DEBUG_LOG(LOGF_NtpSignd, "Connected to signd");
+ DEBUG_LOG("Connected to signd");
return 1;
}
@@ -170,25 +170,25 @@ process_response(SignInstance *inst)
double delay;
if (ntohs(inst->request.packet_id) != ntohl(inst->response.packet_id)) {
- DEBUG_LOG(LOGF_NtpSignd, "Invalid response ID");
+ DEBUG_LOG("Invalid response ID");
return;
}
if (ntohl(inst->response.op) != SIGNING_SUCCESS) {
- DEBUG_LOG(LOGF_NtpSignd, "Signing failed");
+ DEBUG_LOG("Signing failed");
return;
}
/* Check if the file descriptor is still valid */
if (!NIO_IsServerSocket(inst->local_addr.sock_fd)) {
- DEBUG_LOG(LOGF_NtpSignd, "Invalid NTP socket");
+ DEBUG_LOG("Invalid NTP socket");
return;
}
SCH_GetLastEventTime(NULL, NULL, &ts);
delay = UTI_DiffTimespecsToDouble(&ts, &inst->request_ts);
- DEBUG_LOG(LOGF_NtpSignd, "Signing succeeded (delay %f)", delay);
+ DEBUG_LOG("Signing succeeded (delay %f)", delay);
/* Send the signed NTP packet */
NIO_SendPacket(&inst->response.signed_packet, &inst->remote_addr, &inst->local_addr,
@@ -222,12 +222,12 @@ read_write_socket(int sock_fd, int event, void *anything)
inst->request_length - inst->sent, 0);
if (s < 0) {
- DEBUG_LOG(LOGF_NtpSignd, "signd socket error: %s", strerror(errno));
+ DEBUG_LOG("signd socket error: %s", strerror(errno));
close_socket();
return;
}
- DEBUG_LOG(LOGF_NtpSignd, "Sent %d bytes to signd", s);
+ DEBUG_LOG("Sent %d bytes to signd", s);
inst->sent += s;
/* Try again later if the request is not complete yet */
@@ -240,7 +240,7 @@ read_write_socket(int sock_fd, int event, void *anything)
if (event == SCH_FILE_INPUT) {
if (IS_QUEUE_EMPTY()) {
- DEBUG_LOG(LOGF_NtpSignd, "Unexpected signd response");
+ DEBUG_LOG("Unexpected signd response");
close_socket();
return;
}
@@ -251,15 +251,15 @@ read_write_socket(int sock_fd, int event, void *anything)
if (s <= 0) {
if (s < 0)
- DEBUG_LOG(LOGF_NtpSignd, "signd socket error: %s", strerror(errno));
+ DEBUG_LOG("signd socket error: %s", strerror(errno));
else
- DEBUG_LOG(LOGF_NtpSignd, "signd socket closed");
+ DEBUG_LOG("signd socket closed");
close_socket();
return;
}
- DEBUG_LOG(LOGF_NtpSignd, "Received %d bytes from signd", s);
+ DEBUG_LOG("Received %d bytes from signd", s);
inst->received += s;
if (inst->received < sizeof (inst->response.length))
@@ -269,7 +269,7 @@ read_write_socket(int sock_fd, int event, void *anything)
if (response_length < offsetof(SigndResponse, signed_packet) ||
response_length > sizeof (SigndResponse)) {
- DEBUG_LOG(LOGF_NtpSignd, "Invalid response length");
+ DEBUG_LOG("Invalid response length");
close_socket();
return;
}
@@ -303,7 +303,7 @@ NSD_Initialise()
ARR_SetSize(queue, MAX_QUEUE_LENGTH);
queue_head = queue_tail = 0;
- LOG(LOGS_INFO, LOGF_NtpSignd, "MS-SNTP authentication enabled");
+ LOG(LOGS_INFO, "MS-SNTP authentication enabled");
}
/* ================================================== */
@@ -333,17 +333,17 @@ NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_Remote_Address *r
SignInstance *inst;
if (!enabled) {
- DEBUG_LOG(LOGF_NtpSignd, "signd disabled");
+ DEBUG_LOG("signd disabled");
return 0;
}
if (queue_head == NEXT_QUEUE_INDEX(queue_tail)) {
- DEBUG_LOG(LOGF_NtpSignd, "signd queue full");
+ DEBUG_LOG("signd queue full");
return 0;
}
if (length != NTP_NORMAL_PACKET_LENGTH) {
- DEBUG_LOG(LOGF_NtpSignd, "Invalid packet length");
+ DEBUG_LOG("Invalid packet length");
return 0;
}
@@ -373,8 +373,7 @@ NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_Remote_Address *r
queue_tail = NEXT_QUEUE_INDEX(queue_tail);
- DEBUG_LOG(LOGF_NtpSignd, "Packet added to signd queue (%u:%u)",
- queue_head, queue_tail);
+ DEBUG_LOG("Packet added to signd queue (%u:%u)", queue_head, queue_tail);
return 1;
}
diff --git a/ntp_sources.c b/ntp_sources.c
index 5024a42..ff0be6e 100644
--- a/ntp_sources.c
+++ b/ntp_sources.c
@@ -39,6 +39,7 @@
#include "local.h"
#include "memory.h"
#include "nameserv_async.h"
+#include "privops.h"
#include "sched.h"
/* ================================================== */
@@ -354,7 +355,7 @@ replace_source(NTP_Remote_Address *old_addr, NTP_Remote_Address *new_addr)
/* The hash table must be rebuilt for the new address */
rehash_records();
- LOG(LOGS_INFO, LOGF_NtpSources, "Source %s replaced with %s",
+ LOG(LOGS_INFO, "Source %s replaced with %s",
UTI_IPToString(&old_addr->ip_addr),
UTI_IPToString(&new_addr->ip_addr));
@@ -377,7 +378,7 @@ process_resolved_name(struct UnresolvedSource *us, IPAddr *ip_addrs, int n_addrs
address.ip_addr = ip_addrs[((unsigned int)i + first) % n_addrs];
address.port = us->port;
- DEBUG_LOG(LOGF_NtpSources, "(%d) %s", i + 1, UTI_IPToString(&address.ip_addr));
+ DEBUG_LOG("(%d) %s", i + 1, UTI_IPToString(&address.ip_addr));
if (us->replacement) {
if (replace_source(&us->replace_source, &address) != NSR_AlreadyInUse)
@@ -404,7 +405,7 @@ name_resolve_handler(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *any
assert(us == resolving_source);
- DEBUG_LOG(LOGF_NtpSources, "%s resolved to %d addrs", us->name, n_addrs);
+ DEBUG_LOG("%s resolved to %d addrs", us->name, n_addrs);
switch (status) {
case DNS_TryAgain:
@@ -413,7 +414,7 @@ name_resolve_handler(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *any
process_resolved_name(us, ip_addrs, n_addrs);
break;
case DNS_Failure:
- LOG(LOGS_WARN, LOGF_NtpSources, "Invalid host %s", us->name);
+ LOG(LOGS_WARN, "Invalid host %s", us->name);
break;
default:
assert(0);
@@ -438,7 +439,7 @@ name_resolve_handler(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *any
if (next) {
/* Continue with the next source in the list */
- DEBUG_LOG(LOGF_NtpSources, "resolving %s", next->name);
+ DEBUG_LOG("resolving %s", next->name);
DNS_Name2IPAddressAsync(next->name, name_resolve_handler, next);
} else {
/* This was the last source in the list. If some sources couldn't
@@ -469,14 +470,14 @@ resolve_sources(void *arg)
assert(!resolving_source);
- DNS_Reload();
+ PRV_ReloadDNS();
/* Start with the first source in the list, name_resolve_handler
will iterate over the rest */
us = unresolved_sources;
resolving_source = us;
- DEBUG_LOG(LOGF_NtpSources, "resolving %s", us->name);
+ DEBUG_LOG("resolving %s", us->name);
DNS_Name2IPAddressAsync(us->name, name_resolve_handler, us);
}
@@ -657,8 +658,7 @@ resolve_source_replacement(SourceRecord *record)
{
struct UnresolvedSource *us;
- DEBUG_LOG(LOGF_NtpSources, "trying to replace %s",
- UTI_IPToString(&record->remote_addr->ip_addr));
+ DEBUG_LOG("trying to replace %s", UTI_IPToString(&record->remote_addr->ip_addr));
us = MallocNew(struct UnresolvedSource);
us->name = Strdup(record->name);
@@ -704,7 +704,7 @@ NSR_HandleBadSource(IPAddr *address)
SCH_GetLastEventTime(NULL, NULL, &now);
diff = UTI_DiffTimespecsToDouble(&now, &last_replacement);
if (fabs(diff) < RESOLVE_INTERVAL_UNIT * (1 << MIN_REPLACEMENT_INTERVAL)) {
- DEBUG_LOG(LOGF_NtpSources, "replacement postponed");
+ DEBUG_LOG("replacement postponed");
return;
}
last_replacement = now;
@@ -742,7 +742,7 @@ static void remove_tentative_pool_sources(int pool)
if (!record->remote_addr || record->pool != pool || !record->tentative)
continue;
- DEBUG_LOG(LOGF_NtpSources, "removing tentative source %s",
+ DEBUG_LOG("removing tentative source %s",
UTI_IPToString(&record->remote_addr->ip_addr));
clean_source_record(record);
@@ -800,8 +800,7 @@ NSR_ProcessRx(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
pool = ARR_GetElement(pools, record->pool);
pool->sources++;
- DEBUG_LOG(LOGF_NtpSources, "pool %s has %d confirmed sources",
- record->name, pool->sources);
+ DEBUG_LOG("pool %s has %d confirmed sources", record->name, pool->sources);
/* If the number of sources from the pool reached the configured
maximum, remove the remaining tentative sources */
diff --git a/pktlength.c b/pktlength.c
index 84facb6..23a1b47 100644
--- a/pktlength.c
+++ b/pktlength.c
@@ -114,8 +114,10 @@ static const struct request_length request_lengths[] = {
client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX2 */
REQ_LENGTH_ENTRY(local, null), /* LOCAL2 */
REQ_LENGTH_ENTRY(ntp_data, ntp_data), /* NTP_DATA */
- REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_SERVER2 */
- REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_PEER2 */
+ { 0, 0 }, /* ADD_SERVER2 */
+ { 0, 0 }, /* ADD_PEER2 */
+ REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_SERVER3 */
+ REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_PEER3 */
};
static const uint16_t reply_lengths[] = {
@@ -123,7 +125,7 @@ static const uint16_t reply_lengths[] = {
RPY_LENGTH_ENTRY(null), /* NULL */
RPY_LENGTH_ENTRY(n_sources), /* N_SOURCES */
RPY_LENGTH_ENTRY(source_data), /* SOURCE_DATA */
- RPY_LENGTH_ENTRY(manual_timestamp), /* MANUAL_TIMESTAMP */
+ 0, /* MANUAL_TIMESTAMP */
RPY_LENGTH_ENTRY(tracking), /* TRACKING */
RPY_LENGTH_ENTRY(sourcestats), /* SOURCESTATS */
RPY_LENGTH_ENTRY(rtc), /* RTC */
@@ -136,6 +138,7 @@ static const uint16_t reply_lengths[] = {
RPY_LENGTH_ENTRY(server_stats), /* SERVER_STATS */
RPY_LENGTH_ENTRY(client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX2 */
RPY_LENGTH_ENTRY(ntp_data), /* NTP_DATA */
+ RPY_LENGTH_ENTRY(manual_timestamp), /* MANUAL_TIMESTAMP2 */
};
/* ================================================== */
diff --git a/privops.c b/privops.c
index b588131..a7ba890 100644
--- a/privops.c
+++ b/privops.c
@@ -3,7 +3,7 @@
**********************************************************************
* 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
* it under the terms of version 2 of the GNU General Public License as
@@ -40,6 +40,7 @@
#define OP_SETTIME 1026
#define OP_BINDSOCKET 1027
#define OP_NAME2IPADDRESS 1028
+#define OP_RELOADDNS 1029
#define OP_QUIT 1099
union sockaddr_in46 {
@@ -293,8 +294,6 @@ do_name_to_ipaddress(ReqName2IPAddress *req, PrvResponse *res)
/* make sure the string is terminated */
req->name[sizeof (req->name) - 1] = '\0';
- DNS_Reload();
-
res->rc = DNS_Name2IPAddress(req->name, res->data.name_to_ipaddress.addresses,
DNS_MAX_ADDRESSES);
}
@@ -302,6 +301,19 @@ do_name_to_ipaddress(ReqName2IPAddress *req, PrvResponse *res)
/* ======================================================================= */
+/* HELPER - perform DNS_Reload() */
+
+#ifdef PRIVOPS_RELOADDNS
+static void
+do_reload_dns(PrvResponse *res)
+{
+ DNS_Reload();
+ res->rc = 0;
+}
+#endif
+
+/* ======================================================================= */
+
/* HELPER - main loop - action requests from the daemon */
static void
@@ -344,6 +356,11 @@ helper_main(int fd)
do_name_to_ipaddress(&req.data.name_to_ipaddress, &res);
break;
#endif
+#ifdef PRIVOPS_RELOADDNS
+ case OP_RELOADDNS:
+ do_reload_dns(&res);
+ break;
+#endif
case OP_QUIT:
quit = 1;
continue;
@@ -371,14 +388,14 @@ receive_response(PrvResponse *res)
resp_len = recv(helper_fd, res, sizeof (*res), 0);
if (resp_len < 0)
- LOG_FATAL(LOGF_PrivOps, "Could not read from helper : %s", strerror(errno));
+ LOG_FATAL("Could not read from helper : %s", strerror(errno));
if (resp_len != sizeof (*res))
- LOG_FATAL(LOGF_PrivOps, "Invalid helper response");
+ LOG_FATAL("Invalid helper response");
if (res->fatal_error)
- LOG_FATAL(LOGF_PrivOps, "Error in helper : %s", res->data.fatal_msg.msg);
+ LOG_FATAL("Error in helper : %s", res->data.fatal_msg.msg);
- DEBUG_LOG(LOGF_PrivOps, "Received response rc=%d", res->rc);
+ DEBUG_LOG("Received response rc=%d", res->rc);
/* if operation failed in the helper, set errno so daemon can print log message */
if (res->res_errno)
@@ -429,10 +446,10 @@ send_request(PrvRequest *req)
if (sendmsg(helper_fd, &msg, 0) < 0) {
/* don't try to send another request from exit() */
helper_fd = -1;
- LOG_FATAL(LOGF_PrivOps, "Could not send to helper : %s", strerror(errno));
+ LOG_FATAL("Could not send to helper : %s", strerror(errno));
}
- DEBUG_LOG(LOGF_PrivOps, "Sent request op=%d", req->op);
+ DEBUG_LOG("Sent request op=%d", req->op);
}
/* ======================================================================= */
@@ -598,7 +615,7 @@ PRV_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
req.op = OP_NAME2IPADDRESS;
if (snprintf(req.data.name_to_ipaddress.name, sizeof (req.data.name_to_ipaddress.name),
"%s", name) >= sizeof (req.data.name_to_ipaddress.name)) {
- DEBUG_LOG(LOGF_PrivOps, "Name too long");
+ DEBUG_LOG("Name too long");
return DNS_Failure;
}
@@ -613,6 +630,30 @@ PRV_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
/* ======================================================================= */
+/* DAEMON - request res_init() */
+
+#ifdef PRIVOPS_RELOADDNS
+void
+PRV_ReloadDNS(void)
+{
+ PrvRequest req;
+ PrvResponse res;
+
+ if (!have_helper()) {
+ DNS_Reload();
+ return;
+ }
+
+ memset(&req, 0, sizeof (req));
+ req.op = OP_RELOADDNS;
+
+ submit_request(&req, &res);
+ assert(!res.rc);
+}
+#endif
+
+/* ======================================================================= */
+
void
PRV_Initialise(void)
{
@@ -631,21 +672,21 @@ PRV_StartHelper(void)
int fd, sock_pair[2];
if (have_helper())
- LOG_FATAL(LOGF_PrivOps, "Helper already running");
+ LOG_FATAL("Helper already running");
if (
#ifdef SOCK_SEQPACKET
socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sock_pair) &&
#endif
socketpair(AF_UNIX, SOCK_DGRAM, 0, sock_pair))
- LOG_FATAL(LOGF_PrivOps, "socketpair() failed : %s", strerror(errno));
+ LOG_FATAL("socketpair() failed : %s", strerror(errno));
UTI_FdSetCloexec(sock_pair[0]);
UTI_FdSetCloexec(sock_pair[1]);
pid = fork();
if (pid < 0)
- LOG_FATAL(LOGF_PrivOps, "fork() failed : %s", strerror(errno));
+ LOG_FATAL("fork() failed : %s", strerror(errno));
if (pid == 0) {
/* child process */
diff --git a/privops.h b/privops.h
index 77cdde7..146580b 100644
--- a/privops.h
+++ b/privops.h
@@ -58,6 +58,12 @@ int PRV_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs);
#define PRV_Name2IPAddress DNS_Name2IPAddress
#endif
+#ifdef PRIVOPS_RELOADDNS
+void PRV_ReloadDNS(void);
+#else
+#define PRV_ReloadDNS DNS_Reload
+#endif
+
#ifdef PRIVOPS_HELPER
void PRV_Initialise(void);
void PRV_StartHelper(void);
diff --git a/refclock.c b/refclock.c
index 43b561a..6ca9118 100644
--- a/refclock.c
+++ b/refclock.c
@@ -2,7 +2,7 @@
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
* it under the terms of version 2 of the GNU General Public License as
@@ -75,6 +75,7 @@ struct RCL_Instance_Record {
int driver_polled;
int poll;
int leap_status;
+ int pps_forced;
int pps_rate;
int pps_active;
int max_lock_age;
@@ -84,6 +85,7 @@ struct RCL_Instance_Record {
double offset;
double delay;
double precision;
+ double pulse_width;
SCH_TimeoutID timeout_id;
SRC_Instance source;
};
@@ -93,7 +95,7 @@ static ARR_Instance refclocks;
static LOG_FileID logfileid;
-static int valid_sample_time(RCL_Instance instance, struct timespec *raw, struct timespec *cooked);
+static int valid_sample_time(RCL_Instance instance, struct timespec *sample_time);
static int pps_stratum(RCL_Instance instance, struct timespec *ts);
static void poll_timeout(void *arg);
static void slew_samples(struct timespec *raw, struct timespec *cooked, double dfreq,
@@ -164,7 +166,6 @@ RCL_Finalise(void)
int
RCL_AddRefclock(RefclockParameters *params)
{
- int pps_source = 0;
RCL_Instance inst;
inst = MallocNew(struct RCL_Instance_Record);
@@ -172,25 +173,19 @@ RCL_AddRefclock(RefclockParameters *params)
if (strcmp(params->driver_name, "SHM") == 0) {
inst->driver = &RCL_SHM_driver;
- inst->precision = 1e-6;
} else if (strcmp(params->driver_name, "SOCK") == 0) {
inst->driver = &RCL_SOCK_driver;
- inst->precision = 1e-9;
- pps_source = 1;
} else if (strcmp(params->driver_name, "PPS") == 0) {
inst->driver = &RCL_PPS_driver;
- inst->precision = 1e-9;
- pps_source = 1;
} else if (strcmp(params->driver_name, "PHC") == 0) {
inst->driver = &RCL_PHC_driver;
- inst->precision = 1e-9;
} else {
- LOG_FATAL(LOGF_Refclock, "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) {
- LOG_FATAL(LOGF_Refclock, "refclock driver %s is not compiled in", params->driver_name);
+ LOG_FATAL("refclock driver %s is not compiled in", params->driver_name);
return 0;
}
@@ -201,14 +196,16 @@ RCL_AddRefclock(RefclockParameters *params)
inst->poll = params->poll;
inst->driver_polled = 0;
inst->leap_status = LEAP_Normal;
+ inst->pps_forced = params->pps_forced;
inst->pps_rate = params->pps_rate;
inst->pps_active = 0;
inst->max_lock_age = params->max_lock_age;
inst->lock_ref = params->lock_ref_id;
inst->offset = params->offset;
inst->delay = params->delay;
- if (params->precision > 0.0)
- inst->precision = params->precision;
+ inst->precision = LCL_GetSysPrecisionAsQuantum();
+ inst->precision = MAX(inst->precision, params->precision);
+ inst->pulse_width = params->pulse_width;
inst->timeout_id = -1;
inst->source = NULL;
@@ -221,12 +218,8 @@ RCL_AddRefclock(RefclockParameters *params)
inst->driver_parameter[i] = '\0';
}
- if (pps_source) {
- if (inst->pps_rate < 1)
- inst->pps_rate = 1;
- } else {
- inst->pps_rate = 0;
- }
+ if (inst->pps_rate < 1)
+ inst->pps_rate = 1;
if (params->ref_id)
inst->ref_id = params->ref_id;
@@ -251,7 +244,7 @@ RCL_AddRefclock(RefclockParameters *params)
max_samples = 1 << (inst->poll - inst->driver_poll);
if (max_samples < params->filter_length) {
if (max_samples < 4) {
- LOG(LOGS_WARN, LOGF_Refclock, "Setting filter length for %s to %d",
+ LOG(LOGS_WARN, "Setting filter length for %s to %d",
UTI_RefidToString(inst->ref_id), max_samples);
}
params->filter_length = max_samples;
@@ -260,16 +253,16 @@ RCL_AddRefclock(RefclockParameters *params)
if (inst->driver->init)
if (!inst->driver->init(inst)) {
- LOG_FATAL(LOGF_Refclock, "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);
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(LOGF_Refclock, "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),
inst->poll, inst->driver_poll, params->filter_length);
@@ -369,13 +362,16 @@ RCL_AddSample(RCL_Instance instance, struct timespec *sample_time, double offset
double correction, dispersion;
struct timespec cooked_time;
+ if (instance->pps_forced)
+ return RCL_AddPulse(instance, sample_time, -offset);
+
LCL_GetOffsetCorrection(sample_time, &correction, &dispersion);
UTI_AddDoubleToTimespec(sample_time, correction, &cooked_time);
dispersion += instance->precision;
/* Make sure the timestamp and offset provided by the driver are sane */
if (!UTI_IsTimeOffsetSane(sample_time, offset) ||
- !valid_sample_time(instance, sample_time, &cooked_time))
+ !valid_sample_time(instance, &cooked_time))
return 0;
switch (leap) {
@@ -385,7 +381,7 @@ RCL_AddSample(RCL_Instance instance, struct timespec *sample_time, double offset
instance->leap_status = leap;
break;
default:
- DEBUG_LOG(LOGF_Refclock, "refclock sample ignored bad leap %d", leap);
+ DEBUG_LOG("refclock sample ignored bad leap %d", leap);
return 0;
}
@@ -404,24 +400,57 @@ RCL_AddSample(RCL_Instance instance, struct timespec *sample_time, double offset
int
RCL_AddPulse(RCL_Instance instance, struct timespec *pulse_time, double second)
{
- double correction, dispersion, offset;
+ double correction, dispersion;
struct timespec cooked_time;
- int rate;
- NTP_Leap leap;
- leap = LEAP_Normal;
LCL_GetOffsetCorrection(pulse_time, &correction, &dispersion);
UTI_AddDoubleToTimespec(pulse_time, correction, &cooked_time);
- dispersion += instance->precision;
+ second += correction;
+
+ if (!UTI_IsTimeOffsetSane(pulse_time, 0.0))
+ return 0;
+
+ return RCL_AddCookedPulse(instance, &cooked_time, second, dispersion, correction);
+}
+
+static int
+check_pulse_edge(RCL_Instance instance, double offset, double distance)
+{
+ double max_error;
+
+ if (instance->pulse_width <= 0.0)
+ return 1;
+
+ max_error = 1.0 / instance->pps_rate - instance->pulse_width;
+ max_error = MIN(instance->pulse_width, max_error);
+ max_error *= 0.5;
+
+ if (fabs(offset) > max_error || distance > max_error) {
+ DEBUG_LOG("refclock pulse ignored offset=%.9f distance=%.9f max_error=%.9f",
+ offset, distance, max_error);
+ return 0;
+ }
+
+ return 1;
+}
+
+int
+RCL_AddCookedPulse(RCL_Instance instance, struct timespec *cooked_time,
+ double second, double dispersion, double raw_correction)
+{
+ double offset;
+ int rate;
+ NTP_Leap leap;
- if (!UTI_IsTimeOffsetSane(pulse_time, 0.0) ||
- !valid_sample_time(instance, pulse_time, &cooked_time))
+ if (!UTI_IsTimeOffsetSane(cooked_time, second) ||
+ !valid_sample_time(instance, cooked_time))
return 0;
+ leap = LEAP_Normal;
+ dispersion += instance->precision;
rate = instance->pps_rate;
- assert(rate > 0);
- offset = -second - correction + instance->offset;
+ offset = -second + instance->offset;
/* Adjust the offset to [-0.5/rate, 0.5/rate) interval */
offset -= (long)(offset * rate) / (double)rate;
@@ -439,15 +468,15 @@ RCL_AddPulse(RCL_Instance instance, struct timespec *pulse_time, double second)
if (!filter_get_last_sample(&lock_refclock->filter,
&ref_sample_time, &ref_offset, &ref_dispersion)) {
- DEBUG_LOG(LOGF_Refclock, "refclock pulse ignored no ref sample");
+ DEBUG_LOG("refclock pulse ignored no ref sample");
return 0;
}
ref_dispersion += filter_get_avg_sample_dispersion(&lock_refclock->filter);
- sample_diff = UTI_DiffTimespecsToDouble(&cooked_time, &ref_sample_time);
+ sample_diff = UTI_DiffTimespecsToDouble(cooked_time, &ref_sample_time);
if (fabs(sample_diff) >= (double)instance->max_lock_age / rate) {
- DEBUG_LOG(LOGF_Refclock, "refclock pulse ignored samplediff=%.9f",
+ DEBUG_LOG("refclock pulse ignored samplediff=%.9f",
sample_diff);
return 0;
}
@@ -461,15 +490,18 @@ RCL_AddPulse(RCL_Instance instance, struct timespec *pulse_time, double second)
offset += shift;
if (fabs(ref_offset - offset) + ref_dispersion + dispersion >= 0.2 / rate) {
- DEBUG_LOG(LOGF_Refclock, "refclock pulse ignored offdiff=%.9f refdisp=%.9f disp=%.9f",
+ DEBUG_LOG("refclock pulse ignored offdiff=%.9f refdisp=%.9f disp=%.9f",
ref_offset - offset, ref_dispersion, dispersion);
return 0;
}
+ if (!check_pulse_edge(instance, ref_offset - offset, 0.0))
+ return 0;
+
leap = lock_refclock->leap_status;
- DEBUG_LOG(LOGF_Refclock, "refclock pulse second=%.9f offset=%.9f offdiff=%.9f samplediff=%.9f",
- second, offset, ref_offset - offset, sample_diff);
+ DEBUG_LOG("refclock pulse offset=%.9f offdiff=%.9f samplediff=%.9f",
+ offset, ref_offset - offset, sample_diff);
} else {
struct timespec ref_time;
int is_synchronised, stratum;
@@ -479,24 +511,28 @@ RCL_AddPulse(RCL_Instance instance, struct timespec *pulse_time, double second)
/* Ignore the pulse if we are not well synchronized and the local
reference is not active */
- REF_GetReferenceParams(&cooked_time, &is_synchronised, &leap, &stratum,
+ REF_GetReferenceParams(cooked_time, &is_synchronised, &leap, &stratum,
&ref_id, &ref_time, &root_delay, &root_dispersion);
distance = fabs(root_delay) / 2 + root_dispersion;
if (leap == LEAP_Unsynchronised || distance >= 0.5 / rate) {
- DEBUG_LOG(LOGF_Refclock, "refclock pulse ignored second=%.9f sync=%d dist=%.9f",
- second, leap != LEAP_Unsynchronised, distance);
+ DEBUG_LOG("refclock pulse ignored offset=%.9f sync=%d dist=%.9f",
+ offset, leap != LEAP_Unsynchronised, distance);
/* Drop also all stored samples */
filter_reset(&instance->filter);
return 0;
}
+
+ if (!check_pulse_edge(instance, offset, distance))
+ return 0;
}
- filter_add_sample(&instance->filter, &cooked_time, offset, dispersion);
+ filter_add_sample(&instance->filter, cooked_time, offset, dispersion);
instance->leap_status = leap;
instance->pps_active = 1;
- log_sample(instance, &cooked_time, 0, 1, offset + correction - instance->offset, offset, dispersion);
+ log_sample(instance, cooked_time, 0, 1, offset + raw_correction - instance->offset,
+ offset, dispersion);
/* for logging purposes */
if (!instance->driver->poll)
@@ -511,23 +547,29 @@ RCL_GetPrecision(RCL_Instance instance)
return instance->precision;
}
+int
+RCL_GetDriverPoll(RCL_Instance instance)
+{
+ return instance->driver_poll;
+}
+
static int
-valid_sample_time(RCL_Instance instance, struct timespec *raw, struct timespec *cooked)
+valid_sample_time(RCL_Instance instance, struct timespec *sample_time)
{
- struct timespec now_raw, last_sample_time;
+ struct timespec now, last_sample_time;
double diff, last_offset, last_dispersion;
- LCL_ReadRawTime(&now_raw);
- diff = UTI_DiffTimespecsToDouble(&now_raw, raw);
+ LCL_ReadCookedTime(&now, NULL);
+ diff = UTI_DiffTimespecsToDouble(&now, sample_time);
if (diff < 0.0 || diff > UTI_Log2ToDouble(instance->poll + 1) ||
(filter_get_samples(&instance->filter) > 0 &&
filter_get_last_sample(&instance->filter, &last_sample_time,
&last_offset, &last_dispersion) &&
- UTI_CompareTimespecs(&last_sample_time, cooked) >= 0)) {
- DEBUG_LOG(LOGF_Refclock, "%s refclock sample not valid age=%.6f raw=%s cooked=%s",
- UTI_RefidToString(instance->ref_id), diff,
- UTI_TimespecToString(raw), UTI_TimespecToString(cooked));
+ UTI_CompareTimespecs(&last_sample_time, sample_time) >= 0)) {
+ DEBUG_LOG("%s refclock sample time %s not valid age=%.6f",
+ UTI_RefidToString(instance->ref_id),
+ UTI_TimespecToString(sample_time), diff);
return 0;
}
@@ -719,7 +761,7 @@ filter_add_sample(struct MedianFilter *filter, struct timespec *sample_time, dou
filter->samples[filter->index].offset = offset;
filter->samples[filter->index].dispersion = dispersion;
- DEBUG_LOG(LOGF_Refclock, "filter sample %d t=%s offset=%.9f dispersion=%.9f",
+ DEBUG_LOG("filter sample %d t=%s offset=%.9f dispersion=%.9f",
filter->index, UTI_TimespecToString(sample_time), offset, dispersion);
}
@@ -909,7 +951,7 @@ filter_get_sample(struct MedianFilter *filter, struct timespec *sample_time, dou
/* drop the sample if variance is larger than allowed maximum */
if (filter->max_var > 0.0 && var > filter->max_var) {
- DEBUG_LOG(LOGF_Refclock, "filter dispersion too large disp=%.9f max=%.9f",
+ DEBUG_LOG("filter dispersion too large disp=%.9f max=%.9f",
sqrt(var), sqrt(filter->max_var));
return 0;
}
diff --git a/refclock.h b/refclock.h
index f5b7b3d..40ce12d 100644
--- a/refclock.h
+++ b/refclock.h
@@ -37,6 +37,7 @@ typedef struct {
int driver_poll;
int poll;
int filter_length;
+ int pps_forced;
int pps_rate;
int min_samples;
int max_samples;
@@ -48,6 +49,7 @@ typedef struct {
double delay;
double precision;
double max_dispersion;
+ double pulse_width;
} RefclockParameters;
typedef struct RCL_Instance_Record *RCL_Instance;
@@ -71,6 +73,9 @@ extern char *RCL_GetDriverParameter(RCL_Instance instance);
extern char *RCL_GetDriverOption(RCL_Instance instance, char *name);
extern int RCL_AddSample(RCL_Instance instance, struct timespec *sample_time, double offset, int leap);
extern int RCL_AddPulse(RCL_Instance instance, struct timespec *pulse_time, double second);
+extern int RCL_AddCookedPulse(RCL_Instance instance, struct timespec *cooked_time,
+ double second, double dispersion, double raw_correction);
extern double RCL_GetPrecision(RCL_Instance instance);
+extern int RCL_GetDriverPoll(RCL_Instance instance);
#endif
diff --git a/refclock_phc.c b/refclock_phc.c
index ebbbe00..6aa5edd 100644
--- a/refclock_phc.c
+++ b/refclock_phc.c
@@ -34,28 +34,37 @@
#include "sysincl.h"
#include "refclock.h"
+#include "hwclock.h"
+#include "local.h"
#include "logging.h"
#include "memory.h"
#include "util.h"
+#include "sched.h"
#include "sys_linux.h"
struct phc_instance {
int fd;
int mode;
int nocrossts;
+ int extpps;
+ int pin;
+ int channel;
+ HCL_Instance clock;
};
+static void read_ext_pulse(int sockfd, int event, void *anything);
+
static int phc_initialise(RCL_Instance instance)
{
struct phc_instance *phc;
- int phc_fd;
- char *path;
+ int phc_fd, rising_edge;
+ char *path, *s;
path = RCL_GetDriverParameter(instance);
phc_fd = SYS_Linux_OpenPHC(path, 0);
if (phc_fd < 0) {
- LOG_FATAL(LOGF_Refclock, "Could not open PHC");
+ LOG_FATAL("Could not open PHC");
return 0;
}
@@ -63,6 +72,25 @@ static int phc_initialise(RCL_Instance instance)
phc->fd = phc_fd;
phc->mode = 0;
phc->nocrossts = RCL_GetDriverOption(instance, "nocrossts") ? 1 : 0;
+ phc->extpps = RCL_GetDriverOption(instance, "extpps") ? 1 : 0;
+
+ if (phc->extpps) {
+ s = RCL_GetDriverOption(instance, "pin");
+ phc->pin = s ? atoi(s) : 0;
+ s = RCL_GetDriverOption(instance, "channel");
+ phc->channel = s ? atoi(s) : 0;
+ rising_edge = RCL_GetDriverOption(instance, "clear") ? 0 : 1;
+ phc->clock = HCL_CreateInstance(UTI_Log2ToDouble(RCL_GetDriverPoll(instance)));
+
+ if (!SYS_Linux_SetPHCExtTimestamping(phc->fd, phc->pin, phc->channel,
+ rising_edge, !rising_edge, 1))
+ LOG_FATAL("Could not enable external PHC timestamping");
+
+ SCH_AddFileHandler(phc->fd, SCH_FILE_INPUT, read_ext_pulse, instance);
+ } else {
+ phc->pin = phc->channel = 0;
+ phc->clock = NULL;
+ }
RCL_SetDriverData(instance, phc);
return 1;
@@ -73,25 +101,64 @@ static void phc_finalise(RCL_Instance instance)
struct phc_instance *phc;
phc = (struct phc_instance *)RCL_GetDriverData(instance);
+
+ if (phc->extpps) {
+ SCH_RemoveFileHandler(phc->fd);
+ SYS_Linux_SetPHCExtTimestamping(phc->fd, phc->pin, phc->channel, 0, 0, 0);
+ HCL_DestroyInstance(phc->clock);
+ }
+
close(phc->fd);
Free(phc);
}
+static void read_ext_pulse(int fd, int event, void *anything)
+{
+ RCL_Instance instance;
+ struct phc_instance *phc;
+ struct timespec phc_ts, local_ts;
+ double local_err;
+ int channel;
+
+ instance = anything;
+ phc = RCL_GetDriverData(instance);
+
+ if (!SYS_Linux_ReadPHCExtTimestamp(phc->fd, &phc_ts, &channel))
+ return;
+
+ if (channel != phc->channel) {
+ DEBUG_LOG("Unexpected extts channel %d\n", channel);
+ return;
+ }
+
+ if (!HCL_CookTime(phc->clock, &phc_ts, &local_ts, &local_err))
+ return;
+
+ RCL_AddCookedPulse(instance, &local_ts, 1.0e-9 * local_ts.tv_nsec, local_err,
+ UTI_DiffTimespecsToDouble(&phc_ts, &local_ts));
+}
+
static int phc_poll(RCL_Instance instance)
{
struct phc_instance *phc;
- struct timespec phc_ts, sys_ts;
- double offset, err;
+ struct timespec phc_ts, sys_ts, local_ts;
+ double offset, phc_err, local_err;
phc = (struct phc_instance *)RCL_GetDriverData(instance);
if (!SYS_Linux_GetPHCSample(phc->fd, phc->nocrossts, RCL_GetPrecision(instance),
- &phc->mode, &phc_ts, &sys_ts, &err))
+ &phc->mode, &phc_ts, &sys_ts, &phc_err))
+ return 0;
+
+ if (phc->extpps) {
+ LCL_CookTime(&sys_ts, &local_ts, &local_err);
+ HCL_AccumulateSample(phc->clock, &phc_ts, &local_ts, phc_err + local_err);
return 0;
+ }
offset = UTI_DiffTimespecsToDouble(&phc_ts, &sys_ts);
- DEBUG_LOG(LOGF_Refclock, "PHC offset: %+.9f err: %.9f", offset, err);
+ DEBUG_LOG("PHC offset: %+.9f err: %.9f", offset, phc_err);
return RCL_AddSample(instance, &sys_ts, offset, LEAP_Normal);
}
diff --git a/refclock_pps.c b/refclock_pps.c
index 79016de..6f0565e 100644
--- a/refclock_pps.c
+++ b/refclock_pps.c
@@ -59,37 +59,37 @@ static int pps_initialise(RCL_Instance instance) {
fd = open(path, O_RDWR);
if (fd < 0) {
- LOG_FATAL(LOGF_Refclock, "open() failed on %s", path);
+ LOG_FATAL("open() failed on %s", path);
return 0;
}
UTI_FdSetCloexec(fd);
if (time_pps_create(fd, &handle) < 0) {
- LOG_FATAL(LOGF_Refclock, "time_pps_create() failed on %s", path);
+ LOG_FATAL("time_pps_create() failed on %s", path);
return 0;
}
if (time_pps_getcap(handle, &mode) < 0) {
- LOG_FATAL(LOGF_Refclock, "time_pps_getcap() failed on %s", path);
+ LOG_FATAL("time_pps_getcap() failed on %s", path);
return 0;
}
if (time_pps_getparams(handle, &params) < 0) {
- LOG_FATAL(LOGF_Refclock, "time_pps_getparams() failed on %s", path);
+ LOG_FATAL("time_pps_getparams() failed on %s", path);
return 0;
}
if (!edge_clear) {
if (!(mode & PPS_CAPTUREASSERT)) {
- LOG_FATAL(LOGF_Refclock, "CAPTUREASSERT not supported on %s", path);
+ LOG_FATAL("CAPTUREASSERT not supported on %s", path);
return 0;
}
params.mode |= PPS_CAPTUREASSERT;
params.mode &= ~PPS_CAPTURECLEAR;
} else {
if (!(mode & PPS_CAPTURECLEAR)) {
- LOG_FATAL(LOGF_Refclock, "CAPTURECLEAR not supported on %s", path);
+ LOG_FATAL("CAPTURECLEAR not supported on %s", path);
return 0;
}
params.mode |= PPS_CAPTURECLEAR;
@@ -97,7 +97,7 @@ static int pps_initialise(RCL_Instance instance) {
}
if (time_pps_setparams(handle, &params) < 0) {
- LOG_FATAL(LOGF_Refclock, "time_pps_setparams() failed on %s", path);
+ LOG_FATAL("time_pps_setparams() failed on %s", path);
return 0;
}
@@ -133,7 +133,7 @@ static int pps_poll(RCL_Instance instance)
ts.tv_nsec = 0;
if (time_pps_fetch(pps->handle, PPS_TSFMT_TSPEC, &pps_info, &ts) < 0) {
- LOG(LOGS_ERR, LOGF_Refclock, "time_pps_fetch() failed : %s", strerror(errno));
+ LOG(LOGS_ERR, "time_pps_fetch() failed : %s", strerror(errno));
return 0;
}
@@ -146,7 +146,7 @@ static int pps_poll(RCL_Instance instance)
}
if (seq == pps->last_seq || UTI_IsZeroTimespec(&ts)) {
- DEBUG_LOG(LOGF_Refclock, "PPS sample ignored seq=%lu ts=%s",
+ DEBUG_LOG("PPS sample ignored seq=%lu ts=%s",
seq, UTI_TimespecToString(&ts));
return 0;
}
diff --git a/refclock_shm.c b/refclock_shm.c
index 905121b..7cced1d 100644
--- a/refclock_shm.c
+++ b/refclock_shm.c
@@ -69,13 +69,13 @@ static int shm_initialise(RCL_Instance instance) {
id = shmget(SHMKEY + param, sizeof (struct shmTime), IPC_CREAT | perm);
if (id == -1) {
- LOG_FATAL(LOGF_Refclock, "shmget() failed");
+ LOG_FATAL("shmget() failed");
return 0;
}
shm = (struct shmTime *)shmat(id, 0, 0);
if ((long)shm == -1) {
- LOG_FATAL(LOGF_Refclock, "shmat() failed");
+ LOG_FATAL("shmat() failed");
return 0;
}
@@ -100,7 +100,7 @@ static int shm_poll(RCL_Instance instance)
if ((t.mode == 1 && t.count != shm->count) ||
!(t.mode == 0 || t.mode == 1) || !t.valid) {
- DEBUG_LOG(LOGF_Refclock, "SHM sample ignored mode=%d count=%d valid=%d",
+ DEBUG_LOG("SHM sample ignored mode=%d count=%d valid=%d",
t.mode, t.count, t.valid);
return 0;
}
diff --git a/refclock_sock.c b/refclock_sock.c
index 6e71368..eb96147 100644
--- a/refclock_sock.c
+++ b/refclock_sock.c
@@ -69,19 +69,19 @@ static void read_sample(int sockfd, int event, void *anything)
s = recv(sockfd, &sample, sizeof (sample), 0);
if (s < 0) {
- LOG(LOGS_ERR, LOGF_Refclock, "Could not read SOCK sample : %s",
+ LOG(LOGS_ERR, "Could not read SOCK sample : %s",
strerror(errno));
return;
}
if (s != sizeof (sample)) {
- LOG(LOGS_WARN, LOGF_Refclock, "Unexpected length of SOCK sample : %d != %ld",
+ LOG(LOGS_WARN, "Unexpected length of SOCK sample : %d != %ld",
s, (long)sizeof (sample));
return;
}
if (sample.magic != SOCK_MAGIC) {
- LOG(LOGS_WARN, LOGF_Refclock, "Unexpected magic number in SOCK sample : %x != %x",
+ LOG(LOGS_WARN, "Unexpected magic number in SOCK sample : %x != %x",
sample.magic, SOCK_MAGIC);
return;
}
@@ -106,13 +106,13 @@ static int sock_initialise(RCL_Instance instance)
s.sun_family = AF_UNIX;
if (snprintf(s.sun_path, sizeof (s.sun_path), "%s", path) >= sizeof (s.sun_path)) {
- LOG_FATAL(LOGF_Refclock, "path %s is too long", path);
+ LOG_FATAL("path %s is too long", path);
return 0;
}
sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (sockfd < 0) {
- LOG_FATAL(LOGF_Refclock, "socket() failed");
+ LOG_FATAL("socket() failed");
return 0;
}
@@ -120,7 +120,7 @@ static int sock_initialise(RCL_Instance instance)
unlink(path);
if (bind(sockfd, (struct sockaddr *)&s, sizeof (s)) < 0) {
- LOG_FATAL(LOGF_Refclock, "bind() failed");
+ LOG_FATAL("bind() failed");
return 0;
}
diff --git a/reference.c b/reference.c
index b9a25f5..8138b8c 100644
--- a/reference.c
+++ b/reference.c
@@ -3,7 +3,7 @@
**********************************************************************
* 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
* it under the terms of version 2 of the GNU General Public License as
@@ -49,6 +49,7 @@ static int local_orphan;
static double local_distance;
static NTP_Leap our_leap_status;
static int our_leap_sec;
+static int our_tai_offset;
static int our_stratum;
static uint32_t our_ref_id;
static IPAddr our_ref_ip;
@@ -111,8 +112,6 @@ static SCH_TimeoutID leap_timeout_id;
/* Name of a system timezone containing leap seconds occuring at midnight */
static char *leap_tzname;
-static time_t last_tz_leap_check;
-static NTP_Leap tz_leap;
/* ================================================== */
@@ -141,7 +140,7 @@ static double last_ref_update_interval;
/* ================================================== */
-static NTP_Leap get_tz_leap(time_t when);
+static NTP_Leap get_tz_leap(time_t when, int *tai_offset);
static void update_leap_status(NTP_Leap leap, time_t now, int reset);
/* ================================================== */
@@ -157,7 +156,8 @@ handle_slew(struct timespec *raw,
double delta;
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) {
UTI_ZeroTimespec(&last_ref_update);
@@ -181,11 +181,13 @@ REF_Initialise(void)
FILE *in;
double file_freq_ppm, file_skew_ppm;
double our_frequency_ppm;
+ int tai_offset;
mode = REF_ModeNormal;
are_we_synchronised = 0;
our_leap_status = LEAP_Unsynchronised;
our_leap_sec = 0;
+ our_tai_offset = 0;
initialised = 1;
our_root_dispersion = 1.0;
our_root_delay = 1.0;
@@ -205,11 +207,11 @@ REF_Initialise(void)
our_skew = 1.0e-6 * file_skew_ppm;
if (our_skew < MIN_SKEW)
our_skew = MIN_SKEW;
- LOG(LOGS_INFO, LOGF_Reference, "Frequency %.3f +/- %.3f ppm read from %s",
+ LOG(LOGS_INFO, "Frequency %.3f +/- %.3f ppm read from %s",
file_freq_ppm, file_skew_ppm, drift_file);
LCL_SetAbsoluteFrequency(our_frequency_ppm);
} else {
- LOG(LOGS_WARN, LOGF_Reference, "Could not read valid frequency and skew from driftfile %s",
+ LOG(LOGS_WARN, "Could not read valid frequency and skew from driftfile %s",
drift_file);
}
fclose(in);
@@ -219,12 +221,12 @@ REF_Initialise(void)
if (our_frequency_ppm == 0.0) {
our_frequency_ppm = LCL_ReadAbsoluteFrequency();
if (our_frequency_ppm != 0.0) {
- LOG(LOGS_INFO, LOGF_Reference, "Initial frequency %.3f ppm", our_frequency_ppm);
+ LOG(LOGS_INFO, "Initial frequency %.3f ppm", our_frequency_ppm);
}
}
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;
max_update_skew = fabs(CNF_GetMaxUpdateSkew()) * 1.0e-6;
@@ -243,11 +245,11 @@ REF_Initialise(void)
leap_tzname = CNF_GetLeapSecTimezone();
if (leap_tzname) {
/* Check that the timezone has good data for Jun 30 2012 and Dec 31 2012 */
- if (get_tz_leap(1341014400) == LEAP_InsertSecond &&
- get_tz_leap(1356912000) == LEAP_Normal) {
- LOG(LOGS_INFO, LOGF_Reference, "Using %s timezone to obtain leap second data", leap_tzname);
+ if (get_tz_leap(1341014400, &tai_offset) == LEAP_InsertSecond && tai_offset == 34 &&
+ get_tz_leap(1356912000, &tai_offset) == LEAP_Normal && tai_offset == 35) {
+ LOG(LOGS_INFO, "Using %s timezone to obtain leap second data", leap_tzname);
} else {
- LOG(LOGS_WARN, LOGF_Reference, "Timezone %s failed leap second check, ignoring", leap_tzname);
+ LOG(LOGS_WARN, "Timezone %s failed leap second check, ignoring", leap_tzname);
leap_tzname = NULL;
}
}
@@ -266,6 +268,7 @@ REF_Initialise(void)
fb_drift_timeout_id = 0;
}
+ UTI_ZeroTimespec(&our_ref_time);
UTI_ZeroTimespec(&last_ref_update);
last_ref_update_interval = 0.0;
@@ -364,7 +367,7 @@ update_drift_file(double freq_ppm, double skew)
out = fopen(temp_drift_file, "w");
if (!out) {
Free(temp_drift_file);
- LOG(LOGS_WARN, LOGF_Reference, "Could not open temporary driftfile %s.tmp for writing",
+ LOG(LOGS_WARN, "Could not open temporary driftfile %s.tmp for writing",
drift_file);
return;
}
@@ -374,7 +377,7 @@ update_drift_file(double freq_ppm, double skew)
r2 = fclose(out);
if (r1 < 0 || r2) {
Free(temp_drift_file);
- LOG(LOGS_WARN, LOGF_Reference, "Could not write to temporary driftfile %s.tmp",
+ LOG(LOGS_WARN, "Could not write to temporary driftfile %s.tmp",
drift_file);
return;
}
@@ -384,8 +387,7 @@ update_drift_file(double freq_ppm, double skew)
if (!stat(drift_file,&buf)) {
if (chown(temp_drift_file,buf.st_uid,buf.st_gid) ||
chmod(temp_drift_file,buf.st_mode & 0777)) {
- LOG(LOGS_WARN, LOGF_Reference,
- "Could not change ownership or permissions of temporary driftfile %s.tmp",
+ LOG(LOGS_WARN, "Could not change ownership or permissions of temporary driftfile %s.tmp",
drift_file);
}
}
@@ -395,7 +397,7 @@ update_drift_file(double freq_ppm, double skew)
if (rename(temp_drift_file,drift_file)) {
unlink(temp_drift_file);
Free(temp_drift_file);
- LOG(LOGS_WARN, LOGF_Reference, "Could not replace old driftfile %s with new one %s.tmp",
+ LOG(LOGS_WARN, "Could not replace old driftfile %s with new one %s.tmp",
drift_file,drift_file);
return;
}
@@ -443,8 +445,8 @@ update_fb_drifts(double freq_ppm, double update_interval)
(freq_ppm - fb_drifts[i].freq);
}
- DEBUG_LOG(LOGF_Reference, "Fallback drift %d updated: %f ppm %f seconds",
- i + fb_drift_min, fb_drifts[i].freq, fb_drifts[i].secs);
+ DEBUG_LOG("Fallback drift %d updated: %f ppm %f seconds",
+ i + fb_drift_min, fb_drifts[i].freq, fb_drifts[i].secs);
}
}
@@ -457,7 +459,7 @@ fb_drift_timeout(void *arg)
fb_drift_timeout_id = 0;
- DEBUG_LOG(LOGF_Reference, "Fallback drift %d active: %f ppm",
+ DEBUG_LOG("Fallback drift %d active: %f ppm",
next_fb_drift, fb_drifts[next_fb_drift - fb_drift_min].freq);
LCL_SetAbsoluteFrequency(fb_drifts[next_fb_drift - fb_drift_min].freq);
REF_SetUnsynchronised();
@@ -492,14 +494,14 @@ schedule_fb_drift(struct timespec *now)
if (c > next_fb_drift) {
LCL_SetAbsoluteFrequency(fb_drifts[c - fb_drift_min].freq);
next_fb_drift = c;
- DEBUG_LOG(LOGF_Reference, "Fallback drift %d set", c);
+ DEBUG_LOG("Fallback drift %d set", c);
}
if (i <= fb_drift_max) {
next_fb_drift = i;
UTI_AddDoubleToTimespec(now, secs - unsynchronised, &when);
fb_drift_timeout_id = SCH_AddTimeout(&when, fb_drift_timeout, NULL);
- DEBUG_LOG(LOGF_Reference, "Fallback drift %d scheduled", i);
+ DEBUG_LOG("Fallback drift %d scheduled", i);
}
}
@@ -531,8 +533,7 @@ maybe_log_offset(double offset, time_t now)
abs_offset = fabs(offset);
if (abs_offset > log_change_threshold) {
- LOG(LOGS_WARN, LOGF_Reference,
- "System clock wrong by %.6f seconds, adjustment started",
+ LOG(LOGS_WARN, "System clock wrong by %.6f seconds, adjustment started",
-offset);
}
@@ -558,8 +559,7 @@ maybe_log_offset(double offset, time_t now)
-offset, mail_change_threshold);
pclose(p);
} else {
- LOG(LOGS_ERR, LOGF_Reference,
- "Could not send mail notification to user %s\n",
+ LOG(LOGS_ERR, "Could not send mail notification to user %s\n",
mail_change_user);
}
}
@@ -594,7 +594,7 @@ is_offset_ok(double offset)
offset = fabs(offset);
if (offset > max_offset) {
- LOG(LOGS_WARN, LOGF_Reference,
+ LOG(LOGS_WARN,
"Adjustment of %.3f seconds exceeds the allowed maximum of %.3f seconds (%s) ",
-offset, max_offset, !max_offset_ignore ? "exiting" : "ignored");
if (!max_offset_ignore)
@@ -609,7 +609,14 @@ is_offset_ok(double offset)
/* ================================================== */
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 */
return (stm->tm_mon == 5 && stm->tm_mday == 30) ||
(stm->tm_mon == 11 && stm->tm_mday == 31);
@@ -618,12 +625,18 @@ is_leap_second_day(struct tm *stm) {
/* ================================================== */
static NTP_Leap
-get_tz_leap(time_t when)
+get_tz_leap(time_t when, int *tai_offset)
{
- struct tm stm;
+ static time_t last_tz_leap_check;
+ static NTP_Leap tz_leap;
+ static int tz_tai_offset;
+
+ struct tm stm, *tm;
time_t t;
char *tz_env, tz_orig[128];
+ *tai_offset = tz_tai_offset;
+
/* Do this check at most twice a day */
when = when / (12 * 3600) * (12 * 3600);
if (last_tz_leap_check == when)
@@ -631,12 +644,14 @@ get_tz_leap(time_t when)
last_tz_leap_check = when;
tz_leap = LEAP_Normal;
+ tz_tai_offset = 0;
- stm = *gmtime(&when);
-
- if (!is_leap_second_day(&stm))
+ tm = gmtime(&when);
+ if (!tm)
return tz_leap;
+ stm = *tm;
+
/* Temporarily switch to the timezone containing leap seconds */
tz_env = getenv("TZ");
if (tz_env) {
@@ -647,6 +662,11 @@ get_tz_leap(time_t when)
setenv("TZ", leap_tzname, 1);
tzset();
+ /* Get the TAI-UTC offset, which started at the epoch at 10 seconds */
+ t = mktime(&stm);
+ if (t != -1)
+ tz_tai_offset = t - when + 10;
+
/* Set the time to 23:59:60 and see how it overflows in mktime() */
stm.tm_sec = 60;
stm.tm_min = 59;
@@ -668,6 +688,8 @@ get_tz_leap(time_t when)
else if (stm.tm_sec == 1)
tz_leap = LEAP_DeleteSecond;
+ *tai_offset = tz_tai_offset;
+
return tz_leap;
}
@@ -678,10 +700,13 @@ leap_end_timeout(void *arg)
{
leap_timeout_id = 0;
leap_in_progress = 0;
+
+ if (our_tai_offset)
+ our_tai_offset += our_leap_sec;
our_leap_sec = 0;
if (leap_mode == REF_LeapModeSystem)
- LCL_SetSystemLeap(0);
+ LCL_SetSystemLeap(our_leap_sec, our_tai_offset);
if (our_leap_status == LEAP_InsertSecond ||
our_leap_status == LEAP_DeleteSecond)
@@ -697,20 +722,20 @@ leap_start_timeout(void *arg)
switch (leap_mode) {
case REF_LeapModeSystem:
- DEBUG_LOG(LOGF_Reference, "Waiting for system clock leap second correction");
+ DEBUG_LOG("Waiting for system clock leap second correction");
break;
case REF_LeapModeSlew:
LCL_NotifyLeap(our_leap_sec);
LCL_AccumulateOffset(our_leap_sec, 0.0);
- LOG(LOGS_WARN, LOGF_Reference, "Adjusting system clock for leap second");
+ LOG(LOGS_WARN, "Adjusting system clock for leap second");
break;
case REF_LeapModeStep:
LCL_NotifyLeap(our_leap_sec);
LCL_ApplyStepOffset(our_leap_sec);
- LOG(LOGS_WARN, LOGF_Reference, "System clock was stepped for leap second");
+ LOG(LOGS_WARN, "System clock was stepped for leap second");
break;
case REF_LeapModeIgnore:
- LOG(LOGS_WARN, LOGF_Reference, "Ignoring leap second");
+ LOG(LOGS_WARN, "Ignoring leap second");
break;
default:
break;
@@ -755,17 +780,22 @@ set_leap_timeout(time_t now)
static void
update_leap_status(NTP_Leap leap, time_t now, int reset)
{
- int leap_sec;
+ NTP_Leap tz_leap;
+ int leap_sec, tai_offset;
leap_sec = 0;
+ tai_offset = 0;
- if (leap_tzname && now && leap == LEAP_Normal)
- leap = get_tz_leap(now);
+ if (leap_tzname && now) {
+ tz_leap = get_tz_leap(now, &tai_offset);
+ if (leap == LEAP_Normal)
+ leap = tz_leap;
+ }
if (leap == LEAP_InsertSecond || leap == LEAP_DeleteSecond) {
/* Check that leap second is allowed today */
- if (is_leap_second_day(gmtime(&now))) {
+ if (is_leap_second_day(now)) {
if (leap == LEAP_InsertSecond) {
leap_sec = 1;
} else {
@@ -776,12 +806,14 @@ update_leap_status(NTP_Leap leap, time_t now, int reset)
}
}
- if (leap_sec != our_leap_sec && !REF_IsLeapSecondClose()) {
+ if ((leap_sec != our_leap_sec || tai_offset != our_tai_offset)
+ && !REF_IsLeapSecondClose()) {
our_leap_sec = leap_sec;
+ our_tai_offset = tai_offset;
switch (leap_mode) {
case REF_LeapModeSystem:
- LCL_SetSystemLeap(our_leap_sec);
+ LCL_SetSystemLeap(our_leap_sec, our_tai_offset);
/* Fall through */
case REF_LeapModeSlew:
case REF_LeapModeStep:
@@ -801,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
-write_log(struct timespec *ref_time, char *ref, int stratum, NTP_Leap leap,
- double freq, double skew, double offset, int combined_sources,
- double offset_sd, double uncorrected_offset)
+write_log(struct timespec *now, int combined_sources, double freq,
+ double offset, double offset_sd, double uncorrected_offset,
+ double orig_root_distance)
{
const char leap_codes[4] = {'N', '+', '-', '?'};
- if (logfileid != -1) {
- LOG_FileWrite(logfileid, "%s %-15s %2d %10.3f %10.3f %10.3e %1c %2d %10.3e %10.3e",
- UTI_TimeToLogForm(ref_time->tv_sec), ref, stratum, freq, skew,
- offset, leap_codes[leap], combined_sources, offset_sd,
- uncorrected_offset);
- }
+ double root_dispersion, max_error;
+ static double last_sys_offset = 0.0;
+
+ if (logfileid == -1)
+ 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);
}
/* ================================================== */
@@ -825,15 +882,14 @@ special_mode_sync(int valid, double offset)
switch (mode) {
case REF_ModeInitStepSlew:
if (!valid) {
- LOG(LOGS_WARN, LOGF_Reference, "No suitable source for initstepslew");
+ LOG(LOGS_WARN, "No suitable source for initstepslew");
end_ref_mode(0);
break;
}
step = fabs(offset) >= CNF_GetInitStepThreshold();
- LOG(LOGS_INFO, LOGF_Reference,
- "System's initial offset : %.6f seconds %s of true (%s)",
+ LOG(LOGS_INFO, "System's initial offset : %.6f seconds %s of true (%s)",
fabs(offset), offset >= 0 ? "fast" : "slow", step ? "step" : "slew");
if (step)
@@ -847,14 +903,14 @@ special_mode_sync(int valid, double offset)
case REF_ModeUpdateOnce:
case REF_ModePrintOnce:
if (!valid) {
- LOG(LOGS_WARN, LOGF_Reference, "No suitable source for synchronisation");
+ LOG(LOGS_WARN, "No suitable source for synchronisation");
end_ref_mode(0);
break;
}
step = mode == REF_ModeUpdateOnce;
- LOG(LOGS_INFO, LOGF_Reference, "System clock wrong by %.6f seconds (%s)",
+ LOG(LOGS_INFO, "System clock wrong by %.6f seconds (%s)",
-offset, step ? "step" : "ignored");
if (step)
@@ -897,8 +953,7 @@ REF_SetReference(int stratum,
double our_frequency;
double abs_freq_ppm;
double update_interval;
- double elapsed;
- double correction_rate;
+ double elapsed, correction_rate, orig_root_distance;
double uncorrected_offset, accumulate_offset, step_offset;
struct timespec now, raw_now;
NTP_int64 ref_fuzz;
@@ -911,28 +966,10 @@ REF_SetReference(int stratum,
return;
}
- /* Guard against dividing by zero */
- if (skew < MIN_SKEW)
+ /* Guard against dividing by zero and NaN */
+ if (!(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, LOGF_Reference, "Bogus skew value encountered");
- return;
- }
- }
-
LCL_ReadRawTime(&raw_now);
LCL_GetOffsetCorrection(&raw_now, &uncorrected_offset, NULL);
UTI_AddDoubleToTimespec(&raw_now, uncorrected_offset, &now);
@@ -943,6 +980,8 @@ REF_SetReference(int stratum,
if (!is_offset_ok(our_offset))
return;
+ orig_root_distance = our_root_delay / 2.0 + get_root_dispersion(&now);
+
are_we_synchronised = leap != LEAP_Unsynchronised ? 1 : 0;
our_stratum = stratum + 1;
our_ref_id = ref_id;
@@ -1025,7 +1064,7 @@ REF_SetReference(int stratum,
LCL_AccumulateFrequencyAndOffset(our_frequency, accumulate_offset, correction_rate);
} else {
- DEBUG_LOG(LOGF_Reference, "Skew %f too large to track, offset=%f", skew, accumulate_offset);
+ DEBUG_LOG("Skew %f too large to track, offset=%f", skew, accumulate_offset);
LCL_AccumulateOffset(accumulate_offset, correction_rate);
@@ -1037,7 +1076,7 @@ REF_SetReference(int stratum,
if (step_offset != 0.0) {
if (LCL_ApplyStepOffset(step_offset))
- LOG(LOGS_WARN, LOGF_Reference, "System clock was stepped by %.6f seconds", -step_offset);
+ LOG(LOGS_WARN, "System clock was stepped by %.6f seconds", -step_offset);
}
LCL_SetSyncStatus(are_we_synchronised, offset_sd, offset_sd + root_delay / 2.0 + root_dispersion);
@@ -1053,16 +1092,8 @@ REF_SetReference(int stratum,
abs_freq_ppm = LCL_ReadAbsoluteFrequency();
- write_log(&now,
- our_ref_ip.family != IPADDR_UNSPEC ? UTI_IPToString(&our_ref_ip) : UTI_RefidToString(our_ref_id),
- our_stratum,
- our_leap_status,
- abs_freq_ppm,
- 1.0e6*our_skew,
- our_offset,
- combined_sources,
- offset_sd,
- uncorrected_offset);
+ write_log(&now, combined_sources, abs_freq_ppm, our_offset, offset_sd,
+ uncorrected_offset, orig_root_distance);
if (drift_file) {
/* Update drift file at most once per hour */
@@ -1074,7 +1105,7 @@ REF_SetReference(int stratum,
}
/* Update fallback drifts */
- if (fb_drifts) {
+ if (fb_drifts && are_we_synchronised) {
update_fb_drifts(abs_freq_ppm, update_interval);
schedule_fb_drift(&now);
}
@@ -1136,20 +1167,15 @@ REF_SetUnsynchronised(void)
}
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;
LCL_SetSyncStatus(0, 0.0, 0.0);
- write_log(&now,
- "0.0.0.0",
- 0,
- our_leap_status,
- LCL_ReadAbsoluteFrequency(),
- 1.0e6*our_skew,
- 0.0,
- 0,
- 0.0,
- uncorrected_offset);
+ write_log(&now, 0, LCL_ReadAbsoluteFrequency(), 0.0, 0.0, uncorrected_offset,
+ our_root_delay / 2.0 + get_root_dispersion(&now));
}
/* ================================================== */
@@ -1167,14 +1193,12 @@ REF_GetReferenceParams
double *root_dispersion
)
{
- double elapsed, dispersion;
+ double dispersion;
assert(initialised);
if (are_we_synchronised) {
- elapsed = UTI_DiffTimespecsToDouble(local_time, &our_ref_time);
- dispersion = our_root_dispersion +
- (our_skew + fabs(our_residual_freq) + LCL_GetMaxClockError()) * elapsed;
+ dispersion = get_root_dispersion(local_time);
} else {
dispersion = 0.0;
}
@@ -1348,7 +1372,7 @@ REF_GetTrackingReport(RPT_TrackingReport *rep)
&rep->ref_id, &rep->ref_time,
&rep->root_delay, &rep->root_dispersion);
- if (rep->stratum == NTP_MAX_STRATUM)
+ if (rep->stratum == NTP_MAX_STRATUM && !synchronised)
rep->stratum = 0;
rep->ip_addr.family = IPADDR_UNSPEC;
diff --git a/regress.c b/regress.c
index cac0332..e767e2f 100644
--- a/regress.c
+++ b/regress.c
@@ -3,7 +3,7 @@
**********************************************************************
* 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
* it under the terms of version 2 of the GNU General Public License as
@@ -34,7 +34,7 @@
#include "logging.h"
#include "util.h"
-#define MAX_POINTS 128
+#define MAX_POINTS 64
void
RGR_WeightedRegression
@@ -285,7 +285,7 @@ RGR_FindBestRegression
n - start <= min_samples) {
if (start != resid_start) {
/* Ignore extra samples in returned nruns */
- nruns = n_runs_from_residuals(resid - resid_start + start, n - start);
+ nruns = n_runs_from_residuals(resid + (start - resid_start), n - start);
}
break;
} else {
@@ -340,7 +340,7 @@ RGR_FindBestRegression
0-521-43108-5). */
static double
-find_ordered_entry_with_flags(double *x, int n, int index, int *flags)
+find_ordered_entry_with_flags(double *x, int n, int index, char *flags)
{
int u, v, l, r;
double temp;
@@ -403,9 +403,9 @@ find_ordered_entry_with_flags(double *x, int n, int index, int *flags)
static double
find_ordered_entry(double *x, int n, int index)
{
- int flags[MAX_POINTS];
+ char flags[MAX_POINTS];
- memset(flags, 0, n * sizeof(int));
+ memset(flags, 0, n * sizeof (flags[0]));
return find_ordered_entry_with_flags(x, n, index, flags);
}
#endif
@@ -417,9 +417,9 @@ static double
find_median(double *x, int n)
{
int k;
- int flags[MAX_POINTS];
+ char flags[MAX_POINTS];
- memset(flags, 0, n*sizeof(int));
+ memset(flags, 0, n * sizeof (flags[0]));
k = n>>1;
if (n&1) {
return find_ordered_entry_with_flags(x, n, k, flags);
@@ -430,6 +430,19 @@ find_median(double *x, int n)
}
/* ================================================== */
+
+double
+RGR_FindMedian(double *x, int n)
+{
+ double tmp[MAX_POINTS];
+
+ assert(n > 0 && n <= MAX_POINTS);
+ memcpy(tmp, x, n * sizeof (tmp[0]));
+
+ return find_median(tmp, n);
+}
+
+/* ================================================== */
/* This function evaluates the equation
\sum_{i=0}^{n-1} x_i sign(y_i - a - b x_i)
@@ -509,7 +522,7 @@ RGR_FindBestRobustRegression
double mx, dx, my, dy;
int nruns = 0;
- assert(n < MAX_POINTS);
+ assert(n <= MAX_POINTS);
if (n < 2) {
return 0;
@@ -566,24 +579,18 @@ RGR_FindBestRobustRegression
Estimate standard deviation of b and expand range about b based
on that. */
sb = sqrt(s2 * W/V);
- if (sb > tol) {
- incr = 3.0 * sb;
- } else {
- incr = 3.0 * tol;
- }
+ incr = MAX(sb, tol);
- blo = b;
- bhi = b;
-
do {
- /* Make sure incr is significant to blo and bhi */
- while (bhi + incr == bhi || blo - incr == blo) {
- incr *= 2;
- }
+ incr *= 2.0;
+
+ /* Give up if the interval is too large */
+ if (incr > 100.0)
+ return 0;
+
+ blo = b - incr;
+ bhi = b + incr;
- blo -= incr;
- bhi += incr;
-
/* We don't want 'a' yet */
eval_robust_residual(x + start, y + start, n_points, blo, &a, &rlo);
eval_robust_residual(x + start, y + start, n_points, bhi, &a, &rhi);
@@ -594,6 +601,8 @@ RGR_FindBestRobustRegression
/* OK, so the root for b lies in (blo, bhi). Start bisecting */
do {
bmid = 0.5 * (blo + bhi);
+ if (!(blo < bmid && bmid < bhi))
+ break;
eval_robust_residual(x + start, y + start, n_points, bmid, &a, &rmid);
if (rmid == 0.0) {
break;
@@ -606,7 +615,7 @@ RGR_FindBestRobustRegression
} else {
assert(0);
}
- } while ((bhi - blo) > tol && (bmid - blo) * (bhi - bmid) > 0.0);
+ } while (bhi - blo > tol);
*b0 = a;
*b1 = bmid;
diff --git a/regress.h b/regress.h
index 4e4c32b..90055da 100644
--- a/regress.h
+++ b/regress.h
@@ -131,4 +131,7 @@ RGR_MultipleRegress
double *b2 /* estimated second slope */
);
+/* Return the median value from an array */
+extern double RGR_FindMedian(double *x, int n);
+
#endif /* GOT_REGRESS_H */
diff --git a/rtc.c b/rtc.c
index 05fcad7..33d04bf 100644
--- a/rtc.c
+++ b/rtc.c
@@ -104,7 +104,7 @@ apply_driftfile_time(time_t t)
if (now.tv_sec < t) {
if (LCL_ApplyStepOffset(now.tv_sec - t))
- LOG(LOGS_INFO, LOGF_Rtc, "System time restored from driftfile");
+ LOG(LOGS_INFO, "System time restored from driftfile");
}
}
@@ -142,7 +142,7 @@ RTC_Initialise(int initial_set)
if (file_name) {
if (CNF_GetRtcSync()) {
- LOG_FATAL(LOGF_Rtc, "rtcfile directive cannot be used with rtcsync");
+ LOG_FATAL("rtcfile directive cannot be used with rtcsync");
}
if (driver.init) {
@@ -150,7 +150,7 @@ RTC_Initialise(int initial_set)
driver_initialised = 1;
}
} else {
- LOG(LOGS_ERR, LOGF_Rtc, "RTC not supported on this operating system");
+ LOG(LOGS_ERR, "RTC not supported on this operating system");
}
}
}
diff --git a/rtc_linux.c b/rtc_linux.c
index 7394235..89855c2 100644
--- a/rtc_linux.c
+++ b/rtc_linux.c
@@ -189,7 +189,7 @@ accumulate_sample(time_t rtc, struct timespec *sys)
/* Discard all samples if the RTC was stepped back (not our trim) */
if (n_samples > 0 && rtc_sec[n_samples - 1] - rtc >= rtc_trim[n_samples - 1]) {
- DEBUG_LOG(LOGF_RtcLinux, "RTC samples discarded");
+ DEBUG_LOG("RTC samples discarded");
n_samples = 0;
}
@@ -294,7 +294,7 @@ slew_samples
coef_gain_rate += dfreq * (1.0 - coef_gain_rate);
}
- DEBUG_LOG(LOGF_RtcLinux, "dfreq=%.8f doffset=%.6f old_fast=%.6f old_rate=%.3f new_fast=%.6f new_rate=%.3f",
+ DEBUG_LOG("dfreq=%.8f doffset=%.6f old_fast=%.6f old_rate=%.3f new_fast=%.6f new_rate=%.3f",
dfreq, doffset,
old_seconds_fast, 1.0e6 * old_gain_rate,
coef_seconds_fast, 1.0e6 * coef_gain_rate);
@@ -371,7 +371,7 @@ t_from_rtc(struct tm *stm) {
diff = t2 - t1;
if (t1 - diff == -1)
- DEBUG_LOG(LOGF_RtcLinux, "Could not convert RTC time");
+ DEBUG_LOG("Could not convert RTC time");
return t1 - diff;
}
@@ -390,7 +390,7 @@ read_hwclock_file(const char *hwclock_file)
in = fopen(hwclock_file, "r");
if (!in) {
- LOG(LOGS_WARN, LOGF_RtcLinux, "Could not open %s : %s",
+ LOG(LOGS_WARN, "Could not open %s : %s",
hwclock_file, strerror(errno));
return;
}
@@ -408,8 +408,7 @@ read_hwclock_file(const char *hwclock_file)
} else if (i == 3 && !strncmp(line, "UTC", 3)) {
rtc_on_utc = 1;
} else {
- LOG(LOGS_WARN, LOGF_RtcLinux, "Could not read RTC LOCAL/UTC setting from %s",
- hwclock_file);
+ LOG(LOGS_WARN, "Could not read RTC LOCAL/UTC setting from %s", hwclock_file);
}
}
@@ -451,8 +450,7 @@ read_coefs_from_file(void)
&file_ref_offset,
&file_rate_ppm) == 4) {
} else {
- LOG(LOGS_WARN, LOGF_RtcLinux, "Could not read coefficients from %s",
- coefs_file_name);
+ LOG(LOGS_WARN, "Could not read coefficients from %s", coefs_file_name);
}
fclose(in);
}
@@ -485,7 +483,7 @@ write_coefs_to_file(int valid,time_t ref_time,double offset,double rate)
out = fopen(temp_coefs_file_name, "w");
if (!out) {
Free(temp_coefs_file_name);
- LOG(LOGS_WARN, LOGF_RtcLinux, "Could not open temporary RTC file %s.tmp for writing",
+ LOG(LOGS_WARN, "Could not open temporary RTC file %s.tmp for writing",
coefs_file_name);
return RTC_ST_BADFILE;
}
@@ -496,7 +494,7 @@ write_coefs_to_file(int valid,time_t ref_time,double offset,double rate)
r2 = fclose(out);
if (r1 < 0 || r2) {
Free(temp_coefs_file_name);
- LOG(LOGS_WARN, LOGF_RtcLinux, "Could not write to temporary RTC file %s.tmp",
+ LOG(LOGS_WARN, "Could not write to temporary RTC file %s.tmp",
coefs_file_name);
return RTC_ST_BADFILE;
}
@@ -506,7 +504,7 @@ write_coefs_to_file(int valid,time_t ref_time,double offset,double rate)
if (!stat(coefs_file_name,&buf)) {
if (chown(temp_coefs_file_name,buf.st_uid,buf.st_gid) ||
chmod(temp_coefs_file_name,buf.st_mode & 0777)) {
- LOG(LOGS_WARN, LOGF_RtcLinux,
+ LOG(LOGS_WARN,
"Could not change ownership or permissions of temporary RTC file %s.tmp",
coefs_file_name);
}
@@ -517,7 +515,7 @@ write_coefs_to_file(int valid,time_t ref_time,double offset,double rate)
if (rename(temp_coefs_file_name,coefs_file_name)) {
unlink(temp_coefs_file_name);
Free(temp_coefs_file_name);
- LOG(LOGS_WARN, LOGF_RtcLinux, "Could not replace old RTC file %s.tmp with new one %s",
+ LOG(LOGS_WARN, "Could not replace old RTC file %s.tmp with new one %s",
coefs_file_name, coefs_file_name);
return RTC_ST_BADFILE;
}
@@ -550,7 +548,7 @@ RTC_Linux_Initialise(void)
fd = open (CNF_GetRtcDevice(), O_RDWR);
if (fd < 0) {
- LOG(LOGS_ERR, LOGF_RtcLinux, "Could not open RTC device %s : %s",
+ LOG(LOGS_ERR, "Could not open RTC device %s : %s",
CNF_GetRtcDevice(), strerror(errno));
return 0;
}
@@ -611,16 +609,14 @@ switch_interrupts(int onoff)
if (onoff) {
status = ioctl(fd, RTC_UIE_ON, 0);
if (status < 0) {
- LOG(LOGS_ERR, LOGF_RtcLinux, "Could not %s RTC interrupt : %s",
- "enable", strerror(errno));
+ LOG(LOGS_ERR, "Could not %s RTC interrupt : %s", "enable", strerror(errno));
return;
}
skip_interrupts = 1;
} else {
status = ioctl(fd, RTC_UIE_OFF, 0);
if (status < 0) {
- LOG(LOGS_ERR, LOGF_RtcLinux, "Could not %s RTC interrupt : %s",
- "disable", strerror(errno));
+ LOG(LOGS_ERR, "Could not %s RTC interrupt : %s", "disable", strerror(errno));
return;
}
}
@@ -658,7 +654,7 @@ set_rtc(time_t new_rtc_time)
status = ioctl(fd, RTC_SET_TIME, &rtc_raw);
if (status < 0) {
- LOG(LOGS_ERR, LOGF_RtcLinux, "Could not set RTC time");
+ LOG(LOGS_ERR, "Could not set RTC time");
}
}
@@ -701,10 +697,10 @@ handle_initial_trim(void)
sys_error_now = rtc_error_now - coef_seconds_fast;
LCL_AccumulateOffset(sys_error_now, 0.0);
- LOG(LOGS_INFO, LOGF_RtcLinux, "System clock off from RTC by %f seconds (slew)",
+ LOG(LOGS_INFO, "System clock off from RTC by %f seconds (slew)",
sys_error_now);
} else {
- LOG(LOGS_WARN, LOGF_RtcLinux, "No valid rtcfile coefficients");
+ LOG(LOGS_WARN, "No valid rtcfile coefficients");
}
coefs_valid = 0;
@@ -729,7 +725,7 @@ handle_relock_after_trim(void)
if (valid) {
write_coefs_to_file(1,ref,fast,saved_coef_gain_rate);
} else {
- DEBUG_LOG(LOGF_RtcLinux, "Could not do regression after trim");
+ DEBUG_LOG("Could not do regression after trim");
}
coefs_valid = 0;
@@ -824,7 +820,7 @@ read_from_device(int fd_, int event, void *any)
if (status < 0) {
/* This looks like a bad error : the file descriptor was indicating it was
* ready to read but we couldn't read anything. Give up. */
- LOG(LOGS_ERR, LOGF_RtcLinux, "Could not read flags %s : %s", CNF_GetRtcDevice(), strerror(errno));
+ LOG(LOGS_ERR, "Could not read flags %s : %s", CNF_GetRtcDevice(), strerror(errno));
SCH_RemoveFileHandler(fd);
switch_interrupts(0); /* Likely to raise error too, but just to be sure... */
close(fd);
@@ -848,7 +844,7 @@ read_from_device(int fd_, int event, void *any)
status = ioctl(fd, RTC_RD_TIME, &rtc_raw);
if (status < 0) {
- LOG(LOGS_ERR, LOGF_RtcLinux, "Could not read time from %s : %s", CNF_GetRtcDevice(), strerror(errno));
+ LOG(LOGS_ERR, "Could not read time from %s : %s", CNF_GetRtcDevice(), strerror(errno));
error = 1;
goto turn_off_interrupt;
}
@@ -889,7 +885,7 @@ turn_off_interrupt:
switch (operating_mode) {
case OM_INITIAL:
if (error) {
- DEBUG_LOG(LOGF_RtcLinux, "Could not complete initial step due to errors");
+ DEBUG_LOG("Could not complete initial step due to errors");
operating_mode = OM_NORMAL;
(after_init_hook)(after_init_hook_arg);
@@ -902,7 +898,7 @@ turn_off_interrupt:
case OM_AFTERTRIM:
if (error) {
- DEBUG_LOG(LOGF_RtcLinux, "Could not complete after trim relock due to errors");
+ DEBUG_LOG("Could not complete after trim relock due to errors");
operating_mode = OM_NORMAL;
switch_interrupts(0);
@@ -1041,7 +1037,7 @@ RTC_Linux_TimePreInit(time_t driftfile_time)
UTI_AddDoubleToTimespec(&new_sys_time, -accumulated_error, &new_sys_time);
if (new_sys_time.tv_sec < driftfile_time) {
- LOG(LOGS_WARN, LOGF_RtcLinux, "RTC time before last driftfile modification (ignored)");
+ LOG(LOGS_WARN, "RTC time before last driftfile modification (ignored)");
return 0;
}
@@ -1050,7 +1046,7 @@ RTC_Linux_TimePreInit(time_t driftfile_time)
/* Set system time only if the step is larger than 1 second */
if (fabs(sys_offset) >= 1.0) {
if (LCL_ApplyStepOffset(sys_offset))
- LOG(LOGS_INFO, LOGF_RtcLinux, "System time set from RTC");
+ LOG(LOGS_INFO, "System time set from RTC");
}
} else {
return 0;
@@ -1095,7 +1091,7 @@ RTC_Linux_Trim(void)
if (fabs(coef_seconds_fast) > 1.0) {
- LOG(LOGS_INFO, LOGF_RtcLinux, "RTC wrong by %.3f seconds (step)",
+ LOG(LOGS_INFO, "RTC wrong by %.3f seconds (step)",
coef_seconds_fast);
/* Do processing to set clock. Let R be the value we set the
diff --git a/sched.c b/sched.c
index e4b541d..21b55a7 100644
--- a/sched.c
+++ b/sched.c
@@ -163,7 +163,7 @@ SCH_AddFileHandler
assert(fd >= 0);
if (fd >= FD_SETSIZE)
- LOG_FATAL(LOGF_Scheduler, "Too many file descriptors");
+ LOG_FATAL("Too many file descriptors");
/* Resize the array if the descriptor is highest so far */
while (ARR_GetSize(file_handlers) <= fd) {
@@ -350,7 +350,7 @@ SCH_AddTimeoutByDelay(double delay, SCH_TimeoutHandler handler, SCH_ArbitraryArg
LCL_ReadRawTime(&now);
UTI_AddDoubleToTimespec(&now, delay, &then);
if (UTI_CompareTimespecs(&now, &then) > 0) {
- LOG_FATAL(LOGF_Scheduler, "Timeout overflow");
+ LOG_FATAL("Timeout overflow");
}
return SCH_AddTimeout(&then, handler, arg);
@@ -512,7 +512,7 @@ dispatch_timeouts(struct timespec *now) {
more time than was delay of a scheduled timeout. */
if (n_done > n_timer_queue_entries * 4 &&
n_done > n_entries_on_start * 4) {
- LOG_FATAL(LOGF_Scheduler, "Possible infinite loop in scheduling");
+ LOG_FATAL("Possible infinite loop in scheduling");
}
}
}
@@ -680,10 +680,10 @@ check_current_time(struct timespec *prev_raw, struct timespec *raw, int timeout,
if (last_select_ts_raw.tv_sec + elapsed_min.tv_sec >
raw->tv_sec + JUMP_DETECT_THRESHOLD) {
- LOG(LOGS_WARN, LOGF_Scheduler, "Backward time jump detected!");
+ LOG(LOGS_WARN, "Backward time jump detected!");
} else if (prev_raw->tv_sec + elapsed_max.tv_sec + JUMP_DETECT_THRESHOLD <
raw->tv_sec) {
- LOG(LOGS_WARN, LOGF_Scheduler, "Forward time jump detected!");
+ LOG(LOGS_WARN, "Forward time jump detected!");
} else {
return 1;
}
@@ -742,7 +742,7 @@ SCH_MainLoop(void)
/* if there are no file descriptors being waited on and no
timeout set, this is clearly ridiculous, so stop the run */
if (!ptv && !p_read_fds && !p_write_fds)
- LOG_FATAL(LOGF_Scheduler, "Nothing to do");
+ LOG_FATAL("Nothing to do");
status = select(one_highest_fd, p_read_fds, p_write_fds, p_except_fds, ptv);
errsv = errno;
@@ -762,7 +762,7 @@ SCH_MainLoop(void)
if (status < 0) {
if (!need_to_exit && errsv != EINTR) {
- LOG_FATAL(LOGF_Scheduler, "select() failed : %s", strerror(errsv));
+ LOG_FATAL("select() failed : %s", strerror(errsv));
}
} else if (status > 0) {
/* A file descriptor is ready for input or output */
diff --git a/sched.h b/sched.h
index 837c914..bfb6169 100644
--- a/sched.h
+++ b/sched.h
@@ -34,7 +34,8 @@ typedef unsigned int SCH_TimeoutID;
typedef enum {
SCH_ReservedTimeoutValue = 0,
- SCH_NtpSamplingClass,
+ SCH_NtpClientClass,
+ SCH_NtpPeerClass,
SCH_NtpBroadcastClass,
SCH_NumberOfClasses /* needs to be last */
} SCH_TimeoutClass;
diff --git a/smooth.c b/smooth.c
index 08b80ba..a21dcd8 100644
--- a/smooth.c
+++ b/smooth.c
@@ -208,7 +208,7 @@ update_stages(void)
stages[2].length = l3;
for (i = 0; i < NUM_STAGES; i++) {
- DEBUG_LOG(LOGF_Smooth, "Smooth stage %d wander %e length %f",
+ DEBUG_LOG("Smooth stage %d wander %e length %f",
i + 1, stages[i].wander, stages[i].length);
}
}
@@ -230,7 +230,7 @@ update_smoothing(struct timespec *now, double offset, double freq)
update_stages();
- DEBUG_LOG(LOGF_Smooth, "Smooth offset %e freq %e", smooth_offset, smooth_freq);
+ DEBUG_LOG("Smooth offset %e freq %e", smooth_offset, smooth_freq);
}
static void
@@ -246,7 +246,8 @@ handle_slew(struct timespec *raw, struct timespec *cooked, double 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)
@@ -264,6 +265,8 @@ void SMT_Initialise(void)
max_freq *= 1e-6;
max_wander *= 1e-6;
+ UTI_ZeroTimespec(&last_update);
+
LCL_AddParameterChangeHandler(handle_slew, NULL);
}
@@ -295,7 +298,7 @@ SMT_Activate(struct timespec *now)
if (!enabled || !locked)
return;
- LOG(LOGS_INFO, LOGF_Smooth, "Time smoothing activated%s", leap_only_mode ?
+ LOG(LOGS_INFO, "Time smoothing activated%s", leap_only_mode ?
" (leap seconds only)" : "");
locked = 0;
last_update = *now;
diff --git a/sources.c b/sources.c
index f91ffb1..67b61e7 100644
--- a/sources.c
+++ b/sources.c
@@ -213,7 +213,9 @@ void SRC_Finalise(void)
/* Function to create a new instance. This would be called by one of
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;
@@ -225,7 +227,8 @@ SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_optio
max_samples = CNF_GetMaxSamples();
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) {
/* Reallocate memory */
@@ -348,12 +351,12 @@ void SRC_AccumulateSample
inst->leap_status = leap_status;
- DEBUG_LOG(LOGF_Sources, "ip=[%s] t=%s ofs=%f del=%f disp=%f str=%d",
+ DEBUG_LOG("ip=[%s] t=%s ofs=%f del=%f disp=%f str=%d",
source_to_string(inst), UTI_TimespecToString(sample_time), -offset,
root_delay, root_dispersion, stratum);
if (REF_IsLeapSecondClose()) {
- LOG(LOGS_INFO, LOGF_Sources, "Dropping sample around leap second");
+ LOG(LOGS_INFO, "Dropping sample around leap second");
return;
}
@@ -451,7 +454,7 @@ log_selection_message(char *format, char *arg)
{
if (REF_GetMode() != REF_ModeNormal)
return;
- LOG(LOGS_INFO, LOGF_Sources, format, arg);
+ LOG(LOGS_INFO, format, arg);
}
/* ================================================== */
@@ -563,7 +566,7 @@ combine_sources(int n_sel_sources, struct timespec *ref_time, double *offset,
offset_weight = 1.0 / sources[index]->sel_info.root_distance;
frequency_weight = 1.0 / src_skew;
- DEBUG_LOG(LOGF_Sources, "combining index=%d oweight=%e offset=%e sd=%e fweight=%e freq=%e skew=%e",
+ DEBUG_LOG("combining index=%d oweight=%e offset=%e sd=%e fweight=%e freq=%e skew=%e",
index, offset_weight, src_offset, src_offset_sd, frequency_weight, src_frequency, src_skew);
sum_offset_weight += offset_weight;
@@ -584,7 +587,7 @@ combine_sources(int n_sel_sources, struct timespec *ref_time, double *offset,
*frequency = sum_frequency / sum_frequency_weight;
*skew = 1.0 / sqrt(inv_sum2_skew);
- DEBUG_LOG(LOGF_Sources, "combined result offset=%e sd=%e freq=%e skew=%e",
+ DEBUG_LOG("combined result offset=%e sd=%e freq=%e skew=%e",
*offset, *offset_sd, *frequency, *skew);
return combined;
@@ -736,12 +739,11 @@ SRC_SelectSource(SRC_Instance updated_inst)
uint32_t local_ref_id = NSR_GetLocalRefid(sources[orphan_source]->ip_addr);
if (!local_ref_id) {
- LOG(LOGS_ERR, LOGF_Sources, "Unknown local refid in orphan mode");
+ LOG(LOGS_ERR, "Unknown local refid in orphan mode");
} else if (sources[orphan_source]->ref_id < local_ref_id) {
sources[orphan_source]->status = SRC_OK;
n_sel_sources = 1;
- DEBUG_LOG(LOGF_Sources, "selecting orphan refid=%"PRIx32,
- sources[orphan_source]->ref_id);
+ DEBUG_LOG("selecting orphan refid=%"PRIx32, sources[orphan_source]->ref_id);
}
}
@@ -765,7 +767,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
n_endpoints += 2;
}
- DEBUG_LOG(LOGF_Sources, "badstat=%d sel=%d badstat_reach=%x sel_reach=%x max_reach_ago=%f",
+ DEBUG_LOG("badstat=%d sel=%d badstat_reach=%x sel_reach=%x max_reach_ago=%f",
n_badstats_sources, n_sel_sources, max_badstat_reach,
max_sel_reach, max_reach_sample_ago);
@@ -1003,7 +1005,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
sources[i]->sel_score = 1.0 / distance;
}
- DEBUG_LOG(LOGF_Sources, "select score=%f refid=%"PRIx32" match_refid=%"PRIx32" status=%d dist=%f",
+ DEBUG_LOG("select score=%f refid=%"PRIx32" match_refid=%"PRIx32" status=%d dist=%f",
sources[i]->sel_score, sources[i]->ref_id,
updated_inst ? updated_inst->ref_id : 0,
sources[i]->status, distance);
@@ -1027,7 +1029,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
if (sources[max_score_index]->updates == 0) {
selected_source_index = INVALID_SOURCE;
mark_ok_sources(SRC_WAITS_UPDATE);
- DEBUG_LOG(LOGF_Sources, "best source has no updates");
+ DEBUG_LOG("best source has no updates");
return;
}
@@ -1098,7 +1100,7 @@ SRC_SetReselectDistance(double distance)
{
if (reselect_distance != distance) {
reselect_distance = distance;
- LOG(LOGS_INFO, LOGF_Sources, "New reselect distance %f", distance);
+ LOG(LOGS_INFO, "New reselect distance %f", distance);
}
}
@@ -1153,7 +1155,7 @@ FILE *open_dumpfile(SRC_Instance inst, const char *mode)
dumpdir = CNF_GetDumpDir();
if (dumpdir[0] == '\0') {
- LOG(LOGS_WARN, LOGF_Sources, "dumpdir not specified");
+ LOG(LOGS_WARN, "dumpdir not specified");
return NULL;
}
@@ -1164,13 +1166,13 @@ FILE *open_dumpfile(SRC_Instance inst, const char *mode)
(inst->type != SRC_NTP &&
snprintf(filename, sizeof (filename), "%s/refid:%08"PRIx32".dat",
dumpdir, inst->ref_id) >= sizeof (filename))) {
- LOG(LOGS_WARN, LOGF_Sources, "dumpdir too long");
+ LOG(LOGS_WARN, "dumpdir too long");
return NULL;
}
f = fopen(filename, mode);
if (!f && mode[0] != 'r')
- LOG(LOGS_WARN, LOGF_Sources, "Could not open dump file for %s",
+ LOG(LOGS_WARN, "Could not open dump file for %s",
source_to_string(inst));
return f;
@@ -1207,10 +1209,10 @@ SRC_ReloadSources(void)
if (!in)
continue;
if (!SST_LoadFromFile(sources[i]->stats, in))
- LOG(LOGS_WARN, LOGF_Sources, "Could not load dump file for %s",
+ LOG(LOGS_WARN, "Could not load dump file for %s",
source_to_string(sources[i]));
else
- LOG(LOGS_INFO, LOGF_Sources, "Loaded dump file for %s",
+ LOG(LOGS_INFO, "Loaded dump file for %s",
source_to_string(sources[i]));
fclose(in);
}
@@ -1248,7 +1250,7 @@ SRC_RemoveDumpFiles(void)
if (strncmp(name, "refid:", 6) && !UTI_StringToIP(name, &ip_addr))
continue;
- DEBUG_LOG(LOGF_Sources, "Removing %s", gl.gl_pathv[i]);
+ DEBUG_LOG("Removing %s", gl.gl_pathv[i]);
unlink(gl.gl_pathv[i]);
}
diff --git a/sources.h b/sources.h
index 9acf98b..60d28fd 100644
--- a/sources.h
+++ b/sources.h
@@ -59,7 +59,9 @@ typedef enum {
/* Function to create a new instance. This would be called by one of
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.
This may cause the current reference source to be reselected, if this
diff --git a/sourcestats.c b/sourcestats.c
index c05b4bc..2aec02c 100644
--- a/sourcestats.c
+++ b/sourcestats.c
@@ -3,7 +3,7 @@
**********************************************************************
* 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
* it under the terms of version 2 of the GNU General Public License as
@@ -51,9 +51,6 @@
#define MIN_SKEW 1.0e-12
#define MAX_SKEW 1.0e+02
-/* The minimum assumed std dev for weighting */
-#define MIN_WEIGHT_SD 1.0e-9
-
/* The asymmetry of network jitter when all jitter is in one direction */
#define MAX_ASYMMETRY 0.5
@@ -85,6 +82,12 @@ struct SST_Stats_Record {
int min_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
buffer. */
int n_samples;
@@ -200,13 +203,16 @@ SST_Finalise(void)
/* This function creates a new instance of the statistics handler */
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;
inst = MallocNew(struct SST_Stats_Record);
inst->min_samples = min_samples;
inst->max_samples = max_samples;
+ inst->fixed_min_delay = min_delay;
+ inst->fixed_asymmetry = asymmetry;
SST_SetRefid(inst, refid, addr);
SST_ResetInstance(inst);
@@ -295,7 +301,7 @@ SST_AccumulateSample(SST_Stats inst, struct timespec *sample_time,
/* Make sure it's newer than the last sample */
if (inst->n_samples &&
UTI_CompareTimespecs(&inst->sample_times[inst->last_sample], sample_time) >= 0) {
- LOG(LOGS_WARN, LOGF_SourceStats, "Out of order sample detected, discarding history for %s",
+ LOG(LOGS_WARN, "Out of order sample detected, discarding history for %s",
inst->ip_addr ? UTI_IPToString(inst->ip_addr) : UTI_RefidToString(inst->refid));
SST_ResetInstance(inst);
}
@@ -313,6 +319,9 @@ SST_AccumulateSample(SST_Stats inst, struct timespec *sample_time,
inst->root_dispersions[m] = root_dispersion;
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])
inst->min_delay_sample = n;
@@ -418,45 +427,63 @@ find_min_delay_sample(SST_Stats inst)
minimum network delay. This can significantly improve the accuracy and
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
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;
- /* Don't try to estimate the asymmetry with reference clocks */
- if (!inst->ip_addr)
+ /* Check if the asymmetry was not specified to be zero */
+ if (inst->fixed_asymmetry == 0.0)
return;
+ min_delay = SST_MinRoundTripDelay(inst);
n = inst->runs_samples + inst->n_samples;
for (i = 0; i < n; i++)
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 (!RGR_MultipleRegress(times_back, delays, offsets, n, &asymmetry) ||
- asymmetry * inst->asymmetry_run < 0.0) {
- inst->asymmetry_run = 0;
- inst->asymmetry = 0.0;
- return;
+ if (fabs(inst->fixed_asymmetry) <= MAX_ASYMMETRY) {
+ inst->asymmetry = inst->fixed_asymmetry;
+ } else {
+ if (!estimate_asymmetry(times_back, offsets, delays, n,
+ &inst->asymmetry, &inst->asymmetry_run))
+ 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 */
for (i = 0; i < n; i++)
- offsets[i] -= asymmetry * delays[i];
-
- inst->asymmetry = asymmetry;
+ offsets[i] -= inst->asymmetry * delays[i];
}
/* ================================================== */
@@ -466,7 +493,7 @@ correct_asymmetry(SST_Stats inst, double *times_back, double *offsets)
time. E.g. a value of 4 means that we think the standard deviation
is four times the fluctuation of the peer distance */
-#define SD_TO_DIST_RATIO 1.0
+#define SD_TO_DIST_RATIO 0.7
/* ================================================== */
/* This function runs the linear regression operation on the data. It
@@ -486,9 +513,10 @@ SST_DoNewRegression(SST_Stats inst)
int best_start, times_back_start;
double est_intercept, est_slope, est_var, est_intercept_sd, est_slope_sd;
int i, j, nruns;
- double min_distance, mean_distance;
+ double min_distance, median_distance;
double sd_weight, sd;
double old_skew, old_freq, stress;
+ double precision;
convert_to_intervals(inst, times_back + inst->runs_samples);
@@ -497,24 +525,28 @@ SST_DoNewRegression(SST_Stats inst)
offsets[i + inst->runs_samples] = inst->offsets[get_runsbuf_index(inst, i)];
}
- for (i = 0, mean_distance = 0.0, min_distance = DBL_MAX; i < inst->n_samples; i++) {
+ for (i = 0, min_distance = DBL_MAX; i < inst->n_samples; i++) {
j = get_buf_index(inst, i);
peer_distances[i] = 0.5 * inst->peer_delays[get_runsbuf_index(inst, i)] +
inst->peer_dispersions[j];
- mean_distance += peer_distances[i];
if (peer_distances[i] < min_distance) {
min_distance = peer_distances[i];
}
}
- mean_distance /= inst->n_samples;
/* And now, work out the weight vector */
- sd = mean_distance - min_distance;
- sd = CLAMP(MIN_WEIGHT_SD, sd, min_distance);
+ precision = LCL_GetSysPrecisionAsQuantum();
+ median_distance = RGR_FindMedian(peer_distances, inst->n_samples);
+
+ sd = (median_distance - min_distance) / SD_TO_DIST_RATIO;
+ sd = CLAMP(precision, sd, min_distance);
+ min_distance += precision;
for (i=0; i<inst->n_samples; i++) {
- sd_weight = 1.0 + SD_TO_DIST_RATIO * (peer_distances[i] - min_distance) / sd;
+ sd_weight = 1.0;
+ if (peer_distances[i] > min_distance)
+ sd_weight += (peer_distances[i] - min_distance) / sd;
weights[i] = sd_weight * sd_weight;
}
}
@@ -545,7 +577,7 @@ SST_DoNewRegression(SST_Stats inst)
inst->skew = CLAMP(MIN_SKEW, inst->skew, MAX_SKEW);
stress = fabs(old_freq - inst->estimated_frequency) / old_skew;
- DEBUG_LOG(LOGF_SourceStats, "off=%e freq=%e skew=%e n=%d bs=%d runs=%d asym=%f arun=%d",
+ DEBUG_LOG("off=%e freq=%e skew=%e n=%d bs=%d runs=%d asym=%f arun=%d",
inst->estimated_offset, inst->estimated_frequency, inst->skew,
inst->n_samples, best_start, inst->nruns,
inst->asymmetry, inst->asymmetry_run);
@@ -624,7 +656,7 @@ SST_GetSelectionData(SST_Stats inst, struct timespec *now,
*stratum = inst->strata[get_buf_index(inst, inst->n_samples - 1)];
*std_dev = inst->std_dev;
- sample_elapsed = UTI_DiffTimespecsToDouble(now, &inst->sample_times[i]);
+ sample_elapsed = fabs(UTI_DiffTimespecsToDouble(now, &inst->sample_times[i]));
offset = inst->offsets[i] + sample_elapsed * inst->estimated_frequency;
*root_distance = 0.5 * inst->root_delays[j] +
inst->root_dispersions[j] + sample_elapsed * inst->skew;
@@ -653,7 +685,7 @@ SST_GetSelectionData(SST_Stats inst, struct timespec *now,
*select_ok = inst->regression_ok;
- DEBUG_LOG(LOGF_SourceStats, "n=%d off=%f dist=%f sd=%f first_ago=%f last_ago=%f selok=%d",
+ DEBUG_LOG("n=%d off=%f dist=%f sd=%f first_ago=%f last_ago=%f selok=%d",
inst->n_samples, offset, *root_distance, *std_dev,
*first_sample_ago, *last_sample_ago, *select_ok);
}
@@ -684,8 +716,9 @@ SST_GetTrackingData(SST_Stats inst, struct timespec *ref_time,
elapsed_sample = UTI_DiffTimespecsToDouble(&inst->offset_time, &inst->sample_times[i]);
*root_dispersion = inst->root_dispersions[j] + inst->skew * elapsed_sample;
- DEBUG_LOG(LOGF_SourceStats, "n=%d freq=%f (%.3fppm) skew=%f (%.3fppm) avoff=%f offsd=%f disp=%f",
- inst->n_samples, *frequency, 1.0e6* *frequency, *skew, 1.0e6* *skew, *average_offset, *offset_sd, *root_dispersion);
+ DEBUG_LOG("n=%d freq=%f (%.3fppm) skew=%f (%.3fppm) avoff=%f offsd=%f disp=%f",
+ inst->n_samples, *frequency, 1.0e6* *frequency, *skew, 1.0e6* *skew,
+ *average_offset, *offset_sd, *root_dispersion);
}
@@ -719,7 +752,7 @@ SST_SlewSamples(SST_Stats inst, struct timespec *when, double dfreq, double doff
inst->estimated_offset += delta_time;
inst->estimated_frequency = (inst->estimated_frequency - dfreq) / (1.0 - dfreq);
- DEBUG_LOG(LOGF_SourceStats, "n=%d m=%d old_off_time=%s new=%s old_off=%f new_off=%f old_freq=%.3f new_freq=%.3f",
+ DEBUG_LOG("n=%d m=%d old_off_time=%s new=%s old_off=%f new_off=%f old_freq=%.3f new_freq=%.3f",
inst->n_samples, inst->runs_samples,
UTI_TimespecToString(&prev), UTI_TimespecToString(&inst->offset_time),
prev_offset, inst->estimated_offset,
@@ -768,47 +801,33 @@ SST_PredictOffset(SST_Stats inst, struct timespec *when)
double
SST_MinRoundTripDelay(SST_Stats inst)
{
+ if (inst->fixed_min_delay > 0.0)
+ return inst->fixed_min_delay;
+
if (!inst->n_samples)
return DBL_MAX;
+
return inst->peer_delays[inst->min_delay_sample];
}
/* ================================================== */
int
-SST_IsGoodSample(SST_Stats inst, double offset, double delay,
- double max_delay_dev_ratio, double clock_error, struct timespec *when)
+SST_GetDelayTestData(SST_Stats inst, struct timespec *sample_time,
+ 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 < 3)
- return 1;
-
- elapsed = UTI_DiffTimespecsToDouble(when, &inst->offset_time);
-
- /* 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 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;
+ if (inst->n_samples < 6)
+ return 0;
- DEBUG_LOG(LOGF_SourceStats, "Bad sample: offset=%f delay=%f incr_delay=%f allowed=%f",
- offset, delay, allowed_increase, delay_increase);
+ *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;
- return 0;
+ return 1;
}
/* ================================================== */
diff --git a/sourcestats.h b/sourcestats.h
index 48f73b3..f0a5ca9 100644
--- a/sourcestats.h
+++ b/sourcestats.h
@@ -38,7 +38,9 @@ extern void SST_Initialise(void);
extern void SST_Finalise(void);
/* 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. */
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 */
extern double SST_MinRoundTripDelay(SST_Stats inst);
-/* This routine determines if a new sample is good enough that it should be
- accumulated */
-extern int SST_IsGoodSample(SST_Stats inst, double offset, double delay,
- double max_delay_dev_ratio, double clock_error, struct timespec *when);
+/* Get data needed for testing NTP delay */
+extern int SST_GetDelayTestData(SST_Stats inst, struct timespec *sample_time,
+ double *last_sample_ago, double *predicted_offset,
+ double *min_delay, double *skew, double *std_dev);
extern void SST_SaveToFile(SST_Stats inst, FILE *out);
diff --git a/srcparams.h b/srcparams.h
index bdf13a8..5bd591d 100644
--- a/srcparams.h
+++ b/srcparams.h
@@ -48,6 +48,8 @@ typedef struct {
double max_delay;
double max_delay_ratio;
double max_delay_dev_ratio;
+ double min_delay;
+ double asymmetry;
double offset;
} SourceParameters;
@@ -63,6 +65,7 @@ typedef struct {
#define SRC_DEFAULT_MAXSOURCES 4
#define SRC_DEFAULT_MINSAMPLES (-1)
#define SRC_DEFAULT_MAXSAMPLES (-1)
+#define SRC_DEFAULT_ASYMMETRY 1.0
#define INACTIVE_AUTHKEY 0
/* Flags for source selection */
diff --git a/stubs.c b/stubs.c
index 04e56a3..eac81c0 100644
--- a/stubs.c
+++ b/stubs.c
@@ -91,7 +91,7 @@ DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *
inst->arg = anything;
if (pipe(inst->pipe))
- LOG_FATAL(LOGF_Nameserv, "pipe() failed");
+ LOG_FATAL("pipe() failed");
UTI_FdSetCloexec(inst->pipe[0]);
UTI_FdSetCloexec(inst->pipe[1]);
diff --git a/sys.c b/sys.c
index 248c1e8..5b56aae 100644
--- a/sys.c
+++ b/sys.c
@@ -30,6 +30,7 @@
#include "sysincl.h"
#include "sys.h"
+#include "sys_null.h"
#include "logging.h"
#if defined(LINUX)
@@ -44,9 +45,18 @@
/* ================================================== */
+static int null_driver;
+
+/* ================================================== */
+
void
-SYS_Initialise(void)
+SYS_Initialise(int clock_control)
{
+ null_driver = !clock_control;
+ if (null_driver) {
+ SYS_Null_Initialise();
+ return;
+ }
#if defined(LINUX)
SYS_Linux_Initialise();
#elif defined(SOLARIS)
@@ -65,6 +75,10 @@ SYS_Initialise(void)
void
SYS_Finalise(void)
{
+ if (null_driver) {
+ SYS_Null_Finalise();
+ return;
+ }
#if defined(LINUX)
SYS_Linux_Finalise();
#elif defined(SOLARIS)
@@ -91,7 +105,7 @@ void SYS_DropRoot(uid_t uid, gid_t gid)
#elif defined(MACOSX) && defined(FEAT_PRIVDROP)
SYS_MacOSX_DropRoot(uid, gid);
#else
- LOG_FATAL(LOGF_Sys, "dropping root privileges not supported");
+ LOG_FATAL("dropping root privileges not supported");
#endif
}
@@ -102,7 +116,7 @@ void SYS_EnableSystemCallFilter(int level)
#if defined(LINUX) && defined(FEAT_SCFILTER)
SYS_Linux_EnableSystemCallFilter(level);
#else
- LOG_FATAL(LOGF_Sys, "system call filter not supported");
+ LOG_FATAL("system call filter not supported");
#endif
}
@@ -115,7 +129,7 @@ void SYS_SetScheduler(int SchedPriority)
#elif defined(MACOSX)
SYS_MacOSX_SetScheduler(SchedPriority);
#else
- LOG_FATAL(LOGF_Sys, "scheduler priority setting not supported");
+ LOG_FATAL("scheduler priority setting not supported");
#endif
}
@@ -126,7 +140,7 @@ void SYS_LockMemory(void)
#if defined(LINUX) && defined(HAVE_MLOCKALL)
SYS_Linux_MemLockAll(1);
#else
- LOG_FATAL(LOGF_Sys, "memory locking not supported");
+ LOG_FATAL("memory locking not supported");
#endif
}
diff --git a/sys.h b/sys.h
index bd990e2..cb726f2 100644
--- a/sys.h
+++ b/sys.h
@@ -30,7 +30,7 @@
#define GOT_SYS_H
/* Called at the start of the run to do initialisation */
-extern void SYS_Initialise(void);
+extern void SYS_Initialise(int clock_control);
/* Called at the end of the run to do final clean-up */
extern void SYS_Finalise(void);
diff --git a/sys_generic.c b/sys_generic.c
index 90eaa0c..9c785d2 100644
--- a/sys_generic.c
+++ b/sys_generic.c
@@ -129,7 +129,7 @@ start_fastslew(void)
drv_accrue_offset(offset_register, 0.0);
- DEBUG_LOG(LOGF_SysGeneric, "fastslew offset=%e", offset_register);
+ DEBUG_LOG("fastslew offset=%e", offset_register);
offset_register = 0.0;
fastslew_active = 1;
@@ -246,7 +246,7 @@ update_slew(void)
slew_timeout_id = SCH_AddTimeout(&end_of_slew, handle_end_of_slew, NULL);
slew_start = now;
- DEBUG_LOG(LOGF_SysGeneric, "slew offset=%e corr_rate=%e base_freq=%f total_freq=%f slew_freq=%e duration=%f slew_error=%e",
+ DEBUG_LOG("slew offset=%e corr_rate=%e base_freq=%f total_freq=%f slew_freq=%e duration=%f slew_error=%e",
offset_register, correction_rate, base_freq, total_freq, slew_freq,
duration, slew_error);
}
@@ -333,7 +333,7 @@ apply_step_offset(double offset)
UTI_TimespecToTimeval(&new_time, &new_time_tv);
if (PRV_SetTime(&new_time_tv, NULL) < 0) {
- DEBUG_LOG(LOGF_SysGeneric, "settimeofday() failed");
+ DEBUG_LOG("settimeofday() failed");
return 0;
}
diff --git a/sys_linux.c b/sys_linux.c
index 9e8ed65..190b54f 100644
--- a/sys_linux.c
+++ b/sys_linux.c
@@ -4,7 +4,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* 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
* it under the terms of version 2 of the GNU General Public License as
@@ -240,7 +240,7 @@ guess_hz(void)
}
/* oh dear. doomed. */
- LOG_FATAL(LOGF_SysLinux, "Can't determine hz from tick %d", tick);
+ LOG_FATAL("Can't determine hz from tick %d", tick);
return 0;
}
@@ -283,11 +283,11 @@ get_kernel_version(int *major, int *minor, int *patch)
struct utsname uts;
if (uname(&uts) < 0)
- LOG_FATAL(LOGF_SysLinux, "uname() failed");
+ LOG_FATAL("uname() failed");
*patch = 0;
if (sscanf(uts.release, "%d.%d.%d", major, minor, patch) < 2)
- LOG_FATAL(LOGF_SysLinux, "Could not parse kernel version");
+ LOG_FATAL("Could not parse kernel version");
}
/* ================================================== */
@@ -314,10 +314,10 @@ get_version_specific_details(void)
tick_update_hz = 100;
get_kernel_version(&major, &minor, &patch);
- DEBUG_LOG(LOGF_SysLinux, "Linux kernel major=%d minor=%d patch=%d", major, minor, patch);
+ DEBUG_LOG("Linux kernel major=%d minor=%d patch=%d", major, minor, patch);
if (kernelvercmp(major, minor, patch, 2, 2, 0) < 0) {
- LOG_FATAL(LOGF_SysLinux, "Kernel version not supported, sorry.");
+ LOG_FATAL("Kernel version not supported, sorry.");
}
if (kernelvercmp(major, minor, patch, 2, 6, 27) >= 0 &&
@@ -334,7 +334,7 @@ get_version_specific_details(void)
have_setoffset = 1;
}
- DEBUG_LOG(LOGF_SysLinux, "hz=%d nominal_tick=%d max_tick_bias=%d",
+ DEBUG_LOG("hz=%d nominal_tick=%d max_tick_bias=%d",
hz, nominal_tick, max_tick_bias);
}
@@ -391,7 +391,7 @@ SYS_Linux_Initialise(void)
reset_adjtime_offset();
if (have_setoffset && !test_step_offset()) {
- LOG(LOGS_INFO, LOGF_SysLinux, "adjtimex() doesn't support ADJ_SETOFFSET");
+ LOG(LOGS_INFO, "adjtimex() doesn't support ADJ_SETOFFSET");
have_setoffset = 0;
}
@@ -421,7 +421,7 @@ SYS_Linux_DropRoot(uid_t uid, gid_t gid)
cap_t cap;
if (prctl(PR_SET_KEEPCAPS, 1)) {
- LOG_FATAL(LOGF_SysLinux, "prctl() failed");
+ LOG_FATAL("prctl() failed");
}
UTI_DropRoot(uid, gid);
@@ -431,11 +431,11 @@ SYS_Linux_DropRoot(uid_t uid, gid_t gid)
"cap_net_bind_service,cap_sys_time=ep" : "cap_sys_time=ep";
if ((cap = cap_from_text(cap_text)) == NULL) {
- LOG_FATAL(LOGF_SysLinux, "cap_from_text() failed");
+ LOG_FATAL("cap_from_text() failed");
}
if (cap_set_proc(cap)) {
- LOG_FATAL(LOGF_SysLinux, "cap_set_proc() failed");
+ LOG_FATAL("cap_set_proc() failed");
}
cap_free(cap);
@@ -454,7 +454,7 @@ void check_seccomp_applicability(void)
CNF_GetMailOnChange(&mail_enabled, &mail_threshold, &mail_user);
if (mail_enabled)
- LOG_FATAL(LOGF_SysLinux, "mailonchange directive cannot be used with -F enabled");
+ LOG_FATAL("mailonchange directive cannot be used with -F enabled");
}
/* ================================================== */
@@ -467,9 +467,10 @@ SYS_Linux_EnableSystemCallFilter(int level)
SCMP_SYS(adjtimex), SCMP_SYS(clock_gettime), SCMP_SYS(gettimeofday),
SCMP_SYS(settimeofday), SCMP_SYS(time),
/* Process */
- SCMP_SYS(clone), SCMP_SYS(exit), SCMP_SYS(exit_group), SCMP_SYS(getrlimit),
- SCMP_SYS(rt_sigaction), SCMP_SYS(rt_sigreturn), SCMP_SYS(rt_sigprocmask),
- SCMP_SYS(set_tid_address), SCMP_SYS(sigreturn), SCMP_SYS(wait4),
+ SCMP_SYS(clone), SCMP_SYS(exit), SCMP_SYS(exit_group), SCMP_SYS(getpid),
+ SCMP_SYS(getrlimit), SCMP_SYS(rt_sigaction), SCMP_SYS(rt_sigreturn),
+ SCMP_SYS(rt_sigprocmask), SCMP_SYS(set_tid_address), SCMP_SYS(sigreturn),
+ SCMP_SYS(wait4),
/* Memory */
SCMP_SYS(brk), SCMP_SYS(madvise), SCMP_SYS(mmap), SCMP_SYS(mmap2),
SCMP_SYS(mprotect), SCMP_SYS(mremap), SCMP_SYS(munmap), SCMP_SYS(shmdt),
@@ -489,7 +490,7 @@ SYS_Linux_EnableSystemCallFilter(int level)
SCMP_SYS(poll), SCMP_SYS(read), SCMP_SYS(futex), SCMP_SYS(select),
SCMP_SYS(set_robust_list), SCMP_SYS(write),
/* Miscellaneous */
- SCMP_SYS(uname),
+ SCMP_SYS(getrandom), SCMP_SYS(sysinfo), SCMP_SYS(uname),
};
const int socket_domains[] = {
@@ -516,7 +517,10 @@ SYS_Linux_EnableSystemCallFilter(int level)
const static unsigned long ioctls[] = {
FIONREAD, TCGETS,
#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
- PTP_SYS_OFFSET,
+ PTP_EXTTS_REQUEST, PTP_SYS_OFFSET,
+#ifdef PTP_PIN_SETFUNC
+ PTP_PIN_SETFUNC,
+#endif
#ifdef PTP_SYS_OFFSET_PRECISE
PTP_SYS_OFFSET_PRECISE,
#endif
@@ -546,7 +550,7 @@ SYS_Linux_EnableSystemCallFilter(int level)
ctx = seccomp_init(level > 0 ? SCMP_ACT_KILL : SCMP_ACT_TRAP);
if (ctx == NULL)
- LOG_FATAL(LOGF_SysLinux, "Failed to initialize seccomp");
+ LOG_FATAL("Failed to initialize seccomp");
/* Add system calls that are always allowed */
for (i = 0; i < (sizeof (syscalls) / sizeof (*syscalls)); i++) {
@@ -587,14 +591,14 @@ SYS_Linux_EnableSystemCallFilter(int level)
}
if (seccomp_load(ctx) < 0)
- LOG_FATAL(LOGF_SysLinux, "Failed to load seccomp rules");
+ LOG_FATAL("Failed to load seccomp rules");
- LOG(LOGS_INFO, LOGF_SysLinux, "Loaded seccomp filter");
+ LOG(LOGS_INFO, "Loaded seccomp filter");
seccomp_release(ctx);
return;
add_failed:
- LOG_FATAL(LOGF_SysLinux, "Failed to add seccomp rules");
+ LOG_FATAL("Failed to add seccomp rules");
}
#endif
@@ -608,7 +612,7 @@ void SYS_Linux_SetScheduler(int SchedPriority)
struct sched_param sched;
if (SchedPriority < 1 || SchedPriority > 99) {
- LOG_FATAL(LOGF_SysLinux, "Bad scheduler priority: %d", SchedPriority);
+ LOG_FATAL("Bad scheduler priority: %d", SchedPriority);
} else {
sched.sched_priority = SchedPriority;
pmax = sched_get_priority_max(SCHED_FIFO);
@@ -620,10 +624,10 @@ void SYS_Linux_SetScheduler(int SchedPriority)
sched.sched_priority = pmin;
}
if ( sched_setscheduler(0, SCHED_FIFO, &sched) == -1 ) {
- LOG(LOGS_ERR, LOGF_SysLinux, "sched_setscheduler() failed");
+ LOG(LOGS_ERR, "sched_setscheduler() failed");
}
else {
- DEBUG_LOG(LOGF_SysLinux, "Enabled SCHED_FIFO with priority %d",
+ DEBUG_LOG("Enabled SCHED_FIFO with priority %d",
sched.sched_priority);
}
}
@@ -641,14 +645,14 @@ void SYS_Linux_MemLockAll(int LockAll)
rlim.rlim_max = RLIM_INFINITY;
rlim.rlim_cur = RLIM_INFINITY;
if (setrlimit(RLIMIT_MEMLOCK, &rlim) < 0) {
- LOG(LOGS_ERR, LOGF_SysLinux, "setrlimit() failed: not locking into RAM");
+ LOG(LOGS_ERR, "setrlimit() failed: not locking into RAM");
}
else {
if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0) {
- LOG(LOGS_ERR, LOGF_SysLinux, "mlockall() failed");
+ LOG(LOGS_ERR, "mlockall() failed");
}
else {
- DEBUG_LOG(LOGF_SysLinux, "Successfully locked into RAM");
+ DEBUG_LOG("Successfully locked into RAM");
}
}
}
@@ -688,7 +692,7 @@ get_phc_sample(int phc_fd, double precision, struct timespec *phc_ts,
sys_off.n_samples = PHC_READINGS;
if (ioctl(phc_fd, PTP_SYS_OFFSET, &sys_off)) {
- DEBUG_LOG(LOGF_SysLinux, "ioctl(%s) failed : %s", "PTP_SYS_OFFSET", strerror(errno));
+ DEBUG_LOG("ioctl(%s) failed : %s", "PTP_SYS_OFFSET", strerror(errno));
return 0;
}
@@ -704,9 +708,11 @@ get_phc_sample(int phc_fd, double precision, struct timespec *phc_ts,
phc_tss[i] = ts2;
delays[i] = UTI_DiffTimespecsToDouble(&ts3, &ts1);
- if (delays[i] <= 0.0)
+ if (delays[i] < 0.0) {
/* Step in the middle of a PHC reading? */
+ DEBUG_LOG("Bad PTP_SYS_OFFSET sample delay=%e", delays[i]);
return 0;
+ }
if (!i || delays[i] < min_delay)
min_delay = delays[i];
@@ -745,7 +751,7 @@ get_precise_phc_sample(int phc_fd, double precision, struct timespec *phc_ts,
memset(&sys_off, 0, sizeof (sys_off));
if (ioctl(phc_fd, PTP_SYS_OFFSET_PRECISE, &sys_off)) {
- DEBUG_LOG(LOGF_SysLinux, "ioctl(%s) failed : %s", "PTP_SYS_OFFSET_PRECISE",
+ DEBUG_LOG("ioctl(%s) failed : %s", "PTP_SYS_OFFSET_PRECISE",
strerror(errno));
return 0;
}
@@ -779,13 +785,13 @@ SYS_Linux_OpenPHC(const char *path, int phc_index)
phc_fd = open(path, O_RDONLY);
if (phc_fd < 0) {
- LOG(LOGS_ERR, LOGF_SysLinux, "Could not open %s : %s", path, strerror(errno));
+ LOG(LOGS_ERR, "Could not open %s : %s", path, strerror(errno));
return -1;
}
/* Make sure it is a PHC */
if (ioctl(phc_fd, PTP_CLOCK_GETCAPS, &caps)) {
- LOG(LOGS_ERR, LOGF_SysLinux, "ioctl(%s) failed : %s", "PTP_CLOCK_GETCAPS", strerror(errno));
+ LOG(LOGS_ERR, "ioctl(%s) failed : %s", "PTP_CLOCK_GETCAPS", strerror(errno));
close(phc_fd);
return -1;
}
@@ -813,4 +819,61 @@ SYS_Linux_GetPHCSample(int fd, int nocrossts, double precision, int *reading_mod
return 0;
}
+/* ================================================== */
+
+int
+SYS_Linux_SetPHCExtTimestamping(int fd, int pin, int channel,
+ int rising, int falling, int enable)
+{
+ struct ptp_extts_request extts_req;
+#ifdef PTP_PIN_SETFUNC
+ struct ptp_pin_desc pin_desc;
+
+ memset(&pin_desc, 0, sizeof (pin_desc));
+ pin_desc.index = pin;
+ pin_desc.func = enable ? PTP_PF_EXTTS : PTP_PF_NONE;
+ pin_desc.chan = channel;
+
+ if (ioctl(fd, PTP_PIN_SETFUNC, &pin_desc)) {
+ DEBUG_LOG("ioctl(%s) failed : %s", "PTP_PIN_SETFUNC", strerror(errno));
+ return 0;
+ }
+#else
+ DEBUG_LOG("Missing PTP_PIN_SETFUNC");
+ return 0;
+#endif
+
+ memset(&extts_req, 0, sizeof (extts_req));
+ extts_req.index = channel;
+ extts_req.flags = (enable ? PTP_ENABLE_FEATURE : 0) |
+ (rising ? PTP_RISING_EDGE : 0) |
+ (falling ? PTP_FALLING_EDGE : 0);
+
+ if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_req)) {
+ DEBUG_LOG("ioctl(%s) failed : %s", "PTP_EXTTS_REQUEST", strerror(errno));
+ return 0;
+ }
+
+ return 1;
+}
+
+/* ================================================== */
+
+int
+SYS_Linux_ReadPHCExtTimestamp(int fd, struct timespec *phc_ts, int *channel)
+{
+ struct ptp_extts_event extts_event;
+
+ if (read(fd, &extts_event, sizeof (extts_event)) != sizeof (extts_event)) {
+ DEBUG_LOG("Could not read PHC extts event");
+ return 0;
+ }
+
+ phc_ts->tv_sec = extts_event.t.sec;
+ phc_ts->tv_nsec = extts_event.t.nsec;
+ *channel = extts_event.index;
+
+ return 1;
+}
+
#endif
diff --git a/sys_linux.h b/sys_linux.h
index 4108401..dc1cee6 100644
--- a/sys_linux.h
+++ b/sys_linux.h
@@ -46,4 +46,9 @@ extern int SYS_Linux_OpenPHC(const char *path, int phc_index);
extern int SYS_Linux_GetPHCSample(int fd, int nocrossts, double precision, int *reading_mode,
struct timespec *phc_ts, struct timespec *sys_ts, double *err);
+extern int SYS_Linux_SetPHCExtTimestamping(int fd, int pin, int channel,
+ int rising, int falling, int enable);
+
+extern int SYS_Linux_ReadPHCExtTimestamp(int fd, struct timespec *phc_ts, int *channel);
+
#endif /* GOT_SYS_LINUX_H */
diff --git a/sys_macosx.c b/sys_macosx.c
index 35f03d6..00ce302 100644
--- a/sys_macosx.c
+++ b/sys_macosx.c
@@ -4,7 +4,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-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
* it under the terms of version 2 of the GNU General Public License as
@@ -46,6 +46,15 @@
#include "privops.h"
#include "util.h"
+#ifdef HAVE_MACOS_SYS_TIMEX
+#include <dlfcn.h>
+#include "sys_netbsd.h"
+#include "sys_timex.h"
+
+static int have_ntp_adjtime = 0;
+static int have_bad_adjtime = 0;
+#endif
+
/* ================================================== */
/* This register contains the number of seconds by which the local
@@ -116,7 +125,7 @@ clock_initialise(void)
newadj.tv_usec = 0;
if (PRV_AdjustTime(&newadj, &oldadj) < 0) {
- LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed");
+ LOG_FATAL("adjtime() failed");
}
}
@@ -154,10 +163,9 @@ start_adjust(void)
predicted_error = (current_drift_removal_interval - drift_removal_elapsed) / 2.0 * current_freq;
- DEBUG_LOG(LOGF_SysMacOSX, "drift_removal_elapsed: %.3f current_drift_removal_interval: %.3f predicted_error: %.3f",
- 1.0e6 * drift_removal_elapsed,
- 1.0e6 * current_drift_removal_interval,
- 1.0e6 * predicted_error);
+ DEBUG_LOG("drift_removal_elapsed: %.3f current_drift_removal_interval: %.3f predicted_error: %.3f",
+ 1.0e6 * drift_removal_elapsed, 1.0e6 * current_drift_removal_interval,
+ 1.0e6 * predicted_error);
adjust_required = - (accrued_error + offset_register + predicted_error);
@@ -166,7 +174,7 @@ start_adjust(void)
rounding_error = adjust_required - adjustment_requested;
if (PRV_AdjustTime(&newadj, &oldadj) < 0) {
- LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed");
+ LOG_FATAL("adjtime() failed");
}
old_adjust_remaining = UTI_TimevalToDouble(&oldadj);
@@ -190,7 +198,7 @@ stop_adjust(void)
zeroadj.tv_usec = 0;
if (PRV_AdjustTime(&zeroadj, &remadj) < 0) {
- LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed");
+ LOG_FATAL("adjtime() failed");
}
LCL_ReadRawTime(&T1);
@@ -239,7 +247,7 @@ apply_step_offset(double offset)
UTI_TimespecToTimeval(&new_time, &new_time_tv);
if (PRV_SetTime(&new_time_tv, NULL) < 0) {
- DEBUG_LOG(LOGF_SysMacOSX, "settimeofday() failed");
+ DEBUG_LOG("settimeofday() failed");
return 0;
}
@@ -338,14 +346,14 @@ set_sync_status(int synchronised, double est_error, double max_error)
/* update the RTC by applying a step of 0.0 secs */
apply_step_offset(0.0);
last_rtc_sync = now;
- DEBUG_LOG(LOGF_SysMacOSX, "rtc synchronised");
+ DEBUG_LOG("rtc synchronised");
}
}
interval = ERROR_WEIGHT * est_error / (fabs(current_freq) + FREQUENCY_RES);
drift_removal_interval = MAX(interval, DRIFT_REMOVAL_INTERVAL_MIN);
- DEBUG_LOG(LOGF_SysMacOSX, "est_error: %.3f current_freq: %.3f est drift_removal_interval: %.3f act drift_removal_interval: %.3f",
+ DEBUG_LOG("est_error: %.3f current_freq: %.3f est drift_removal_interval: %.3f act drift_removal_interval: %.3f",
est_error * 1.0e6, current_freq * 1.0e6, interval, drift_removal_interval);
}
@@ -389,7 +397,7 @@ set_realtime(void)
THREAD_TIME_CONSTRAINT_POLICY_COUNT);
if (kr != KERN_SUCCESS) {
- LOG(LOGS_WARN, LOGF_SysMacOSX, "Cannot set real-time priority: %d", kr);
+ LOG(LOGS_WARN, "Cannot set real-time priority: %d", kr);
return -1;
}
return 0;
@@ -418,8 +426,8 @@ void SYS_MacOSX_DropRoot(uid_t uid, gid_t gid)
/* ================================================== */
-void
-SYS_MacOSX_Initialise(void)
+static void
+legacy_MacOSX_Initialise(void)
{
clock_initialise();
@@ -435,8 +443,8 @@ SYS_MacOSX_Initialise(void)
/* ================================================== */
-void
-SYS_MacOSX_Finalise(void)
+static void
+legacy_MacOSX_Finalise(void)
{
SCH_RemoveTimeout(drift_removal_id);
@@ -445,4 +453,67 @@ SYS_MacOSX_Finalise(void)
/* ================================================== */
+#ifdef HAVE_MACOS_SYS_TIMEX
+/*
+ Test adjtime() to see if Apple have fixed the signed/unsigned bug
+*/
+static int
+test_adjtime()
+{
+ struct timeval tv1 = {-1, 0};
+ struct timeval tv2 = {0, 0};
+ struct timeval tv;
+
+ if (PRV_AdjustTime(&tv1, &tv) != 0) {
+ return 0;
+ }
+ if (PRV_AdjustTime(&tv2, &tv) != 0) {
+ return 0;
+ }
+ if (tv.tv_sec < -1 || tv.tv_sec > 1) {
+ return 0;
+ }
+ return 1;
+}
+#endif
+
+/* ================================================== */
+
+void
+SYS_MacOSX_Initialise(void)
+{
+#ifdef HAVE_MACOS_SYS_TIMEX
+ have_ntp_adjtime = (dlsym(RTLD_NEXT, "ntp_adjtime") != NULL);
+ if (have_ntp_adjtime) {
+ have_bad_adjtime = !test_adjtime();
+ if (have_bad_adjtime) {
+ LOG(LOGS_WARN, "adjtime() is buggy - using timex driver");
+ SYS_Timex_Initialise();
+ } else {
+ SYS_NetBSD_Initialise();
+ }
+ return;
+ }
+#endif
+ legacy_MacOSX_Initialise();
+}
+
+/* ================================================== */
+
+void
+SYS_MacOSX_Finalise(void)
+{
+#ifdef HAVE_MACOS_SYS_TIMEX
+ if (have_ntp_adjtime) {
+ if (have_bad_adjtime) {
+ SYS_Timex_Finalise();
+ } else {
+ SYS_NetBSD_Finalise();
+ }
+ return;
+ }
+#endif
+ legacy_MacOSX_Finalise();
+}
+
#endif
diff --git a/sys_netbsd.c b/sys_netbsd.c
index 74cadbc..840d6a5 100644
--- a/sys_netbsd.c
+++ b/sys_netbsd.c
@@ -65,14 +65,14 @@ accrue_offset(double offset, double corr_rate)
UTI_DoubleToTimeval(-offset, &newadj);
if (PRV_AdjustTime(&newadj, &oldadj) < 0)
- LOG_FATAL(LOGF_SysNetBSD, "adjtime() failed");
+ LOG_FATAL("adjtime() failed");
/* Add the old remaining adjustment if not zero */
doldadj = UTI_TimevalToDouble(&oldadj);
if (doldadj != 0.0) {
UTI_DoubleToTimeval(-offset + doldadj, &newadj);
if (PRV_AdjustTime(&newadj, NULL) < 0)
- LOG_FATAL(LOGF_SysNetBSD, "adjtime() failed");
+ LOG_FATAL("adjtime() failed");
}
}
@@ -84,9 +84,18 @@ get_offset_correction(struct timespec *raw,
{
struct timeval remadj;
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)
- LOG_FATAL(LOGF_SysNetBSD, "adjtime() failed");
+ LOG_FATAL("adjtime() failed");
+#endif
adjustment_remaining = UTI_TimevalToDouble(&remadj);
@@ -138,7 +147,7 @@ SYS_NetBSD_DropRoot(uid_t uid, gid_t gid)
/* Check if we have write access to /dev/clockctl */
fd = open("/dev/clockctl", O_WRONLY);
if (fd < 0)
- LOG_FATAL(LOGF_SysNetBSD, "Can't write to /dev/clockctl");
+ LOG_FATAL("Can't write to /dev/clockctl");
close(fd);
#endif
}
diff --git a/sys_null.c b/sys_null.c
new file mode 100644
index 0000000..3a0d5f6
--- /dev/null
+++ b/sys_null.c
@@ -0,0 +1,140 @@
+/*
+ chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar 2017
+ *
+ * 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.
+ *
+ **********************************************************************
+
+ =======================================================================
+
+ Null clock driver for operation with no clock control.
+ */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "sys_null.h"
+
+#include "local.h"
+#include "localp.h"
+#include "logging.h"
+#include "util.h"
+
+/* Current frequency offset of the system clock (in ppm) */
+static double freq;
+
+/* Offset of the system clock at the last update */
+static double offset_register;
+
+/* Time of the last update */
+static struct timespec last_update;
+
+/* Minimum interval between updates when frequency is constant */
+#define MIN_UPDATE_INTERVAL 1000.0
+
+/* ================================================== */
+
+static void
+update_offset(void)
+{
+ struct timespec now;
+ double duration;
+
+ LCL_ReadRawTime(&now);
+ duration = UTI_DiffTimespecsToDouble(&now, &last_update);
+ offset_register += 1.0e-6 * freq * duration;
+ last_update = now;
+
+ DEBUG_LOG("System clock offset=%e freq=%f", offset_register, freq);
+}
+
+/* ================================================== */
+
+static double
+read_frequency(void)
+{
+ return freq;
+}
+
+/* ================================================== */
+
+static double
+set_frequency(double freq_ppm)
+{
+ update_offset();
+ freq = freq_ppm;
+
+ return freq;
+}
+
+/* ================================================== */
+
+static void
+accrue_offset(double offset, double corr_rate)
+{
+ offset_register += offset;
+}
+
+/* ================================================== */
+
+static int
+apply_step_offset(double offset)
+{
+ return 0;
+}
+
+/* ================================================== */
+
+static void
+offset_convert(struct timespec *raw, double *corr, double *err)
+{
+ double duration;
+
+ duration = UTI_DiffTimespecsToDouble(raw, &last_update);
+
+ if (duration > MIN_UPDATE_INTERVAL) {
+ update_offset();
+ duration = 0.0;
+ }
+
+ *corr = -1.0e-6 * freq * duration - offset_register;
+
+ if (err)
+ *err = 0.0;
+}
+
+/* ================================================== */
+
+void
+SYS_Null_Initialise(void)
+{
+ offset_register = 0.0;
+ LCL_ReadRawTime(&last_update);
+
+ lcl_RegisterSystemDrivers(read_frequency, set_frequency, accrue_offset,
+ apply_step_offset, offset_convert, NULL, NULL);
+
+ LOG(LOGS_INFO, "Disabled control of system clock");
+}
+
+/* ================================================== */
+
+void
+SYS_Null_Finalise(void)
+{
+}
diff --git a/sys_null.h b/sys_null.h
new file mode 100644
index 0000000..0fbf077
--- /dev/null
+++ b/sys_null.h
@@ -0,0 +1,34 @@
+/*
+ chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar 2017
+ *
+ * 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.
+ *
+ **********************************************************************
+
+ =======================================================================
+
+ Header file for null clock driver
+ */
+
+#ifndef GOT_SYS_NULL_H
+#define GOT_SYS_NULL_H
+
+extern void SYS_Null_Initialise(void);
+
+extern void SYS_Null_Finalise(void);
+
+#endif
diff --git a/sys_timex.c b/sys_timex.c
index 4ec4ce8..e54ad24 100644
--- a/sys_timex.c
+++ b/sys_timex.c
@@ -3,7 +3,7 @@
**********************************************************************
* 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
* it under the terms of version 2 of the GNU General Public License as
@@ -61,7 +61,10 @@
#define MIN_TICK_RATE 100
/* Saved timex status */
-static int status;
+static int sys_status;
+
+/* Saved TAI-UTC offset */
+static int sys_tai_offset;
/* ================================================== */
@@ -95,33 +98,47 @@ set_frequency(double freq_ppm)
/* ================================================== */
static void
-set_leap(int leap)
+set_leap(int leap, int tai_offset)
{
struct timex txc;
- int applied;
+ int applied, prev_status;
- applied = 0;
- if (!leap) {
- txc.modes = 0;
- if (SYS_Timex_Adjust(&txc, 1) == TIME_WAIT)
- applied = 1;
- }
+ txc.modes = 0;
+ applied = SYS_Timex_Adjust(&txc, 0) == TIME_WAIT;
- status &= ~(STA_INS | STA_DEL);
+ prev_status = sys_status;
+ sys_status &= ~(STA_INS | STA_DEL);
if (leap > 0)
- status |= STA_INS;
+ sys_status |= STA_INS;
else if (leap < 0)
- status |= STA_DEL;
+ sys_status |= STA_DEL;
txc.modes = MOD_STATUS;
- txc.status = status;
+ txc.status = sys_status;
+
+#ifdef MOD_TAI
+ if (tai_offset) {
+ txc.modes |= MOD_TAI;
+ txc.constant = tai_offset;
+
+ if (applied && !(sys_status & (STA_INS | STA_DEL)))
+ sys_tai_offset += prev_status & STA_INS ? 1 : -1;
+
+ if (sys_tai_offset != tai_offset) {
+ sys_tai_offset = tai_offset;
+ LOG(LOGS_INFO, "System clock TAI offset set to %d seconds", tai_offset);
+ }
+ }
+#endif
SYS_Timex_Adjust(&txc, 0);
- LOG(LOGS_INFO, LOGF_SysTimex, "System clock status %s leap second",
- leap ? (leap > 0 ? "set to insert" : "set to delete") :
- (applied ? "reset after" : "set to not insert/delete"));
+ if (prev_status != sys_status) {
+ LOG(LOGS_INFO, "System clock status %s leap second",
+ leap ? (leap > 0 ? "set to insert" : "set to delete") :
+ (applied ? "reset after" : "set to not insert/delete"));
+ }
}
/* ================================================== */
@@ -149,12 +166,12 @@ set_sync_status(int synchronised, double est_error, double max_error)
#endif
if (synchronised)
- status &= ~STA_UNSYNC;
+ sys_status &= ~STA_UNSYNC;
else
- status |= STA_UNSYNC;
+ sys_status |= STA_UNSYNC;
txc.modes = MOD_STATUS | MOD_ESTERROR | MOD_MAXERROR;
- txc.status = status;
+ txc.status = sys_status;
txc.esterror = est_error * 1.0e6;
txc.maxerror = max_error * 1.0e6;
@@ -169,17 +186,18 @@ initialise_timex(void)
{
struct timex txc;
- status = STA_UNSYNC;
+ sys_status = STA_UNSYNC;
+ sys_tai_offset = 0;
/* Reset PLL offset */
txc.modes = MOD_OFFSET | MOD_STATUS;
- txc.status = STA_PLL | status;
+ txc.status = STA_PLL | sys_status;
txc.offset = 0;
SYS_Timex_Adjust(&txc, 0);
/* Turn PLL off */
txc.modes = MOD_STATUS;
- txc.status = status;
+ txc.status = sys_status;
SYS_Timex_Adjust(&txc, 0);
}
@@ -239,11 +257,9 @@ SYS_Timex_Adjust(struct timex *txc, int ignore_error)
if (state < 0) {
if (!ignore_error)
- LOG_FATAL(LOGF_SysTimex, NTP_ADJTIME_NAME"(0x%x) failed : %s",
- txc->modes, strerror(errno));
+ LOG_FATAL(NTP_ADJTIME_NAME"(0x%x) failed : %s", txc->modes, strerror(errno));
else
- DEBUG_LOG(LOGF_SysTimex, NTP_ADJTIME_NAME"(0x%x) failed : %s",
- txc->modes, strerror(errno));
+ DEBUG_LOG(NTP_ADJTIME_NAME"(0x%x) failed : %s", txc->modes, strerror(errno));
}
return state;
diff --git a/sysincl.h b/sysincl.h
index 1caf586..a9e4da0 100644
--- a/sysincl.h
+++ b/sysincl.h
@@ -59,7 +59,7 @@
#include <time.h>
#include <unistd.h>
-#if defined(LINUX) || defined(FREEBSD) || defined(NETBSD) || defined(SOLARIS)
+#if defined(LINUX) || defined(FREEBSD) || defined(NETBSD) || defined(SOLARIS) || defined(HAVE_MACOS_SYS_TIMEX)
#include <sys/timex.h>
#endif
@@ -76,4 +76,8 @@
#include <arpa/inet.h>
#endif
+#ifdef HAVE_GETRANDOM
+#include <sys/random.h>
+#endif
+
#endif /* GOT_SYSINCL_H */
diff --git a/tempcomp.c b/tempcomp.c
index 555fa24..f57e5cc 100644
--- a/tempcomp.c
+++ b/tempcomp.c
@@ -92,7 +92,7 @@ read_timeout(void *arg)
if (fabs(comp) <= MAX_COMP) {
comp = LCL_SetTempComp(comp);
- DEBUG_LOG(LOGF_TempComp, "tempcomp updated to %f for %f", comp, temp);
+ DEBUG_LOG("tempcomp updated to %f for %f", comp, temp);
if (logfileid != -1) {
struct timespec now;
@@ -102,13 +102,11 @@ read_timeout(void *arg)
UTI_TimeToLogForm(now.tv_sec), temp, comp);
}
} else {
- LOG(LOGS_WARN, LOGF_TempComp,
- "Temperature compensation of %.3f ppm exceeds sanity limit of %.1f",
+ LOG(LOGS_WARN, "Temperature compensation of %.3f ppm exceeds sanity limit of %.1f",
comp, MAX_COMP);
}
} else {
- LOG(LOGS_WARN, LOGF_TempComp, "Could not read temperature from %s",
- filename);
+ LOG(LOGS_WARN, "Could not read temperature from %s", filename);
}
if (f)
@@ -126,7 +124,7 @@ read_points(const char *filename)
f = fopen(filename, "r");
if (!f) {
- LOG_FATAL(LOGF_TempComp, "Could not open tempcomp point file %s", filename);
+ LOG_FATAL("Could not open tempcomp point file %s", filename);
return;
}
@@ -135,7 +133,7 @@ read_points(const char *filename)
while (fgets(line, sizeof (line), f)) {
p = (struct Point *)ARR_GetNewElement(points);
if (sscanf(line, "%lf %lf", &p->temp, &p->comp) != 2) {
- LOG_FATAL(LOGF_TempComp, "Could not read tempcomp point from %s", filename);
+ LOG_FATAL("Could not read tempcomp point from %s", filename);
break;
}
}
@@ -143,7 +141,7 @@ read_points(const char *filename)
fclose(f);
if (ARR_GetSize(points) < 2)
- LOG_FATAL(LOGF_TempComp, "Not enough points in %s", filename);
+ LOG_FATAL("Not enough points in %s", filename);
}
void
diff --git a/test/simulation/117-fallbackdrift b/test/simulation/117-fallbackdrift
index a651922..22270c9 100755
--- a/test/simulation/117-fallbackdrift
+++ b/test/simulation/117-fallbackdrift
@@ -11,10 +11,11 @@ freq_offset="(* 1e-4 (sine 1000))"
base_delay="(* -1.0 (equal 0.1 (min time 4250) 4250))"
client_server_options="minpoll 4 maxpoll 4"
client_conf="fallbackdrift 6 10"
+max_sync_time=4500
time_max_limit=1e0
time_rms_limit=1e0
-freq_max_limit=5e-4
-freq_rms_limit=5e-4
+freq_max_limit=2e-4
+freq_rms_limit=1e-4
run_test || test_fail
check_chronyd_exit || test_fail
diff --git a/test/simulation/118-maxdelay b/test/simulation/118-maxdelay
index 9872836..22b9a50 100755
--- a/test/simulation/118-maxdelay
+++ b/test/simulation/118-maxdelay
@@ -10,7 +10,7 @@ wander=0.0
freq_offset="(sum 1e-10)"
time_rms_limit=2e-4
-client_server_options="maxdelay 3e-5 maxdelayratio 2.0 maxdelaydevratio 2.0"
+client_server_options="maxpoll 6 maxdelay 3e-5 maxdelayratio 2.0 maxdelaydevratio 2.0"
run_test || test_fail
check_chronyd_exit || test_fail
@@ -18,7 +18,7 @@ check_source_selection || test_fail
check_packet_interval || test_fail
check_sync || test_fail
-for client_server_options in "maxdelay 2e-5" \ "maxdelayratio 1.001"; do
+for client_server_options in "maxpoll 6 maxdelay 2e-5"; do
run_test || test_fail
check_chronyd_exit || test_fail
check_packet_interval || test_fail
diff --git a/test/simulation/122-xleave b/test/simulation/122-xleave
index e0ce9ec..93f767e 100755
--- a/test/simulation/122-xleave
+++ b/test/simulation/122-xleave
@@ -17,6 +17,7 @@ max_sync_time=500
base_delay="(+ 1e-4 (* -1 (equal 0.1 from 2) (equal 0.1 to 1)))"
client_lpeer_options="xleave minpoll 5 maxpoll 5"
+client_rpeer_options="minpoll 5 maxpoll 5"
run_test || test_fail
check_chronyd_exit || test_fail
diff --git a/test/simulation/123-mindelay b/test/simulation/123-mindelay
new file mode 100755
index 0000000..cde214a
--- /dev/null
+++ b/test/simulation/123-mindelay
@@ -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
diff --git a/test/simulation/run b/test/simulation/run
index a177c83..463e8dd 100755
--- a/test/simulation/run
+++ b/test/simulation/run
@@ -1,24 +1,90 @@
#!/bin/bash
-passed=() failed=() skipped=()
+print_help() {
+ echo "$1 [-a] [-i ITERATIONS] [-m MAXFAILS] [-s SEED] [TEST]..."
+}
+
+run_test() {
+ local result name=$1 seed=$2
+
+ CLKNETSIM_RANDOM_SEED=$seed ./$name
+ result=$?
+
+ if [ $result -ne 0 -a $result -ne 9 ]; then
+ if [ $abort_on_fail -ne 0 ]; then
+ echo 1>&2
+ echo Failed with random seed $seed 1>&2
+ exit 1
+ fi
+ failed_seeds=(${failed_seeds[@]} $seed)
+ fi
+
+ return $result
+}
+
+abort_on_fail=0
+iterations=1
+max_fails=0
+random_seed=${CLKNETSIM_RANDOM_SEED:-$RANDOM}
+
+while getopts ":ai:m:s:" opt; do
+ case $opt in
+ a) abort_on_fail=1;;
+ i) iterations=$OPTARG;;
+ m) max_fails=$OPTARG;;
+ s) random_seed=$OPTARG;;
+ *) print_help "$0"; exit 3;;
+ esac
+done
+
+shift $[$OPTIND - 1]
+
+passed=() failed=() skipped=() failed_seeds=()
[ $# -gt 0 ] && tests=($@) || tests=([0-9]*-*[^_])
for test in "${tests[@]}"; do
- echo "$test ($[${#passed[@]} + ${#failed[@]} + 1]/${#tests[@]})"
- ./$test
- case $? in
+ if [ $iterations -gt 1 ]; then
+ printf "%-30s" "$test"
+ fails=0
+ for i in $(seq 1 $iterations); do
+ run_test $test $[$random_seed + $i - 1] > /dev/null
+ case $? in
+ 0) echo -n ".";;
+ 9) break;;
+ *) echo -n "x"; fails=$[$fails + 1];;
+ esac
+ done
+ if [ $i -lt $iterations ]; then
+ printf "%${iterations}s" ""
+ echo " SKIP"
+ result=9
+ elif [ $fails -gt $max_fails ]; then
+ echo " FAIL"
+ result=1
+ else
+ echo " PASS"
+ result=0
+ fi
+ else
+ printf "%s " "$test"
+ run_test $test $random_seed
+ result=$?
+ echo
+ fi
+
+ case $result in
0) passed=(${passed[@]} $test);;
9) skipped=(${skipped[@]} $test);;
*) failed=(${failed[@]} $test);;
esac
- echo
done
+echo
echo "SUMMARY:"
echo " TOTAL $[${#passed[@]} + ${#failed[@]} + ${#skipped[@]}]"
echo " PASSED ${#passed[@]}"
-echo " FAILED ${#failed[@]} (${failed[@]})"
+echo " FAILED ${#failed[@]} (${failed[@]}) (${failed_seeds[@]})"
echo " SKIPPED ${#skipped[@]} (${skipped[@]})"
[ ${#failed[@]} -eq 0 ]
diff --git a/test/unit/addrfilt.c b/test/unit/addrfilt.c
index 3a21671..b236073 100644
--- a/test/unit/addrfilt.c
+++ b/test/unit/addrfilt.c
@@ -42,7 +42,7 @@ test_unit(void)
TST_GetRandomAddress(&ip, IPADDR_INET6, -1);
}
- DEBUG_LOG(0, "address %s", UTI_IPToString(&ip));
+ DEBUG_LOG("address %s", UTI_IPToString(&ip));
sub = random() % (maxsub + 1);
diff --git a/test/unit/clientlog.c b/test/unit/clientlog.c
index ee29936..515ad1a 100644
--- a/test/unit/clientlog.c
+++ b/test/unit/clientlog.c
@@ -33,7 +33,7 @@ test_unit(void)
"cmdratelimit interval 3 burst 4 leak 3",
};
- CNF_Initialise(0);
+ CNF_Initialise(0, 0);
for (i = 0; i < sizeof conf / sizeof conf[0]; i++)
CNF_ParseLine(NULL, i + 1, conf[i]);
@@ -42,14 +42,14 @@ test_unit(void)
TEST_CHECK(ARR_GetSize(records) == 16);
for (i = 0; i < 500; i++) {
- DEBUG_LOG(0, "iteration %d", i);
+ DEBUG_LOG("iteration %d", i);
ts.tv_sec = (time_t)random() & 0x0fffffff;
ts.tv_nsec = 0;
for (j = 0; j < 1000; j++) {
TST_GetRandomAddress(&ip, IPADDR_UNSPEC, i % 8 ? -1 : i / 8 % 9);
- DEBUG_LOG(0, "address %s", UTI_IPToString(&ip));
+ DEBUG_LOG("address %s", UTI_IPToString(&ip));
if (random() % 2) {
index = CLG_LogNTPAccess(&ip, &ts);
@@ -65,7 +65,7 @@ test_unit(void)
}
}
- DEBUG_LOG(0, "records %d", ARR_GetSize(records));
+ DEBUG_LOG("records %d", ARR_GetSize(records));
TEST_CHECK(ARR_GetSize(records) == 64);
for (i = j = 0; i < 10000; i++) {
@@ -76,7 +76,7 @@ test_unit(void)
j++;
}
- DEBUG_LOG(0, "requests %u responses %u", i, j);
+ DEBUG_LOG("requests %u responses %u", i, j);
TEST_CHECK(j * 4 < i && j * 6 > i);
CLG_Finalise();
diff --git a/test/unit/hwclock.c b/test/unit/hwclock.c
index 5b2406a..804e600 100644
--- a/test/unit/hwclock.c
+++ b/test/unit/hwclock.c
@@ -26,20 +26,20 @@ test_unit(void)
{
struct timespec start_hw_ts, start_local_ts, hw_ts, local_ts, ts;
HCL_Instance clock;
- double freq, jitter, interval, d;
- int i, j;
+ double freq, jitter, interval, dj, sum;
+ int i, j, count;
LCL_Initialise();
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_local_ts);
UTI_AddDoubleToTimespec(&start_hw_ts, TST_GetRandomDouble(0.0, 1e9), &start_hw_ts);
UTI_AddDoubleToTimespec(&start_local_ts, TST_GetRandomDouble(0.0, 1e9), &start_local_ts);
- DEBUG_LOG(0, "iteration %d", i);
+ DEBUG_LOG("iteration %d", i);
freq = TST_GetRandomDouble(0.9, 1.1);
jitter = TST_GetRandomDouble(10.0e-9, 1000.0e-9);
@@ -49,17 +49,23 @@ test_unit(void)
clock->valid_coefs = 0;
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);
if (HCL_CookTime(clock, &hw_ts, &ts, NULL)) {
- d = UTI_DiffTimespecsToDouble(&ts, &local_ts);
- TEST_CHECK(fabs(d) <= 5.0 * jitter);
+ dj = fabs(UTI_DiffTimespecsToDouble(&ts, &local_ts) / 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))
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)
continue;
@@ -68,6 +74,8 @@ test_unit(void)
}
}
+ TEST_CHECK(sum / count < 0.4);
+
HCL_DestroyInstance(clock);
LCL_Finalise();
diff --git a/test/unit/keys.c b/test/unit/keys.c
index 9743b03..ac995fa 100644
--- a/test/unit/keys.c
+++ b/test/unit/keys.c
@@ -90,7 +90,7 @@ test_unit(void)
"keyfile "KEYFILE
};
- CNF_Initialise(0);
+ CNF_Initialise(0, 0);
for (i = 0; i < sizeof conf / sizeof conf[0]; i++)
CNF_ParseLine(NULL, i + 1, conf[i]);
@@ -98,7 +98,7 @@ test_unit(void)
KEY_Initialise();
for (i = 0; i < 100; i++) {
- DEBUG_LOG(0, "iteration %d", i);
+ DEBUG_LOG("iteration %d", i);
if (i) {
generate_key_file(KEYFILE, keys);
@@ -134,8 +134,8 @@ test_unit(void)
UTI_GetRandomBytes(&key, sizeof (key));
if (KEY_KeyKnown(key))
continue;
- TEST_CHECK(!KEY_GenerateAuth(j, data, data_len, auth, sizeof (auth)));
- TEST_CHECK(!KEY_CheckAuth(j, data, data_len, auth, auth_len, auth_len));
+ TEST_CHECK(!KEY_GenerateAuth(key, data, data_len, auth, sizeof (auth)));
+ TEST_CHECK(!KEY_CheckAuth(key, data, data_len, auth, auth_len, auth_len));
}
}
diff --git a/test/unit/ntp_core.c b/test/unit/ntp_core.c
index 40ca03b..b227017 100644
--- a/test/unit/ntp_core.c
+++ b/test/unit/ntp_core.c
@@ -218,7 +218,7 @@ test_unit(void)
CPS_NTP_Source source;
NTP_Remote_Address remote_addr;
- CNF_Initialise(0);
+ CNF_Initialise(0, 0);
for (i = 0; i < sizeof conf / sizeof conf[0]; i++)
CNF_ParseLine(NULL, i + 1, conf[i]);
@@ -249,9 +249,10 @@ test_unit(void)
has_updated = 0;
for (j = 0; j < 50; j++) {
- DEBUG_LOG(0, "iteration %d, %d", i, j);
+ DEBUG_LOG("iteration %d, %d", i, j);
- interleaved = random() % 2;
+ interleaved = random() % 2 && (inst->mode != MODE_CLIENT ||
+ inst->tx_count < MAX_CLIENT_INTERLEAVED_TX);
authenticated = random() % 2;
valid = (!interleaved || (source.params.interleaved && has_updated)) &&
(!source.params.authkey || authenticated);
diff --git a/test/unit/ntp_sources.c b/test/unit/ntp_sources.c
index f55612d..ea8f19c 100644
--- a/test/unit/ntp_sources.c
+++ b/test/unit/ntp_sources.c
@@ -34,7 +34,7 @@ test_unit(void)
memset(&params, 0, sizeof (params));
- CNF_Initialise(0);
+ CNF_Initialise(0, 0);
CNF_ParseLine(NULL, 1, conf);
LCL_Initialise();
@@ -47,7 +47,7 @@ test_unit(void)
for (i = 0; i < 6; i++) {
TEST_CHECK(ARR_GetSize(records) == 1);
- DEBUG_LOG(0, "collision mod %u", 1U << i);
+ DEBUG_LOG("collision mod %u", 1U << i);
for (j = 0; j < sizeof (addrs) / sizeof (addrs[0]); j++) {
do {
@@ -59,7 +59,7 @@ test_unit(void)
if (!j)
hash = UTI_IPToHash(&addrs[j].ip_addr);
- DEBUG_LOG(0, "adding source %s hash %"PRIu32, UTI_IPToString(&addrs[j].ip_addr),
+ DEBUG_LOG("adding source %s hash %"PRIu32, UTI_IPToString(&addrs[j].ip_addr),
UTI_IPToHash(&addrs[j].ip_addr) % (1U << i));
NSR_AddSource(&addrs[j], random() % 2 ? NTP_SERVER : NTP_PEER, &params);
@@ -79,7 +79,7 @@ test_unit(void)
}
for (j = 0; j < sizeof (addrs) / sizeof (addrs[0]); j++) {
- DEBUG_LOG(0, "removing source %s", UTI_IPToString(&addrs[j].ip_addr));
+ DEBUG_LOG("removing source %s", UTI_IPToString(&addrs[j].ip_addr));
NSR_RemoveSource(&addrs[j]);
for (k = 0; k < sizeof (addrs) / sizeof (addrs[0]); k++) {
diff --git a/test/unit/regress.c b/test/unit/regress.c
new file mode 100644
index 0000000..f47d1c4
--- /dev/null
+++ b/test/unit/regress.c
@@ -0,0 +1,119 @@
+/*
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar 2017
+ *
+ * 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 <regress.c>
+#include "test.h"
+
+#define POINTS 64
+
+void
+test_unit(void)
+{
+ double x[POINTS], x2[POINTS], y[POINTS], w[POINTS];
+ double b0, b1, b2, s2, sb0, sb1, slope, slope2, intercept, sd, median;
+ double xrange, yrange, wrange, x2range;
+ int i, j, n, m, c1, c2, c3, runs, best_start, dof;
+
+ for (n = 3; n <= POINTS; n++) {
+ for (i = 0; i < 200; i++) {
+ slope = TST_GetRandomDouble(-0.1, 0.1);
+ intercept = TST_GetRandomDouble(-1.0, 1.0);
+ sd = TST_GetRandomDouble(1e-6, 1e-4);
+ slope2 = (random() % 2 ? 1 : -1) * TST_GetRandomDouble(0.1, 0.5);
+
+ DEBUG_LOG("iteration %d n=%d intercept=%e slope=%e sd=%e",
+ i, n, intercept, slope, sd);
+
+ for (j = 0; j < n; j++) {
+ x[j] = -j;
+ y[j] = intercept + slope * x[j] + (j % 2 ? 1 : -1) * TST_GetRandomDouble(1e-6, sd);
+ w[j] = TST_GetRandomDouble(1.0, 2.0);
+ x2[j] = (y[j] - intercept - slope * x[j]) / slope2;
+ }
+
+ RGR_WeightedRegression(x, y, w, n, &b0, &b1, &s2, &sb0, &sb1);
+ DEBUG_LOG("WR b0=%e b1=%e s2=%e sb0=%e sb1=%e", b0, b1, s2, sb0, sb1);
+ TEST_CHECK(fabs(b0 - intercept) < sd + 1e-3);
+ TEST_CHECK(fabs(b1 - slope) < sd);
+
+ if (RGR_FindBestRegression(x, y, w, n, 0, 3, &b0, &b1, &s2, &sb0, &sb1,
+ &best_start, &runs, &dof)) {
+ DEBUG_LOG("BR b0=%e b1=%e s2=%e sb0=%e sb1=%e runs=%d bs=%d dof=%d",
+ b0, b1, s2, sb0, sb1, runs, best_start, dof);
+
+ TEST_CHECK(fabs(b0 - intercept) < sd + 1e-3);
+ TEST_CHECK(fabs(b1 - slope) < sd);
+ }
+
+ if (RGR_MultipleRegress(x, x2, y, n, &b2)) {
+ DEBUG_LOG("MR b2=%e", b2);
+ TEST_CHECK(fabs(b2 - slope2) < 1e-6);
+ }
+
+ for (j = 0; j < n / 7; j++)
+ y[random() % n] += 100 * sd;
+
+ if (RGR_FindBestRobustRegression(x, y, n, 1e-8, &b0, &b1, &runs, &best_start)) {
+ DEBUG_LOG("BRR b0=%e b1=%e runs=%d bs=%d", b0, b1, runs, best_start);
+
+ TEST_CHECK(fabs(b0 - intercept) < sd + 1e-2);
+ TEST_CHECK(fabs(b1 - slope) < 5.0 * sd);
+ }
+
+ for (j = 0; j < n; j++)
+ x[j] = random() % 4 * TST_GetRandomDouble(-1000, 1000);
+
+ median = RGR_FindMedian(x, n);
+
+ for (j = c1 = c2 = c3 = 0; j < n; j++) {
+ if (x[j] < median)
+ c1++;
+ if (x[j] > median)
+ c3++;
+ else
+ c2++;
+ }
+
+ TEST_CHECK(c1 + c2 >= c3 && c1 <= c2 + c3);
+
+ xrange = TST_GetRandomDouble(1e-6, pow(10.0, random() % 10));
+ yrange = random() % 3 * TST_GetRandomDouble(0.0, pow(10.0, random() % 10));
+ wrange = random() % 3 * TST_GetRandomDouble(0.0, pow(10.0, random() % 10));
+ x2range = random() % 3 * TST_GetRandomDouble(0.0, pow(10.0, random() % 10));
+ m = random() % n;
+
+ for (j = 0; j < n; j++) {
+ x[j] = (j ? x[j - 1] : 0.0) + TST_GetRandomDouble(1e-6, xrange);
+ y[j] = TST_GetRandomDouble(-yrange, yrange);
+ w[j] = 1.0 + TST_GetRandomDouble(0.0, wrange);
+ x2[j] = TST_GetRandomDouble(-x2range, x2range);
+ }
+
+ RGR_WeightedRegression(x, y, w, n, &b0, &b1, &s2, &sb0, &sb1);
+
+ if (RGR_FindBestRegression(x + m, y + m, w, n - m, m, 3, &b0, &b1, &s2, &sb0, &sb1,
+ &best_start, &runs, &dof))
+ ;
+ if (RGR_MultipleRegress(x, x2, y, n, &b2))
+ ;
+ if (RGR_FindBestRobustRegression(x, y, n, 1e-8, &b0, &b1, &runs, &best_start))
+ ;
+ }
+ }
+}
diff --git a/test/unit/smooth.c b/test/unit/smooth.c
index 0cc6a40..998a4d1 100644
--- a/test/unit/smooth.c
+++ b/test/unit/smooth.c
@@ -29,7 +29,7 @@ test_unit(void)
double offset, freq, wander;
char conf[] = "smoothtime 300 0.01";
- CNF_Initialise(0);
+ CNF_Initialise(0, 0);
CNF_ParseLine(NULL, 1, conf);
LCL_Initialise();
@@ -40,7 +40,7 @@ test_unit(void)
UTI_ZeroTimespec(&ts);
SMT_Reset(&ts);
- DEBUG_LOG(0, "iteration %d", i);
+ DEBUG_LOG("iteration %d", i);
offset = (random() % 1000000 - 500000) / 1.0e6;
freq = (random() % 1000000 - 500000) / 1.0e9;
diff --git a/test/unit/sources.c b/test/unit/sources.c
index 08ee20c..341e22e 100644
--- a/test/unit/sources.c
+++ b/test/unit/sources.c
@@ -31,7 +31,7 @@ test_unit(void)
double offset, delay, disp;
struct timespec ts;
- CNF_Initialise(0);
+ CNF_Initialise(0, 0);
LCL_Initialise();
TST_RegisterDummyDrivers();
SCH_Initialise();
@@ -41,7 +41,7 @@ test_unit(void)
REF_SetMode(REF_ModeIgnore);
for (i = 0; i < 1000; i++) {
- DEBUG_LOG(0, "iteration %d", i);
+ DEBUG_LOG("iteration %d", i);
for (j = 0; j < sizeof (srcs) / sizeof (srcs[0]); j++) {
TEST_CHECK(n_sources == j);
@@ -51,9 +51,10 @@ test_unit(void)
sel_options = i & random() & (SRC_SELECT_NOSELECT | SRC_SELECT_PREFER |
SRC_SELECT_TRUST | SRC_SELECT_REQUIRE);
- DEBUG_LOG(0, "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,
- SRC_DEFAULT_MINSAMPLES, SRC_DEFAULT_MAXSAMPLES);
+ SRC_DEFAULT_MINSAMPLES, SRC_DEFAULT_MAXSAMPLES,
+ 0.0, 1.0);
SRC_UpdateReachability(srcs[j], 1);
samples = (i + j) % 5 + 3;
@@ -68,7 +69,7 @@ test_unit(void)
delay = TST_GetRandomDouble(1.0e-6, 1.0e-1);
disp = TST_GetRandomDouble(1.0e-6, 1.0e-1);
- DEBUG_LOG(0, "source %d sample %d offset %f delay %f disp %f", j, k,
+ DEBUG_LOG("source %d sample %d offset %f delay %f disp %f", j, k,
offset, delay, disp);
SRC_AccumulateSample(srcs[j], &ts, offset, delay, disp, delay, disp,
@@ -81,7 +82,7 @@ test_unit(void)
double passed_lo = DBL_MAX, passed_hi = DBL_MIN;
SRC_SelectSource(srcs[k]);
- DEBUG_LOG(0, "source %d status %d", k, sources[k]->status);
+ DEBUG_LOG("source %d status %d", k, sources[k]->status);
for (l = 0; l <= j; l++) {
TEST_CHECK(sources[l]->status > SRC_OK && sources[l]->status <= SRC_SELECTED);
@@ -114,7 +115,7 @@ test_unit(void)
}
}
- DEBUG_LOG(0, "sources %d passed %d trusted %d/%d required %d/%d", j, passed,
+ DEBUG_LOG("sources %d passed %d trusted %d/%d required %d/%d", j, passed,
trusted_passed, trusted, required_passed, required);
TEST_CHECK(!trusted || !passed || (passed_lo >= trusted_lo && passed_hi <= trusted_hi));
diff --git a/test/unit/test.c b/test/unit/test.c
index 29f23ac..67f7678 100644
--- a/test/unit/test.c
+++ b/test/unit/test.c
@@ -64,8 +64,12 @@ main(int argc, char **argv)
printf("Testing %-30s ", test_name);
fflush(stdout);
+ LOG_Initialise();
+
test_unit();
+ LOG_Finalise();
+
printf("PASS\n");
return 0;
diff --git a/test/unit/util.c b/test/unit/util.c
index 5cd9bad..17f0c28 100644
--- a/test/unit/util.c
+++ b/test/unit/util.c
@@ -4,10 +4,11 @@
void test_unit(void) {
NTP_int64 ntp_ts, ntp_fuzz;
struct timespec ts, ts2;
+ struct sockaddr_un sun;
double x, y;
Float f;
int i, j, c;
- char buf[16];
+ char buf[16], *s;
for (i = -31; i < 31; i++) {
x = pow(2.0, i);
@@ -42,6 +43,10 @@ void test_unit(void) {
ntp_ts.hi = htonl(JAN_1970);
ntp_ts.lo = 0xffffffff;
UTI_Ntp64ToTimespec(&ntp_ts, &ts);
+ TEST_CHECK(ts.tv_sec == 0);
+ TEST_CHECK(ts.tv_nsec == 999999999);
+
+ UTI_AddDoubleToTimespec(&ts, 1e-9, &ts);
TEST_CHECK(ts.tv_sec == 1);
TEST_CHECK(ts.tv_nsec == 0);
@@ -145,4 +150,18 @@ void test_unit(void) {
c++;
}
TEST_CHECK(c > 46000 && c < 48000);
+
+ for (i = 1; i < 2 * BUFFER_LENGTH; i++) {
+ sun.sun_family = AF_UNIX;
+ for (j = 0; j + 1 < i && j + 1 < sizeof (sun.sun_path); j++)
+ sun.sun_path[j] = 'A' + j % 26;
+ sun.sun_path[j] = '\0';
+ s = UTI_SockaddrToString((struct sockaddr *)&sun);
+ if (i <= BUFFER_LENGTH) {
+ TEST_CHECK(!strcmp(s, sun.sun_path));
+ } else {
+ TEST_CHECK(!strncmp(s, sun.sun_path, BUFFER_LENGTH - 2));
+ TEST_CHECK(s[BUFFER_LENGTH - 2] == '>');
+ }
+ }
}
diff --git a/util.c b/util.c
index a9355ca..635a090 100644
--- a/util.c
+++ b/util.c
@@ -3,7 +3,7 @@
**********************************************************************
* 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
* it under the terms of version 2 of the GNU General Public License as
@@ -180,7 +180,7 @@ UTI_DiffTimespecs(struct timespec *result, struct timespec *a, struct timespec *
double
UTI_DiffTimespecsToDouble(struct timespec *a, struct timespec *b)
{
- return (a->tv_sec - b->tv_sec) + 1.0e-9 * (a->tv_nsec - b->tv_nsec);
+ return ((double)a->tv_sec - (double)b->tv_sec) + 1.0e-9 * (a->tv_nsec - b->tv_nsec);
}
/* ================================================== */
@@ -558,7 +558,7 @@ char *UTI_SockaddrToString(struct sockaddr *sa)
{
unsigned short port;
IPAddr ip;
- char *result;
+ char *result, *sun_path;
result = NEXT_BUFFER;
@@ -571,7 +571,11 @@ char *UTI_SockaddrToString(struct sockaddr *sa)
snprintf(result, BUFFER_LENGTH, "%s:%hu", UTI_IPToString(&ip), port);
break;
case AF_UNIX:
- snprintf(result, BUFFER_LENGTH, "%s", ((struct sockaddr_un *)sa)->sun_path);
+ sun_path = ((struct sockaddr_un *)sa)->sun_path;
+ snprintf(result, BUFFER_LENGTH, "%.*s", BUFFER_LENGTH - 1, sun_path);
+ /* Indicate truncated path */
+ if (strlen(sun_path) >= BUFFER_LENGTH)
+ result[BUFFER_LENGTH - 2] = '>';
break;
default:
snprintf(result, BUFFER_LENGTH, "[UNKNOWN]");
@@ -606,13 +610,17 @@ UTI_SockaddrFamilyToString(int family)
char *
UTI_TimeToLogForm(time_t t)
{
- struct tm stm;
+ struct tm *stm;
char *result;
result = NEXT_BUFFER;
- stm = *gmtime(&t);
- strftime(result, BUFFER_LENGTH, "%Y-%m-%d %H:%M:%S", &stm);
+ stm = gmtime(&t);
+
+ if (stm)
+ strftime(result, BUFFER_LENGTH, "%Y-%m-%d %H:%M:%S", stm);
+ else
+ snprintf(result, BUFFER_LENGTH, "INVALID INVALID ");
return result;
}
@@ -637,6 +645,7 @@ UTI_GetNtp64Fuzz(NTP_int64 *ts, int precision)
int start, bits;
assert(precision >= -32 && precision <= 32);
+ assert(sizeof (*ts) == 8);
start = sizeof (*ts) - (precision + 32 + 7) / 8;
ts->hi = ts->lo = 0;
@@ -774,9 +783,7 @@ UTI_Ntp64ToTimespec(NTP_int64 *src, struct timespec *dest)
dest->tv_sec = ntp_sec - JAN_1970;
#endif
- dest->tv_nsec = ntp_frac / NSEC_PER_NTP64 + 0.5;
-
- UTI_NormaliseTimespec(dest);
+ dest->tv_nsec = ntp_frac / NSEC_PER_NTP64;
}
/* ================================================== */
@@ -836,12 +843,11 @@ UTI_Log2ToDouble(int l)
void
UTI_TimespecNetworkToHost(Timespec *src, struct timespec *dest)
{
- uint32_t sec_low;
+ uint32_t sec_low, nsec;
#ifdef HAVE_LONG_TIME_T
uint32_t sec_high;
#endif
- dest->tv_nsec = ntohl(src->tv_nsec);
sec_low = ntohl(src->tv_sec_low);
#ifdef HAVE_LONG_TIME_T
sec_high = ntohl(src->tv_sec_high);
@@ -853,7 +859,8 @@ UTI_TimespecNetworkToHost(Timespec *src, struct timespec *dest)
dest->tv_sec = sec_low;
#endif
- UTI_NormaliseTimespec(dest);
+ nsec = ntohl(src->tv_nsec);
+ dest->tv_nsec = MIN(nsec, 999999999U);
}
/* ================================================== */
@@ -1038,25 +1045,25 @@ create_dir(char *p, mode_t mode, uid_t uid, gid_t gid)
if (status < 0) {
if (errno != ENOENT) {
- LOG(LOGS_ERR, LOGF_Util, "Could not access %s : %s", p, strerror(errno));
+ LOG(LOGS_ERR, "Could not access %s : %s", p, strerror(errno));
return 0;
}
} else {
if (S_ISDIR(buf.st_mode))
return 1;
- LOG(LOGS_ERR, LOGF_Util, "%s is not directory", p);
+ LOG(LOGS_ERR, "%s is not directory", p);
return 0;
}
/* Create the directory */
if (mkdir(p, mode) < 0) {
- LOG(LOGS_ERR, LOGF_Util, "Could not create directory %s : %s", p, strerror(errno));
+ LOG(LOGS_ERR, "Could not create directory %s : %s", p, strerror(errno));
return 0;
}
/* Set its owner */
if (chown(p, uid, gid) < 0) {
- LOG(LOGS_ERR, LOGF_Util, "Could not change ownership of %s : %s", p, strerror(errno));
+ LOG(LOGS_ERR, "Could not change ownership of %s : %s", p, strerror(errno));
/* Don't leave it there with incorrect ownership */
rmdir(p);
return 0;
@@ -1125,27 +1132,27 @@ UTI_CheckDirPermissions(const char *path, mode_t perm, uid_t uid, gid_t gid)
struct stat buf;
if (stat(path, &buf)) {
- LOG(LOGS_ERR, LOGF_Util, "Could not access %s : %s", path, strerror(errno));
+ LOG(LOGS_ERR, "Could not access %s : %s", path, strerror(errno));
return 0;
}
if (!S_ISDIR(buf.st_mode)) {
- LOG(LOGS_ERR, LOGF_Util, "%s is not directory", path);
+ LOG(LOGS_ERR, "%s is not directory", path);
return 0;
}
if ((buf.st_mode & 0777) & ~perm) {
- LOG(LOGS_ERR, LOGF_Util, "Wrong permissions on %s", path);
+ LOG(LOGS_ERR, "Wrong permissions on %s", path);
return 0;
}
if (buf.st_uid != uid) {
- LOG(LOGS_ERR, LOGF_Util, "Wrong owner of %s (%s != %d)", path, "UID", uid);
+ LOG(LOGS_ERR, "Wrong owner of %s (%s != %d)", path, "UID", uid);
return 0;
}
if (buf.st_gid != gid) {
- LOG(LOGS_ERR, LOGF_Util, "Wrong owner of %s (%s != %d)", path, "GID", gid);
+ LOG(LOGS_ERR, "Wrong owner of %s (%s != %d)", path, "GID", gid);
return 0;
}
@@ -1159,17 +1166,17 @@ UTI_DropRoot(uid_t uid, gid_t gid)
{
/* Drop supplementary groups */
if (setgroups(0, NULL))
- LOG_FATAL(LOGF_Util, "setgroups() failed : %s", strerror(errno));
+ LOG_FATAL("setgroups() failed : %s", strerror(errno));
/* Set effective, saved and real group ID */
if (setgid(gid))
- LOG_FATAL(LOGF_Util, "setgid(%d) failed : %s", gid, strerror(errno));
+ LOG_FATAL("setgid(%d) failed : %s", gid, strerror(errno));
/* Set effective, saved and real user ID */
if (setuid(uid))
- LOG_FATAL(LOGF_Util, "setuid(%d) failed : %s", uid, strerror(errno));
+ LOG_FATAL("setuid(%d) failed : %s", uid, strerror(errno));
- DEBUG_LOG(LOGF_Util, "Dropped root privileges: UID %d GID %d", uid, gid);
+ DEBUG_LOG("Dropped root privileges: UID %d GID %d", uid, gid);
}
/* ================================================== */
@@ -1184,18 +1191,51 @@ UTI_GetRandomBytesUrandom(void *buf, unsigned int len)
if (!f)
f = fopen(DEV_URANDOM, "r");
if (!f)
- LOG_FATAL(LOGF_Util, "Can't open %s : %s", DEV_URANDOM, strerror(errno));
+ LOG_FATAL("Can't open %s : %s", DEV_URANDOM, strerror(errno));
if (fread(buf, 1, len, f) != len)
- LOG_FATAL(LOGF_Util, "Can't read from %s", DEV_URANDOM);
+ LOG_FATAL("Can't read from %s", DEV_URANDOM);
}
/* ================================================== */
+#ifdef HAVE_GETRANDOM
+static void
+get_random_bytes_getrandom(char *buf, unsigned int len)
+{
+ static char rand_buf[256];
+ static unsigned int available = 0, disabled = 0;
+ unsigned int i;
+
+ for (i = 0; i < len; i++) {
+ if (!available) {
+ if (disabled)
+ break;
+
+ if (getrandom(rand_buf, sizeof (rand_buf), 0) != sizeof (rand_buf)) {
+ disabled = 1;
+ break;
+ }
+
+ available = sizeof (rand_buf);
+ }
+
+ buf[i] = rand_buf[--available];
+ }
+
+ if (i < len)
+ UTI_GetRandomBytesUrandom(buf, len);
+}
+#endif
+
+/* ================================================== */
+
void
UTI_GetRandomBytes(void *buf, unsigned int len)
{
#ifdef HAVE_ARC4RANDOM
arc4random_buf(buf, len);
+#elif defined(HAVE_GETRANDOM)
+ get_random_bytes_getrandom(buf, len);
#else
UTI_GetRandomBytesUrandom(buf, len);
#endif
diff --git a/version.txt b/version.txt
index 8c50098..a3ec5a4 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-3.1
+3.2