mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-03 19:25:07 -05:00
Compare commits
176 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
554b9b06de | ||
|
|
f734bd1a7c | ||
|
|
77fc5c42b9 | ||
|
|
ea85bc43e0 | ||
|
|
e8fb11c433 | ||
|
|
01a29c7a11 | ||
|
|
6ec3dc1650 | ||
|
|
0c54cf316d | ||
|
|
bd3fb49a1e | ||
|
|
f6e72a80e1 | ||
|
|
c2ab1426e5 | ||
|
|
fa2c59d78d | ||
|
|
16afa8eb50 | ||
|
|
992590e99c | ||
|
|
0baa35eade | ||
|
|
2e0870ee0c | ||
|
|
43cd119d6d | ||
|
|
62cd319a51 | ||
|
|
d0f789425b | ||
|
|
30e6549692 | ||
|
|
043c7d7c9f | ||
|
|
1c277a8850 | ||
|
|
ccb94ac5fb | ||
|
|
778fce4039 | ||
|
|
9983185d6d | ||
|
|
7bd1c02781 | ||
|
|
760285218f | ||
|
|
4fe0e6b7fd | ||
|
|
0773a1e630 | ||
|
|
4a24368763 | ||
|
|
577290c5bc | ||
|
|
854ff69f78 | ||
|
|
29b0ad894c | ||
|
|
cde0a20307 | ||
|
|
a768578a26 | ||
|
|
5d838729ef | ||
|
|
d6b763dc24 | ||
|
|
95adb52a45 | ||
|
|
707d9a3484 | ||
|
|
1872d4d195 | ||
|
|
17f32c266e | ||
|
|
6207655ab2 | ||
|
|
5e1e31ad5f | ||
|
|
13111c1dd8 | ||
|
|
85c84073c1 | ||
|
|
c2944d8727 | ||
|
|
e118b9b1e8 | ||
|
|
7fb7f95979 | ||
|
|
cc507bffae | ||
|
|
0dbfe020ad | ||
|
|
018a1c42b0 | ||
|
|
c5735ebfe9 | ||
|
|
db93180ce1 | ||
|
|
39da10d939 | ||
|
|
f2da253bc3 | ||
|
|
934d4047f1 | ||
|
|
b799cfd1c4 | ||
|
|
b712c100d7 | ||
|
|
c049bce007 | ||
|
|
46fad717e5 | ||
|
|
ae0c3bbbe8 | ||
|
|
f95d57e0d9 | ||
|
|
a1cbd4eb82 | ||
|
|
6cbeb107db | ||
|
|
3a5566c6c3 | ||
|
|
73c548ad01 | ||
|
|
82203e12c8 | ||
|
|
1ca099473f | ||
|
|
eceb8d9937 | ||
|
|
4ba92bb6d6 | ||
|
|
f31f68ae8e | ||
|
|
cff15f91d4 | ||
|
|
6b74917954 | ||
|
|
1bf2384a1f | ||
|
|
54a12779e2 | ||
|
|
e8b06fef9f | ||
|
|
653d70ec4e | ||
|
|
abb09418b1 | ||
|
|
c103bebd9f | ||
|
|
935d855b47 | ||
|
|
f8f9100a0d | ||
|
|
6de7b98e76 | ||
|
|
c390351c65 | ||
|
|
768bce799b | ||
|
|
d3a30142e5 | ||
|
|
3a635fc51f | ||
|
|
10078566da | ||
|
|
c44346096c | ||
|
|
0ff449e6a6 | ||
|
|
f3a16383b9 | ||
|
|
539ef3f770 | ||
|
|
f282856c72 | ||
|
|
6db8ec1ba2 | ||
|
|
5187c08c90 | ||
|
|
c8076ac10d | ||
|
|
362d155558 | ||
|
|
7b7eb0a6e5 | ||
|
|
d96f49f67d | ||
|
|
43ba5d2126 | ||
|
|
48f7598fed | ||
|
|
510b22e96b | ||
|
|
0a0aff14d8 | ||
|
|
e225ac68bc | ||
|
|
58060c40a5 | ||
|
|
2ac1b3d5c4 | ||
|
|
c174566982 | ||
|
|
60fca19d40 | ||
|
|
8bcb15b02f | ||
|
|
65c2cebcd5 | ||
|
|
2a51b45a43 | ||
|
|
5ac791665e | ||
|
|
a4e3f83611 | ||
|
|
8a837f9c2b | ||
|
|
da2d33e9a8 | ||
|
|
4b98dadae9 | ||
|
|
86acea5c46 | ||
|
|
a60fc73e7b | ||
|
|
50f99ec5f4 | ||
|
|
31b6a14444 | ||
|
|
9df4d36157 | ||
|
|
b70f0b674f | ||
|
|
510784077f | ||
|
|
9800e397fb | ||
|
|
1436d9961f | ||
|
|
98f5d05925 | ||
|
|
7a937c7652 | ||
|
|
b198d76676 | ||
|
|
97d4203354 | ||
|
|
beaaaad162 | ||
|
|
4e78975909 | ||
|
|
99147ed8f2 | ||
|
|
dec0d3bfc2 | ||
|
|
cd84c99e70 | ||
|
|
d5c507975c | ||
|
|
b4235abd36 | ||
|
|
1966085a97 | ||
|
|
e31e7af48f | ||
|
|
adb9123fc3 | ||
|
|
b0f7efd59e | ||
|
|
e28dfada8c | ||
|
|
ac0b28cce6 | ||
|
|
48b16ae66c | ||
|
|
061579ec28 | ||
|
|
f2f834e7e7 | ||
|
|
a7802e9a76 | ||
|
|
8f7ab95ff0 | ||
|
|
042c670747 | ||
|
|
cacbe9976f | ||
|
|
8efec1d640 | ||
|
|
c44d282f0b | ||
|
|
4432f29bd2 | ||
|
|
5fee3ed5e9 | ||
|
|
b76ea64263 | ||
|
|
ed904f08a4 | ||
|
|
96cc80ffc8 | ||
|
|
ab99373cfc | ||
|
|
dbfb49384b | ||
|
|
14bb9f29a3 | ||
|
|
16519ee2cc | ||
|
|
50022e9286 | ||
|
|
5059019535 | ||
|
|
c6a38f5069 | ||
|
|
11ed197663 | ||
|
|
5634e6b963 | ||
|
|
db312a5ff6 | ||
|
|
88c31b3785 | ||
|
|
967f3e4f77 | ||
|
|
2e311d1766 | ||
|
|
11f7cc0507 | ||
|
|
a4f28892a5 | ||
|
|
5bc53741be | ||
|
|
95a4f33265 | ||
|
|
fac1093ebf | ||
|
|
1b1384ccaa | ||
|
|
0c9a19ded5 | ||
|
|
b7bd7469b7 |
12
Makefile.in
12
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@
|
||||
|
||||
@@ -64,10 +64,10 @@ chronyc : $(CLI_OBJS)
|
||||
$(CC) $(CFLAGS) -o chronyc $(CLI_OBJS) $(LDFLAGS) $(LIBS) $(EXTRA_CLI_LIBS)
|
||||
|
||||
distclean : clean
|
||||
-rm -f .DS_Store
|
||||
-rm -f Makefile config.h config.log
|
||||
$(MAKE) -C doc distclean
|
||||
$(MAKE) -C test/unit distclean
|
||||
-rm -f .DS_Store
|
||||
-rm -f Makefile config.h config.log
|
||||
|
||||
clean :
|
||||
-rm -f *.o *.s chronyc chronyd core *~
|
||||
@@ -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
|
||||
|
||||
52
NEWS
52
NEWS
@@ -1,3 +1,49 @@
|
||||
New in version 3.2
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Improve stability with NTP sources and reference clocks
|
||||
* 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
|
||||
* Add support for new HW timestamping options added in Linux 4.13
|
||||
* Add rxfilter option to hwtimestamp 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 -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
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add support for precise cross timestamping of PHC on Linux
|
||||
* Add minpoll, precision, nocrossts options to hwtimestamp directive
|
||||
* Add rawmeasurements option to log directive and modify measurements
|
||||
option to log only valid measurements from synchronised sources
|
||||
* Allow sub-second polling interval with NTP sources
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix time smoothing in interleaved mode
|
||||
|
||||
New in version 3.0
|
||||
==================
|
||||
|
||||
@@ -16,14 +62,20 @@ Enhancements
|
||||
* Add -t option to chronyd to exit after specified time
|
||||
* Add partial protection against replay attacks on symmetric mode
|
||||
* Don't reset polling interval when switching sources to online state
|
||||
* Allow rate limiting with very short intervals
|
||||
* Improve maximum server throughput on Linux and NetBSD
|
||||
* Remove dump files after start
|
||||
* Add tab-completion to chronyc with libedit/readline
|
||||
* Add ntpdata command to print details about NTP measurements
|
||||
* Allow all source options to be set in add server/peer command
|
||||
* Indicate truncated addresses/hostnames in chronyc output
|
||||
* Print reference IDs as hexadecimal numbers to avoid confusion with
|
||||
IPv4 addresses
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix crash with disabled asynchronous name resolving
|
||||
|
||||
New in version 2.4.1
|
||||
====================
|
||||
|
||||
|
||||
5
README
5
README
@@ -16,7 +16,7 @@ and systems that do not run continuosly, or run on a virtual machine.
|
||||
|
||||
Typical accuracy between two machines synchronised over the Internet is
|
||||
within a few milliseconds; on a LAN, accuracy is typically in tens of
|
||||
microseconds. With hardware timestamping or a hardware reference clock
|
||||
microseconds. With hardware timestamping, or a hardware reference clock,
|
||||
sub-microsecond accuracy may be possible.
|
||||
|
||||
Two programs are included in chrony, chronyd is a daemon that can be
|
||||
@@ -203,6 +203,9 @@ Kalle Olavi Niemitalo <tosi@stekt.oulu.fi>
|
||||
Frank Otto <sandwichmacher@web.de>
|
||||
Handling arbitrary HZ values
|
||||
|
||||
Denny Page <dennypage@me.com>
|
||||
Advice on support for hardware timestamping
|
||||
|
||||
Gautier PHILIPPON <gautier.philippon@ensimag.grenoble-inp.fr>
|
||||
Patch to add refresh command to chronyc
|
||||
|
||||
|
||||
@@ -50,8 +50,11 @@ typedef struct {
|
||||
unsigned short port;
|
||||
} NTP_Remote_Address;
|
||||
|
||||
#define INVALID_IF_INDEX -1
|
||||
|
||||
typedef struct {
|
||||
IPAddr ip_addr;
|
||||
int if_index;
|
||||
int sock_fd;
|
||||
} NTP_Local_Address;
|
||||
|
||||
|
||||
11
candm.h
11
candm.h
@@ -362,8 +362,9 @@ typedef struct {
|
||||
domain socket.
|
||||
|
||||
Version 6 (no authentication) : changed format of client accesses by index
|
||||
(using new request/reply types), new flags in NTP source request and report,
|
||||
new commands: 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 +462,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 +571,7 @@ typedef struct {
|
||||
} RPY_Rtc;
|
||||
|
||||
typedef struct {
|
||||
uint32_t centiseconds;
|
||||
Float offset;
|
||||
Float dfreq_ppm;
|
||||
Float new_afreq_ppm;
|
||||
int32_t EOR;
|
||||
@@ -672,6 +674,7 @@ typedef struct {
|
||||
uint32_t total_tx_count;
|
||||
uint32_t total_rx_count;
|
||||
uint32_t total_valid_count;
|
||||
uint32_t reserved[4];
|
||||
int32_t EOR;
|
||||
} RPY_NTPData;
|
||||
|
||||
|
||||
398
client.c
398
client.c
@@ -3,6 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Lonnie Abelbeck 2016
|
||||
* Copyright (C) Miroslav Lichvar 2009-2016
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -80,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, ...)
|
||||
{
|
||||
@@ -167,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]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,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;
|
||||
}
|
||||
|
||||
@@ -228,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;
|
||||
@@ -236,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;
|
||||
}
|
||||
|
||||
@@ -268,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);
|
||||
@@ -294,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;
|
||||
@@ -316,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;
|
||||
@@ -372,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;
|
||||
}
|
||||
|
||||
@@ -437,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;
|
||||
@@ -465,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;
|
||||
@@ -702,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;
|
||||
}
|
||||
|
||||
@@ -734,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;
|
||||
}
|
||||
|
||||
@@ -763,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);
|
||||
@@ -797,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);
|
||||
@@ -851,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));
|
||||
}
|
||||
}
|
||||
@@ -986,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;
|
||||
}
|
||||
}
|
||||
@@ -1002,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;
|
||||
}
|
||||
}
|
||||
@@ -1072,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;
|
||||
}
|
||||
|
||||
@@ -1152,11 +1151,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);
|
||||
@@ -1191,7 +1190,7 @@ give_help(void)
|
||||
"\0\0"
|
||||
"NTP sources:\0\0"
|
||||
"activity\0Check how many NTP sources are online/offline\0"
|
||||
"ntpdata <address>\0Display information about last valid measurement\0"
|
||||
"ntpdata [<address>]\0Display information about last valid measurement\0"
|
||||
"add server <address> [options]\0Add new NTP server\0"
|
||||
"add peer <address> [options]\0Add new NTP peer\0"
|
||||
"delete <address>\0Remove server or peer\0"
|
||||
@@ -1241,6 +1240,7 @@ give_help(void)
|
||||
"Other daemon commands:\0\0"
|
||||
"cyclelogs\0Close and re-open log files\0"
|
||||
"dump\0Dump all measurements to save files\0"
|
||||
"rekey\0Re-read keys from key file\0"
|
||||
"\0\0"
|
||||
"Client commands:\0\0"
|
||||
"dns -n|+n\0Disable/enable resolving IP addresses to hostnames\0"
|
||||
@@ -1367,17 +1367,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))
|
||||
@@ -1392,7 +1391,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);
|
||||
@@ -1406,7 +1405,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;
|
||||
@@ -1416,10 +1415,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)) {
|
||||
@@ -1469,7 +1468,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;
|
||||
}
|
||||
@@ -2059,7 +2058,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) {
|
||||
@@ -2214,8 +2214,8 @@ process_cmd_tracking(char *line)
|
||||
"Frequency : %.3F\n"
|
||||
"Residual freq : %+.3f ppm\n"
|
||||
"Skew : %.3f ppm\n"
|
||||
"Root delay : %.6f seconds\n"
|
||||
"Root dispersion : %.6f seconds\n"
|
||||
"Root delay : %.9f seconds\n"
|
||||
"Root dispersion : %.9f seconds\n"
|
||||
"Update interval : %.1f seconds\n"
|
||||
"Leap status : %L\n",
|
||||
(unsigned long)ref_id, name,
|
||||
@@ -2244,71 +2244,107 @@ process_cmd_ntpdata(char *line)
|
||||
CMD_Reply reply;
|
||||
IPAddr remote_addr, local_addr;
|
||||
struct timespec ref_time;
|
||||
uint32_t i, n_sources;
|
||||
uint16_t mode;
|
||||
int specified_addr;
|
||||
|
||||
if (DNS_Name2IPAddress(line, &remote_addr, 1) != DNS_Success) {
|
||||
LOG(LOGS_ERR, LOGF_Client, "Could not get address for hostname");
|
||||
return 0;
|
||||
if (*line) {
|
||||
specified_addr = 1;
|
||||
n_sources = 1;
|
||||
} else {
|
||||
specified_addr = 0;
|
||||
request.command = htons(REQ_N_SOURCES);
|
||||
if (!request_reply(&request, &reply, RPY_N_SOURCES, 0))
|
||||
return 0;
|
||||
n_sources = ntohl(reply.data.n_sources.n_sources);
|
||||
}
|
||||
|
||||
request.command = htons(REQ_NTP_DATA);
|
||||
UTI_IPHostToNetwork(&remote_addr, &request.data.ntp_data.ip_addr);
|
||||
if (!request_reply(&request, &reply, RPY_NTP_DATA, 0))
|
||||
return 0;
|
||||
for (i = 0; i < n_sources; i++) {
|
||||
if (specified_addr) {
|
||||
if (DNS_Name2IPAddress(line, &remote_addr, 1) != DNS_Success) {
|
||||
LOG(LOGS_ERR, "Could not get address for hostname");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
request.command = htons(REQ_SOURCE_DATA);
|
||||
request.data.source_data.index = htonl(i);
|
||||
if (!request_reply(&request, &reply, RPY_SOURCE_DATA, 0))
|
||||
return 0;
|
||||
|
||||
UTI_IPNetworkToHost(&reply.data.ntp_data.remote_addr, &remote_addr);
|
||||
UTI_IPNetworkToHost(&reply.data.ntp_data.local_addr, &local_addr);
|
||||
UTI_TimespecNetworkToHost(&reply.data.ntp_data.ref_time, &ref_time);
|
||||
mode = ntohs(reply.data.source_data.mode);
|
||||
if (mode != RPY_SD_MD_CLIENT && mode != RPY_SD_MD_PEER)
|
||||
continue;
|
||||
|
||||
print_report("Remote address : %s (%R)\n"
|
||||
"Remote port : %u\n"
|
||||
"Local address : %s (%R)\n"
|
||||
"Leap status : %L\n"
|
||||
"Version : %u\n"
|
||||
"Mode : %M\n"
|
||||
"Stratum : %u\n"
|
||||
"Poll : %d\n"
|
||||
"Precision : %.9f seconds\n"
|
||||
"Root delay : %.6f seconds\n"
|
||||
"Root dispersion : %.6f seconds\n"
|
||||
"Reference ID : %R\n"
|
||||
"Reference time : %T\n"
|
||||
"Offset : %+.9f seconds\n"
|
||||
"Peer delay : %.9f seconds\n"
|
||||
"Peer dispersion : %.9f seconds\n"
|
||||
"Response time : %.9f seconds\n"
|
||||
"Jitter asymmetry: %+.2f\n"
|
||||
"NTP tests : %.3b %.3b %.4b\n"
|
||||
"Interleaved : %B\n"
|
||||
"Authenticated : %B\n"
|
||||
"TX timestamping : %N\n"
|
||||
"RX timestamping : %N\n"
|
||||
"Total TX : %U\n"
|
||||
"Total RX : %U\n"
|
||||
"Total valid RX : %U\n",
|
||||
UTI_IPToString(&remote_addr), (unsigned long)UTI_IPToRefid(&remote_addr),
|
||||
ntohs(reply.data.ntp_data.remote_port),
|
||||
UTI_IPToString(&local_addr), (unsigned long)UTI_IPToRefid(&local_addr),
|
||||
reply.data.ntp_data.leap, reply.data.ntp_data.version,
|
||||
reply.data.ntp_data.mode, reply.data.ntp_data.stratum,
|
||||
reply.data.ntp_data.poll, UTI_Log2ToDouble(reply.data.ntp_data.precision),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.root_delay),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.root_dispersion),
|
||||
(unsigned long)ntohl(reply.data.ntp_data.ref_id), &ref_time,
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.offset),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.peer_delay),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.peer_dispersion),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.response_time),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.jitter_asymmetry),
|
||||
ntohs(reply.data.ntp_data.flags) >> 7,
|
||||
ntohs(reply.data.ntp_data.flags) >> 4,
|
||||
ntohs(reply.data.ntp_data.flags),
|
||||
ntohs(reply.data.ntp_data.flags) & RPY_NTP_FLAG_INTERLEAVED,
|
||||
ntohs(reply.data.ntp_data.flags) & RPY_NTP_FLAG_AUTHENTICATED,
|
||||
reply.data.ntp_data.tx_tss_char, reply.data.ntp_data.rx_tss_char,
|
||||
(unsigned long)ntohl(reply.data.ntp_data.total_tx_count),
|
||||
(unsigned long)ntohl(reply.data.ntp_data.total_rx_count),
|
||||
(unsigned long)ntohl(reply.data.ntp_data.total_valid_count),
|
||||
REPORT_END);
|
||||
UTI_IPNetworkToHost(&reply.data.source_data.ip_addr, &remote_addr);
|
||||
}
|
||||
|
||||
request.command = htons(REQ_NTP_DATA);
|
||||
UTI_IPHostToNetwork(&remote_addr, &request.data.ntp_data.ip_addr);
|
||||
if (!request_reply(&request, &reply, RPY_NTP_DATA, 0))
|
||||
return 0;
|
||||
|
||||
UTI_IPNetworkToHost(&reply.data.ntp_data.remote_addr, &remote_addr);
|
||||
UTI_IPNetworkToHost(&reply.data.ntp_data.local_addr, &local_addr);
|
||||
UTI_TimespecNetworkToHost(&reply.data.ntp_data.ref_time, &ref_time);
|
||||
|
||||
if (!specified_addr && !csv_mode)
|
||||
printf("\n");
|
||||
|
||||
print_report("Remote address : %s (%R)\n"
|
||||
"Remote port : %u\n"
|
||||
"Local address : %s (%R)\n"
|
||||
"Leap status : %L\n"
|
||||
"Version : %u\n"
|
||||
"Mode : %M\n"
|
||||
"Stratum : %u\n"
|
||||
"Poll interval : %d (%.0f seconds)\n"
|
||||
"Precision : %d (%.9f seconds)\n"
|
||||
"Root delay : %.6f seconds\n"
|
||||
"Root dispersion : %.6f seconds\n"
|
||||
"Reference ID : %R (%s)\n"
|
||||
"Reference time : %T\n"
|
||||
"Offset : %+.9f seconds\n"
|
||||
"Peer delay : %.9f seconds\n"
|
||||
"Peer dispersion : %.9f seconds\n"
|
||||
"Response time : %.9f seconds\n"
|
||||
"Jitter asymmetry: %+.2f\n"
|
||||
"NTP tests : %.3b %.3b %.4b\n"
|
||||
"Interleaved : %B\n"
|
||||
"Authenticated : %B\n"
|
||||
"TX timestamping : %N\n"
|
||||
"RX timestamping : %N\n"
|
||||
"Total TX : %U\n"
|
||||
"Total RX : %U\n"
|
||||
"Total valid RX : %U\n",
|
||||
UTI_IPToString(&remote_addr), (unsigned long)UTI_IPToRefid(&remote_addr),
|
||||
ntohs(reply.data.ntp_data.remote_port),
|
||||
UTI_IPToString(&local_addr), (unsigned long)UTI_IPToRefid(&local_addr),
|
||||
reply.data.ntp_data.leap, reply.data.ntp_data.version,
|
||||
reply.data.ntp_data.mode, reply.data.ntp_data.stratum,
|
||||
reply.data.ntp_data.poll, UTI_Log2ToDouble(reply.data.ntp_data.poll),
|
||||
reply.data.ntp_data.precision, UTI_Log2ToDouble(reply.data.ntp_data.precision),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.root_delay),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.root_dispersion),
|
||||
(unsigned long)ntohl(reply.data.ntp_data.ref_id),
|
||||
reply.data.ntp_data.stratum <= 1 ?
|
||||
UTI_RefidToString(ntohl(reply.data.ntp_data.ref_id)) : "",
|
||||
&ref_time,
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.offset),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.peer_delay),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.peer_dispersion),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.response_time),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.jitter_asymmetry),
|
||||
ntohs(reply.data.ntp_data.flags) >> 7,
|
||||
ntohs(reply.data.ntp_data.flags) >> 4,
|
||||
ntohs(reply.data.ntp_data.flags),
|
||||
ntohs(reply.data.ntp_data.flags) & RPY_NTP_FLAG_INTERLEAVED,
|
||||
ntohs(reply.data.ntp_data.flags) & RPY_NTP_FLAG_AUTHENTICATED,
|
||||
reply.data.ntp_data.tx_tss_char, reply.data.ntp_data.rx_tss_char,
|
||||
(unsigned long)ntohl(reply.data.ntp_data.total_tx_count),
|
||||
(unsigned long)ntohl(reply.data.ntp_data.total_rx_count),
|
||||
(unsigned long)ntohl(reply.data.ntp_data.total_valid_count),
|
||||
REPORT_END);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -2383,7 +2419,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;
|
||||
}
|
||||
|
||||
@@ -2531,7 +2567,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;
|
||||
}
|
||||
|
||||
@@ -2549,7 +2585,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;
|
||||
|
||||
@@ -2563,9 +2598,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",
|
||||
@@ -2594,7 +2628,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);
|
||||
@@ -2687,7 +2721,8 @@ process_cmd_waitsync(char *line)
|
||||
max_skew_ppm = 0.0;
|
||||
interval = 10.0;
|
||||
|
||||
sscanf(line, "%d %lf %lf %lf", &max_tries, &max_correction, &max_skew_ppm, &interval);
|
||||
if (sscanf(line, "%d %lf %lf %lf", &max_tries, &max_correction, &max_skew_ppm, &interval))
|
||||
;
|
||||
|
||||
/* Don't allow shorter interval than 0.1 seconds */
|
||||
if (interval < 0.1)
|
||||
@@ -2742,7 +2777,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;
|
||||
@@ -2757,7 +2792,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;
|
||||
@@ -2772,8 +2807,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;
|
||||
@@ -2795,11 +2830,12 @@ process_cmd_keygen(char *line)
|
||||
snprintf(hash_name, sizeof (hash_name), "MD5");
|
||||
#endif
|
||||
|
||||
sscanf(line, "%u %16s %d", &id, hash_name, &bits);
|
||||
if (sscanf(line, "%u %16s %d", &id, hash_name, &bits))
|
||||
;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -2991,11 +3027,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;
|
||||
}
|
||||
|
||||
@@ -3012,7 +3048,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;
|
||||
@@ -3058,7 +3094,7 @@ static void
|
||||
display_gpl(void)
|
||||
{
|
||||
printf("chrony version %s\n"
|
||||
"Copyright (C) 1997-2003, 2007, 2009-2016 Richard P. Curnow and others\n"
|
||||
"Copyright (C) 1997-2003, 2007, 2009-2017 Richard P. Curnow and others\n"
|
||||
"chrony comes with ABSOLUTELY NO WARRANTY. This is free software, and\n"
|
||||
"you are welcome to redistribute it under certain conditions. See the\n"
|
||||
"GNU General Public License version 2 for details.\n\n",
|
||||
@@ -3067,54 +3103,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3122,7 +3184,7 @@ main(int argc, char **argv)
|
||||
on_terminal = 1;
|
||||
}
|
||||
|
||||
if (on_terminal && (argc == 0)) {
|
||||
if (on_terminal && optind == argc) {
|
||||
display_gpl();
|
||||
}
|
||||
|
||||
@@ -3137,10 +3199,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();
|
||||
|
||||
63
clientlog.c
63
clientlog.c
@@ -86,6 +86,10 @@ static unsigned int max_slots;
|
||||
#define TS_FRAC 4
|
||||
#define INVALID_TS 0
|
||||
|
||||
/* Static offset included in conversion to the fixed-point timestamps to
|
||||
randomise their alignment */
|
||||
static uint32_t ts_offset;
|
||||
|
||||
/* Request rates are saved in the record as 8-bit scaled log2 values */
|
||||
#define RATE_SCALE 4
|
||||
#define MIN_RATE (-14 * RATE_SCALE)
|
||||
@@ -95,7 +99,7 @@ static unsigned int max_slots;
|
||||
number of tokens spent on response are determined from configured
|
||||
minimum inverval between responses (in log2) and burst length. */
|
||||
|
||||
#define MIN_LIMIT_INTERVAL (-TS_FRAC)
|
||||
#define MIN_LIMIT_INTERVAL (-15 - TS_FRAC)
|
||||
#define MAX_LIMIT_INTERVAL 12
|
||||
#define MIN_LIMIT_BURST 1
|
||||
#define MAX_LIMIT_BURST 255
|
||||
@@ -105,7 +109,8 @@ static uint16_t max_cmd_tokens;
|
||||
static uint16_t ntp_tokens_per_packet;
|
||||
static uint16_t cmd_tokens_per_packet;
|
||||
|
||||
/* Reduction of token rates to avoid overflow of 16-bit counters */
|
||||
/* Reduction of token rates to avoid overflow of 16-bit counters. Negative
|
||||
shift is used for coarse limiting with intervals shorter than -TS_FRAC. */
|
||||
static int ntp_token_shift;
|
||||
static int cmd_token_shift;
|
||||
|
||||
@@ -123,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;
|
||||
|
||||
@@ -133,6 +141,8 @@ static uint32_t total_ntp_drops;
|
||||
static uint32_t total_cmd_drops;
|
||||
static uint32_t total_record_drops;
|
||||
|
||||
#define NSEC_PER_SEC 1000000000U
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int expand_hashtable(void);
|
||||
@@ -271,16 +281,23 @@ set_bucket_params(int interval, int burst, uint16_t *max_tokens,
|
||||
interval = CLAMP(MIN_LIMIT_INTERVAL, interval, MAX_LIMIT_INTERVAL);
|
||||
burst = CLAMP(MIN_LIMIT_BURST, burst, MAX_LIMIT_BURST);
|
||||
|
||||
/* Find smallest shift with which the maximum number fits in 16 bits */
|
||||
for (*token_shift = 0; *token_shift < interval + TS_FRAC; (*token_shift)++) {
|
||||
if (burst << (TS_FRAC + interval - *token_shift) < 1U << 16)
|
||||
break;
|
||||
if (interval >= -TS_FRAC) {
|
||||
/* Find the smallest shift with which the maximum number fits in 16 bits */
|
||||
for (*token_shift = 0; *token_shift < interval + TS_FRAC; (*token_shift)++) {
|
||||
if (burst << (TS_FRAC + interval - *token_shift) < 1U << 16)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Coarse rate limiting */
|
||||
*token_shift = interval + TS_FRAC;
|
||||
*tokens_per_packet = 1;
|
||||
burst = MAX(1U << -*token_shift, burst);
|
||||
}
|
||||
|
||||
*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);
|
||||
}
|
||||
|
||||
@@ -295,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)) {
|
||||
@@ -311,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;
|
||||
}
|
||||
|
||||
@@ -325,6 +344,9 @@ CLG_Initialise(void)
|
||||
records = NULL;
|
||||
|
||||
expand_hashtable();
|
||||
|
||||
UTI_GetRandomBytes(&ts_offset, sizeof (ts_offset));
|
||||
ts_offset %= NSEC_PER_SEC / (1U << TS_FRAC);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -345,6 +367,12 @@ get_ts_from_timespec(struct timespec *ts)
|
||||
{
|
||||
uint32_t sec = ts->tv_sec, nsec = ts->tv_nsec;
|
||||
|
||||
nsec += ts_offset;
|
||||
if (nsec >= NSEC_PER_SEC) {
|
||||
nsec -= NSEC_PER_SEC;
|
||||
sec++;
|
||||
}
|
||||
|
||||
/* This is fast and accurate enough */
|
||||
return sec << TS_FRAC | (140740U * (nsec >> 15)) >> (32 - TS_FRAC);
|
||||
}
|
||||
@@ -369,7 +397,12 @@ update_record(struct timespec *now, uint32_t *last_hit, uint32_t *hits,
|
||||
if (prev_hit == INVALID_TS || (int32_t)interval < 0)
|
||||
return;
|
||||
|
||||
new_tokens = (now_ts >> token_shift) - (prev_hit >> token_shift);
|
||||
if (token_shift >= 0)
|
||||
new_tokens = (now_ts >> token_shift) - (prev_hit >> token_shift);
|
||||
else if (now_ts - prev_hit > max_tokens)
|
||||
new_tokens = max_tokens;
|
||||
else
|
||||
new_tokens = (now_ts - prev_hit) << -token_shift;
|
||||
*tokens = MIN(*tokens + new_tokens, max_tokens);
|
||||
|
||||
/* Convert the interval to scaled and rounded log2 */
|
||||
@@ -442,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);
|
||||
|
||||
@@ -466,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);
|
||||
@@ -578,6 +611,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)
|
||||
{
|
||||
|
||||
@@ -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. */
|
||||
|
||||
|
||||
50
cmdmon.c
50
cmdmon.c
@@ -161,7 +161,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 +172,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 +188,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 +230,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 +238,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 +315,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 +396,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 +568,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 {
|
||||
@@ -874,7 +873,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 +886,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);
|
||||
}
|
||||
|
||||
@@ -1232,6 +1231,7 @@ handle_ntp_data(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
tx_message->data.ntp_data.total_tx_count = htonl(report.total_tx_count);
|
||||
tx_message->data.ntp_data.total_rx_count = htonl(report.total_rx_count);
|
||||
tx_message->data.ntp_data.total_valid_count = htonl(report.total_valid_count);
|
||||
memset(tx_message->data.ntp_data.reserved, 0xff, sizeof (tx_message->data.ntp_data.reserved));
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1257,14 +1257,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;
|
||||
}
|
||||
|
||||
@@ -1299,7 +1299,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))) {
|
||||
@@ -1318,7 +1318,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;
|
||||
}
|
||||
|
||||
@@ -1340,7 +1340,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) {
|
||||
@@ -1352,7 +1352,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);
|
||||
@@ -1360,7 +1360,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);
|
||||
@@ -1375,7 +1375,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;
|
||||
}
|
||||
|
||||
@@ -1626,7 +1626,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;
|
||||
}
|
||||
|
||||
164
conf.c
164
conf.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
|
||||
@@ -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;
|
||||
@@ -97,13 +97,13 @@ static double combine_limit = 3.0;
|
||||
|
||||
static int cmd_port = DEFAULT_CANDM_PORT;
|
||||
|
||||
static int raw_measurements = 0;
|
||||
static int do_log_measurements = 0;
|
||||
static int do_log_statistics = 0;
|
||||
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;
|
||||
@@ -194,10 +194,10 @@ static char *pidfile;
|
||||
static int ntp_ratelimit_enabled = 0;
|
||||
static int ntp_ratelimit_interval = 3;
|
||||
static int ntp_ratelimit_burst = 8;
|
||||
static int ntp_ratelimit_leak = 3;
|
||||
static int ntp_ratelimit_leak = 2;
|
||||
static int cmd_ratelimit_enabled = 0;
|
||||
static int cmd_ratelimit_interval = 1;
|
||||
static int cmd_ratelimit_burst = 16;
|
||||
static int cmd_ratelimit_interval = -4;
|
||||
static int cmd_ratelimit_burst = 8;
|
||||
static int cmd_ratelimit_leak = 2;
|
||||
|
||||
/* Smoothing constants */
|
||||
@@ -223,7 +223,7 @@ static char *leapsec_tz = NULL;
|
||||
/* Name of the user to which will be dropped root privileges. */
|
||||
static char *user;
|
||||
|
||||
/* Array of strings for interfaces with HW timestamping */
|
||||
/* Array of CNF_HwTsInterface */
|
||||
static ARR_Instance hwts_interfaces;
|
||||
|
||||
typedef struct {
|
||||
@@ -270,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 : "");
|
||||
}
|
||||
@@ -280,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 : "");
|
||||
}
|
||||
@@ -313,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 : "");
|
||||
@@ -323,11 +323,11 @@ check_number_of_args(char *line, int num)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
CNF_Initialise(int r)
|
||||
CNF_Initialise(int r, int client_only)
|
||||
{
|
||||
restarted = r;
|
||||
|
||||
hwts_interfaces = ARR_CreateInstance(sizeof (char *));
|
||||
hwts_interfaces = ARR_CreateInstance(sizeof (CNF_HwTsInterface));
|
||||
|
||||
init_sources = ARR_CreateInstance(sizeof (IPAddr));
|
||||
ntp_sources = ARR_CreateInstance(sizeof (NTP_Source));
|
||||
@@ -339,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);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -354,7 +361,7 @@ CNF_Finalise(void)
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARR_GetSize(hwts_interfaces); i++)
|
||||
Free(*(char **)ARR_GetElement(hwts_interfaces, i));
|
||||
Free(((CNF_HwTsInterface *)ARR_GetElement(hwts_interfaces, i))->name);
|
||||
ARR_DestroyInstance(hwts_interfaces);
|
||||
|
||||
for (i = 0; i < ARR_GetSize(ntp_sources); i++)
|
||||
@@ -397,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);
|
||||
@@ -468,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")) {
|
||||
@@ -568,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");
|
||||
}
|
||||
@@ -674,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;
|
||||
@@ -684,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;
|
||||
@@ -692,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;
|
||||
@@ -756,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;
|
||||
@@ -791,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;
|
||||
@@ -799,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;
|
||||
@@ -814,7 +831,10 @@ parse_log(char *line)
|
||||
log_name = line;
|
||||
line = CPS_SplitWord(line);
|
||||
if (*log_name) {
|
||||
if (!strcmp(log_name, "measurements")) {
|
||||
if (!strcmp(log_name, "rawmeasurements")) {
|
||||
do_log_measurements = 1;
|
||||
raw_measurements = 1;
|
||||
} else if (!strcmp(log_name, "measurements")) {
|
||||
do_log_measurements = 1;
|
||||
} else if (!strcmp(log_name, "statistics")) {
|
||||
do_log_statistics = 1;
|
||||
@@ -874,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1051,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;
|
||||
@@ -1166,7 +1186,7 @@ parse_broadcast(char *line)
|
||||
}
|
||||
} else {
|
||||
/* default port */
|
||||
port = 123;
|
||||
port = NTP_PORT;
|
||||
}
|
||||
|
||||
destination = (NTP_Broadcast_Destination *)ARR_GetNewElement(broadcasts);
|
||||
@@ -1245,8 +1265,63 @@ parse_tempcomp(char *line)
|
||||
static void
|
||||
parse_hwtimestamp(char *line)
|
||||
{
|
||||
check_number_of_args(line, 1);
|
||||
*(char **)ARR_GetNewElement(hwts_interfaces) = Strdup(line);
|
||||
CNF_HwTsInterface *iface;
|
||||
char *p, filter[5];
|
||||
int n;
|
||||
|
||||
if (!*line) {
|
||||
command_parse_error();
|
||||
return;
|
||||
}
|
||||
|
||||
p = line;
|
||||
line = CPS_SplitWord(line);
|
||||
|
||||
iface = ARR_GetNewElement(hwts_interfaces);
|
||||
iface->name = Strdup(p);
|
||||
iface->minpoll = 0;
|
||||
iface->nocrossts = 0;
|
||||
iface->rxfilter = CNF_HWTS_RXFILTER_NTP;
|
||||
iface->precision = 100.0e-9;
|
||||
iface->tx_comp = 0.0;
|
||||
iface->rx_comp = 0.0;
|
||||
|
||||
for (p = line; *p; line += n, p = line) {
|
||||
line = CPS_SplitWord(line);
|
||||
|
||||
if (!strcasecmp(p, "minpoll")) {
|
||||
if (sscanf(line, "%d%n", &iface->minpoll, &n) != 1)
|
||||
break;
|
||||
} else if (!strcasecmp(p, "precision")) {
|
||||
if (sscanf(line, "%lf%n", &iface->precision, &n) != 1)
|
||||
break;
|
||||
} else if (!strcasecmp(p, "rxcomp")) {
|
||||
if (sscanf(line, "%lf%n", &iface->rx_comp, &n) != 1)
|
||||
break;
|
||||
} 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;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*p)
|
||||
command_parse_error();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1256,11 +1331,15 @@ 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, GLOB_ERR | GLOB_NOMAGIC, 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;
|
||||
}
|
||||
|
||||
@@ -1286,7 +1365,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';
|
||||
}
|
||||
|
||||
@@ -1425,8 +1504,9 @@ CNF_GetDumpDir(void)
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CNF_GetLogMeasurements(void)
|
||||
CNF_GetLogMeasurements(int *raw)
|
||||
{
|
||||
*raw = raw_measurements;
|
||||
return do_log_measurements;
|
||||
}
|
||||
|
||||
@@ -1504,14 +1584,6 @@ CNF_GetRtcDevice(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CNF_GetDumpOnExit(void)
|
||||
{
|
||||
return do_dump_on_exit;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
double
|
||||
CNF_GetMaxUpdateSkew(void)
|
||||
{
|
||||
@@ -1692,7 +1764,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1700,7 +1772,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1930,8 +2002,12 @@ CNF_GetInitStepThreshold(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
ARR_Instance
|
||||
CNF_GetHwTsInterfaces(void)
|
||||
int
|
||||
CNF_GetHwTsInterface(unsigned int index, CNF_HwTsInterface **iface)
|
||||
{
|
||||
return hwts_interfaces;
|
||||
if (index >= ARR_GetSize(hwts_interfaces))
|
||||
return 0;
|
||||
|
||||
*iface = (CNF_HwTsInterface *)ARR_GetElement(hwts_interfaces, index);
|
||||
return 1;
|
||||
}
|
||||
|
||||
22
conf.h
22
conf.h
@@ -29,10 +29,9 @@
|
||||
#define GOT_CONF_H
|
||||
|
||||
#include "addressing.h"
|
||||
#include "array.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);
|
||||
@@ -53,7 +52,7 @@ extern char *CNF_GetDriftFile(void);
|
||||
extern char *CNF_GetLogDir(void);
|
||||
extern char *CNF_GetDumpDir(void);
|
||||
extern int CNF_GetLogBanner(void);
|
||||
extern int CNF_GetLogMeasurements(void);
|
||||
extern int CNF_GetLogMeasurements(int *raw);
|
||||
extern int CNF_GetLogStatistics(void);
|
||||
extern int CNF_GetLogTracking(void);
|
||||
extern int CNF_GetLogRtc(void);
|
||||
@@ -61,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);
|
||||
@@ -120,6 +118,20 @@ extern char *CNF_GetHwclockFile(void);
|
||||
extern int CNF_GetInitSources(void);
|
||||
extern double CNF_GetInitStepThreshold(void);
|
||||
|
||||
extern ARR_Instance CNF_GetHwTsInterfaces(void);
|
||||
#define CNF_HWTS_RXFILTER_NONE 0
|
||||
#define CNF_HWTS_RXFILTER_NTP 1
|
||||
#define CNF_HWTS_RXFILTER_ALL 2
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
int minpoll;
|
||||
int nocrossts;
|
||||
int rxfilter;
|
||||
double precision;
|
||||
double tx_comp;
|
||||
double rx_comp;
|
||||
} CNF_HwTsInterface;
|
||||
|
||||
extern int CNF_GetHwTsInterface(unsigned int index, CNF_HwTsInterface **iface);
|
||||
|
||||
#endif /* GOT_CONF_H */
|
||||
|
||||
84
configure
vendored
84
configure
vendored
@@ -4,7 +4,8 @@
|
||||
# chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
#
|
||||
# Copyright (C) Richard P. Curnow 1997-2003
|
||||
# Copyright (C) Miroslav Lichvar 2009, 2012-2015
|
||||
# Copyright (C) Bryan Christianson 2016
|
||||
# Copyright (C) Miroslav Lichvar 2009, 2012-2016
|
||||
#
|
||||
# =======================================================================
|
||||
|
||||
@@ -219,6 +220,7 @@ try_lockmem=0
|
||||
feat_asyncdns=1
|
||||
feat_forcednsretry=1
|
||||
try_clock_gettime=1
|
||||
try_recvmmsg=1
|
||||
feat_timestamping=1
|
||||
try_timestamping=0
|
||||
feat_ntp_signd=0
|
||||
@@ -400,6 +402,9 @@ case $OPERATINGSYSTEM in
|
||||
echo "Configuring for " $SYSTEM
|
||||
;;
|
||||
FreeBSD)
|
||||
# recvmmsg() seems to be broken on FreeBSD 11.0 and it's just
|
||||
# a wrapper around recvmsg()
|
||||
try_recvmmsg=0
|
||||
EXTRA_OBJECTS="sys_generic.o sys_netbsd.o sys_timex.o"
|
||||
add_def FREEBSD
|
||||
if [ $feat_droproot = "1" ]; then
|
||||
@@ -423,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)
|
||||
@@ -485,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"
|
||||
@@ -502,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
|
||||
|
||||
@@ -626,17 +658,24 @@ 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);'
|
||||
if test_code 'recvmmsg()' 'sys/socket.h' '' "$EXTRA_LIBS" "$RECVMMSG_CODE"; then
|
||||
add_def HAVE_RECVMMSG
|
||||
else
|
||||
if test_code 'recvmmsg() with _GNU_SOURCE' 'sys/socket.h' '-D_GNU_SOURCE' \
|
||||
"$EXTRA_LIBS" "$RECVMMSG_CODE"
|
||||
then
|
||||
add_def _GNU_SOURCE
|
||||
if [ $try_recvmmsg = "1" ]; then
|
||||
if test_code 'recvmmsg()' 'sys/socket.h' '' "$EXTRA_LIBS" "$RECVMMSG_CODE"; then
|
||||
add_def HAVE_RECVMMSG
|
||||
else
|
||||
if test_code 'recvmmsg() with _GNU_SOURCE' 'sys/socket.h' '-D_GNU_SOURCE' \
|
||||
"$EXTRA_LIBS" "$RECVMMSG_CODE"
|
||||
then
|
||||
add_def _GNU_SOURCE
|
||||
add_def HAVE_RECVMMSG
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -651,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=""
|
||||
@@ -702,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
|
||||
|
||||
@@ -725,8 +775,10 @@ fi
|
||||
if [ $feat_refclock = "1" ] && [ $feat_phc = "1" ] && [ $try_phc = "1" ] && \
|
||||
grep '#define HAVE_CLOCK_GETTIME' config.h > /dev/null && \
|
||||
test_code '<linux/ptp_clock.h>' 'sys/ioctl.h linux/ptp_clock.h' '' '' \
|
||||
'ioctl(1, PTP_CLOCK_GETCAPS, 0);'
|
||||
'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
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// This file is part of chrony
|
||||
//
|
||||
// Copyright (C) Richard P. Curnow 1997-2003
|
||||
// Copyright (C) Miroslav Lichvar 2009-2016
|
||||
// Copyright (C) Stephen Wadeley 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
|
||||
@@ -67,11 +68,15 @@ options:
|
||||
Although *chronyd* will trim the rate at which it samples the server during
|
||||
normal operation, the user might want to constrain the minimum polling interval.
|
||||
This is always defined as a power of 2, so *minpoll 5* would mean that the
|
||||
polling interval cannot drop below 32 seconds. The default is 6 (64 seconds).
|
||||
polling interval cannot drop below 32 seconds. The default is 6 (64 seconds),
|
||||
the minimum is -4 (1/16th of a second), and the maximum is 24 (6 months). Note
|
||||
that intervals shorter than 6 (64 seconds) should generally not be used with
|
||||
public servers on the Internet, because it might be considered abuse.
|
||||
*maxpoll* _poll_:::
|
||||
In a similar way, the user might want to constrain the maximum polling interval.
|
||||
Again this is specified as a power of 2, *maxpoll 9* indicates that the polling
|
||||
interval must stay at or below 512 seconds. The default is 10 (1024 seconds).
|
||||
interval must stay at or below 512 seconds. The default is 10 (1024 seconds),
|
||||
the minimum is 0 (1 second), and the maximum is 24 (6 months).
|
||||
*iburst*:::
|
||||
If this option is set, the interval between the first four polls will be 2
|
||||
seconds instead of _minpoll_. This is useful to quickly get the first update of
|
||||
@@ -105,12 +110,13 @@ If the user knows that round trip delays above a certain level should cause the
|
||||
measurement to be ignored, this level can be defined with the *maxdelay*
|
||||
option. For example, *maxdelay 0.3* would indicate that measurements with a
|
||||
round-trip delay of 0.3 seconds or more should be ignored. The default value is
|
||||
3 seconds.
|
||||
3 seconds and the maximum value is 1000 seconds.
|
||||
*maxdelayratio* _ratio_:::
|
||||
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.
|
||||
maxdelayratio times the minimum delay, it will be rejected. This option works
|
||||
only in the *server* directive when not in the interleaved mode.
|
||||
*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
|
||||
@@ -159,9 +165,8 @@ synchronisation only if they agree with the trusted and required source.
|
||||
*xleave*:::
|
||||
This option enables an interleaved mode which allows the server or the peer to
|
||||
send transmit timestamps captured after the actual transmission (e.g. when the
|
||||
server or the peer is running *chronyd* with HW timestamping enabled by the
|
||||
<<hwtimestamp,*hwtimestamp*>> directive). This can significantly improve the
|
||||
accuracy of the measurements.
|
||||
server or the peer is running *chronyd* with software (kernel) or hardware
|
||||
timestamping). This can significantly improve the accuracy of the measurements.
|
||||
+
|
||||
The interleaved mode is compatible with servers that support only the basic
|
||||
mode, but peers must both support and have enabled the interleaved mode,
|
||||
@@ -171,9 +176,12 @@ the interleaved mode requires the servers to keep some state for each client
|
||||
and the state might be dropped when there are too many clients (e.g.
|
||||
<<clientloglimit,*clientloglimit*>> is too small), or it might be overwritten
|
||||
by other clients that have the same IP address (e.g. computers behind NAT or
|
||||
someone sending requests with a spoofed source address). The *presend* option
|
||||
can be used to shorten the interval in which the server has to keep the state
|
||||
for this computer and be able to respond in the interleaved mode.
|
||||
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.
|
||||
*polltarget* _target_:::
|
||||
Target number of measurements to use for the regression algorithm which
|
||||
*chronyd* will try to maintain by adjusting the polling interval between
|
||||
@@ -336,47 +344,56 @@ 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:
|
||||
+
|
||||
*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).
|
||||
:::
|
||||
+
|
||||
Examples:
|
||||
+
|
||||
----
|
||||
refclock SHM 1 poll 3 refid GPS1
|
||||
refclock SHM 0 poll 3 refid GPS1
|
||||
refclock SHM 1:perm=0644 refid GPS2
|
||||
----
|
||||
+
|
||||
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 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*].
|
||||
+
|
||||
*SOCK*:::
|
||||
Unix domain socket driver. It is similar to the SHM driver, but samples are
|
||||
received from a Unix domain socket instead of shared memory and the messages
|
||||
@@ -396,17 +413,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*]. 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:
|
||||
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 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
|
||||
----
|
||||
+
|
||||
::
|
||||
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
|
||||
@@ -439,6 +483,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
|
||||
prefered 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.
|
||||
@@ -450,9 +505,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.
|
||||
@@ -533,19 +587,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:
|
||||
+
|
||||
@@ -557,11 +610,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
|
||||
@@ -643,8 +691,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
|
||||
@@ -727,8 +776,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
|
||||
@@ -783,15 +832,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.
|
||||
+
|
||||
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.
|
||||
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 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:
|
||||
+
|
||||
@@ -863,7 +920,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.
|
||||
@@ -898,14 +955,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]]
|
||||
@@ -993,7 +1054,7 @@ both a client of its servers, and a server to other clients.
|
||||
Examples of the use of the directive are as follows:
|
||||
+
|
||||
----
|
||||
allow foo.example.net
|
||||
allow 1.2.3.4
|
||||
allow 1.2
|
||||
allow 3.4.5
|
||||
allow 6.7.8/22
|
||||
@@ -1004,7 +1065,8 @@ allow ::/0
|
||||
allow
|
||||
----
|
||||
+
|
||||
The first directive allows the named node to be an NTP client of this computer.
|
||||
The first directive allows a node with IPv4 address _1.2.3.4_ to be an NTP
|
||||
client of this computer.
|
||||
The second directive allows any node with an IPv4 address of the form _1.2.x.y_
|
||||
(with _x_ and _y_ arbitrary) to be an NTP client of this computer. Likewise,
|
||||
the third directive allows any node with an IPv4 address of the form _3.4.5.x_
|
||||
@@ -1045,6 +1107,10 @@ Within a configuration file this capability is probably rather moot; however,
|
||||
it is of greater use for reconfiguration at run-time via *chronyc* with the
|
||||
<<chronyc.adoc#allow,*allow all*>> command.
|
||||
+
|
||||
The directive allows a hostname to be specified instead of an IP address, but
|
||||
the name must be resolvable when *chronyd* is started (i.e. *chronyd* needs
|
||||
to be started when the network is already up and DNS is working).
|
||||
+
|
||||
Note, if the <<initstepslew,*initstepslew*>> directive is used in the
|
||||
configuration file, each of the computers listed in that directive must allow
|
||||
client access by this computer for it to work.
|
||||
@@ -1237,7 +1303,10 @@ in any order):
|
||||
*interval*:::
|
||||
This option sets the minimum interval between responses. It is defined as a
|
||||
power of 2 in seconds. The default value is 3 (8 seconds). The minimum value
|
||||
is -4 and the maximum value is 12.
|
||||
is -19 (524288 packets per second) and the maximum value is 12 (one packet per
|
||||
4096 seconds). Note that with values below -4 the rate limiting is coarse
|
||||
(responses are allowed in bursts, even if the interval between them is shorter
|
||||
than the specified interval).
|
||||
*burst*:::
|
||||
This option sets the maximum number of responses that can be sent in a burst,
|
||||
temporarily exceeding the limit specified by the *interval* option. This is
|
||||
@@ -1249,20 +1318,20 @@ This option sets the rate at which responses are randomly allowed even if the
|
||||
limits specified by the *interval* and *burst* options are exceeded. This is
|
||||
necessary to prevent an attacker who is sending requests with a spoofed
|
||||
source address from completely blocking responses to that address. The leak
|
||||
rate is defined as a power of 1/2 and it is 3 by default, i.e. on average at
|
||||
least every eighth request has a response. The minimum value is 1 and the
|
||||
rate is defined as a power of 1/2 and it is 2 by default, i.e. on average at
|
||||
least every fourth request has a response. The minimum value is 1 and the
|
||||
maximum value is 4.
|
||||
::
|
||||
+
|
||||
An example use of the directive is:
|
||||
+
|
||||
----
|
||||
ratelimit interval 4 burst 4
|
||||
ratelimit interval 1 burst 16
|
||||
----
|
||||
+
|
||||
This would reduce the response rate for IP addresses that send packets on
|
||||
average more frequently than once per 16 seconds or send packets in bursts
|
||||
of more than 4 packets.
|
||||
This would reduce the response rate for IP addresses sending packets on average
|
||||
more than once per 2 seconds, or sending packets in bursts of more than 16
|
||||
packets, by up to 75% (with default *leak* of 2).
|
||||
|
||||
[[smoothtime]]*smoothtime* _max-freq_ _max-wander_ [*leaponly*]::
|
||||
The *smoothtime* directive can be used to enable smoothing of the time that
|
||||
@@ -1391,8 +1460,8 @@ need to be run with the *-p 257* switch to inter-operate correctly.)
|
||||
[[cmdratelimit]]*cmdratelimit* [_option_]...::
|
||||
This directive enables response rate limiting for command packets. It is
|
||||
similar to the <<ratelimit,*ratelimit*>> directive, except responses to
|
||||
localhost are never limited and the default interval is 1 (2 seconds), the default
|
||||
burst is 16, and the default leak rate is 2.
|
||||
localhost are never limited and the default interval is -4 (16 packets per
|
||||
second).
|
||||
+
|
||||
An example of the use of the directive is:
|
||||
+
|
||||
@@ -1501,10 +1570,12 @@ The log files are written to the directory specified by the <<logdir,*logdir*>>
|
||||
directive. A banner is periodically written to the files to indicate the
|
||||
meanings of the columns.
|
||||
+
|
||||
*measurements*:::
|
||||
*rawmeasurements*:::
|
||||
This option logs the raw NTP measurements and related information to a file
|
||||
called _measurements.log_. An example line (which actually appears as a single
|
||||
line in the file) from the log file is shown below.
|
||||
called _measurements.log_. An entry is made for each packet received from the
|
||||
source. This can be useful when debugging a problem. An example line (which
|
||||
actually appears as a single line in the file) from the log file is shown
|
||||
below.
|
||||
+
|
||||
----
|
||||
2016-11-09 05:40:50 203.0.113.15 N 2 111 111 1111 10 10 1.0 \
|
||||
@@ -1546,6 +1617,12 @@ from the example line above):
|
||||
. Source of the local receive timestamp
|
||||
(_D_=daemon, _K_=kernel, _H_=hardware). [K]
|
||||
+
|
||||
*measurements*:::
|
||||
This option is identical to the *rawmeasurements* option, except it logs only
|
||||
valid measurements from synchronised sources, i.e. measurements which passed
|
||||
the RFC 5905 tests 1 through 7. This can be useful for producing graphs of the
|
||||
source's performance.
|
||||
+
|
||||
*statistics*:::
|
||||
This option logs information about the regression processing to a file called
|
||||
_statistics.log_. An example line (which actually appears as a single line in
|
||||
@@ -1772,37 +1849,81 @@ sendmail binary.
|
||||
|
||||
=== Miscellaneous
|
||||
|
||||
[[hwtimestamp]]*hwtimestamp* _interface_::
|
||||
[[hwtimestamp]]*hwtimestamp* _interface_ [_option_]...::
|
||||
This directive enables hardware timestamping of NTP packets sent to and
|
||||
received from the specified network interface. The network interface controller
|
||||
(NIC) uses its own clock to accurately timestamp the actual transmissions and
|
||||
receptions, avoiding processing and queueing delays in the kernel, network
|
||||
driver, and hardware. This can significantly improve the accuracy of the
|
||||
timestamps and the measured offset, which is used for synchronisation of the
|
||||
system clock. In order to get best results, it is necessary to enable HW
|
||||
timestamping on both sides receiving and sending the packets (i.e. server and
|
||||
client, or both peers), and also enable the interleaved mode with the *xleave*
|
||||
option in the <<server,*server*>> or the <<peer,*peer*>> directive.
|
||||
system clock. In order to get the best results, both sides receiving and
|
||||
sending NTP packets (i.e. server and client, or two peers) need to use HW
|
||||
timestamping. If the server or peer supports the interleaved mode, it needs to
|
||||
be enabled by the *xleave* option in the <<server,*server*>> or the
|
||||
<<peer,*peer*>> directive.
|
||||
+
|
||||
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
|
||||
modes should include _HWTSTAMP_FILTER_ALL_ or _HWTSTAMP_FILTER_NTP_ALL_. 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. With both hardware and software timestamping there are some
|
||||
limitations on which timestamps can be actually used, 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
|
||||
hardware timestamping of packets received from bridges, bonds, and other
|
||||
virtual interfaces, works only on Linux 4.13 and newer. The source of
|
||||
timestamps (i.e. hardware, kernel, or daemon) is indicated in the
|
||||
_measurements.log_ file if enabled by the <<log,*log measurements*>> directive,
|
||||
and the <<chronyc.adoc#ntpdata,*ntpdata*>> report in *chronyc*.
|
||||
+
|
||||
An example of the directive is:
|
||||
If the specified interface is _*_, *chronyd* will try to enable HW timestamping
|
||||
on all available interfaces.
|
||||
+
|
||||
The *hwtimestamp* directive has the following options:
|
||||
+
|
||||
*minpoll* _poll_:::
|
||||
This option specifies the minimum interval between readings of the NIC clock.
|
||||
It's defined as a power of two. It should correspond to the minimum polling
|
||||
interval of all NTP sources and the minimum expected polling interval of NTP
|
||||
clients. The default value is 0 (1 second) and the minimum value is -6 (1/64th
|
||||
of a second).
|
||||
*precision* _precision_:::
|
||||
This option specifies the assumed precision of reading of the NIC clock. The
|
||||
default value is 100e-9 (100 nanoseconds).
|
||||
*txcomp* _compensation_:::
|
||||
This option specifies the difference in seconds between the actual transmission
|
||||
time at the physical layer and the reported transmit timestamp. This value will
|
||||
be added to transmit timestamps obtained from the NIC. The default value is 0.
|
||||
*rxcomp* _compensation_:::
|
||||
This option specifies the difference in seconds between the reported receive
|
||||
timestamp and the actual reception time at the physical layer. This value will
|
||||
be subtracted from receive timestamps obtained from the NIC. The default value
|
||||
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. Possible values are:
|
||||
_all_, _ntp_, and _none_. The default value is _ntp_, which enables
|
||||
timestamping of NTP packets (_HWTSTAMP_FILTER_NTP_ALL_) if it is supported, or
|
||||
timestamping of all packets (_HWTSTAMP_FILTER_ALL_). Setting *rxfilter* to
|
||||
_all_ forces timestamping of all packets, which can be useful when the NIC
|
||||
supports both filters and NTP packets are received from or on a non-standard
|
||||
UDP port (e.g. specified by the *port* directive). Setting *rxfilter* to _none_
|
||||
disables receive HW timestamping and allows transmit HW timestamping to be
|
||||
enabled when the NIC supports only PTP-specific receive filters.
|
||||
::
|
||||
+
|
||||
Examples of the directive are:
|
||||
+
|
||||
----
|
||||
hwtimestamp eth0
|
||||
hwtimestamp eth1 txcomp 300e-9 rxcomp 645e-9
|
||||
hwtimestamp *
|
||||
----
|
||||
|
||||
[[include]]*include* _pattern_::
|
||||
@@ -2122,8 +2243,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
|
||||
@@ -2176,7 +2296,6 @@ log statistics measurements tracking
|
||||
driftfile @CHRONYVARDIR@/drift
|
||||
makestep 1.0 3
|
||||
maxupdateskew 100.0
|
||||
dumponexit
|
||||
dumpdir @CHRONYVARDIR@
|
||||
rtcfile @CHRONYVARDIR@/rtc
|
||||
----
|
||||
@@ -2211,27 +2330,36 @@ information to be saved.
|
||||
*chronyd* can be configured to operate as a public NTP server, e.g. to join the
|
||||
http://www.pool.ntp.org/en/join.html[pool.ntp.org] project. The configuration
|
||||
is similar to the NTP client with permanent connection, except it needs to
|
||||
allow client access from all addresses. It is recommended to handpick at least
|
||||
few good servers, and possibly combine them with a random selection of other
|
||||
servers in the pool. Rate limiting can be enabled to not waste too much
|
||||
bandwidth on misconfigured and broken NTP clients. The *-r* option with the
|
||||
*dumpdir* directive shortens the time for which *chronyd* will not serve time
|
||||
to its clients when it needs to be restarted for any reason.
|
||||
allow client access from all addresses. It is recommended to find at least four
|
||||
good servers (e.g. from the pool, or on the NTP homepage). If the server has a
|
||||
hardware reference clock (e.g. a GPS receiver), it can be specified by the
|
||||
<<refclock,*refclock*>> directive.
|
||||
|
||||
The configuration file might be:
|
||||
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
|
||||
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
|
||||
restarted (e.g. after upgrading to a newer version, or a change in the
|
||||
configuration).
|
||||
|
||||
The configuration file could look like:
|
||||
|
||||
----
|
||||
server foo.example.net iburst
|
||||
server bar.example.net iburst
|
||||
server baz.example.net iburst
|
||||
pool pool.ntp.org iburst
|
||||
server qux.example.net iburst
|
||||
makestep 1.0 3
|
||||
rtcsync
|
||||
allow
|
||||
ratelimit interval 2 burst 10
|
||||
clientloglimit 100000000
|
||||
leapsectz right/UTC
|
||||
driftfile @CHRONYVARDIR@/drift
|
||||
dumpdir @CHRONYRUNDIR@
|
||||
dumponexit
|
||||
----
|
||||
|
||||
== SEE ALSO
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// This file is part of chrony
|
||||
//
|
||||
// Copyright (C) Richard P. Curnow 1997-2003
|
||||
// Copyright (C) Stephen Wadeley 2016
|
||||
// Copyright (C) Miroslav Lichvar 2009-2016
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
@@ -129,15 +130,15 @@ performance. An example of the output is shown below.
|
||||
----
|
||||
Reference ID : CB00710F (foo.example.net)
|
||||
Stratum : 3
|
||||
Ref time (UTC) : Fri Feb 3 15:00:29 2012
|
||||
System time : 0.000001501 seconds slow of NTP time
|
||||
Last offset : -0.000001632 seconds
|
||||
RMS offset : 0.000002360 seconds
|
||||
Frequency : 331.898 ppm fast
|
||||
Residual freq : 0.004 ppm
|
||||
Skew : 0.154 ppm
|
||||
Root delay : 0.373169 seconds
|
||||
Root dispersion : 0.024780 seconds
|
||||
Ref time (UTC) : Fri Jan 27 09:49:17 2017
|
||||
System time : 0.000006523 seconds slow of NTP time
|
||||
Last offset : -0.000006747 seconds
|
||||
RMS offset : 0.000035822 seconds
|
||||
Frequency : 3.225 ppm slow
|
||||
Residual freq : -0.000 ppm
|
||||
Skew : 0.129 ppm
|
||||
Root delay : 0.013639022 seconds
|
||||
Root dispersion : 0.001100737 seconds
|
||||
Update interval : 64.2 seconds
|
||||
Leap status : Normal
|
||||
----
|
||||
@@ -186,9 +187,6 @@ The '`frequency`' is the rate by which the system's clock would be wrong if
|
||||
For example, a value of 1 ppm would mean that when the system's clock thinks it
|
||||
has advanced 1 second, it has actually advanced by 1.000001 seconds relative to
|
||||
true time.
|
||||
+
|
||||
As you can see in the example, the clock in the computer is not a very
|
||||
good one; it would gain about 30 seconds per day if it was not corrected!
|
||||
*Residual freq*:::
|
||||
This shows the '`residual frequency`' for the currently selected reference
|
||||
source. This reflects any difference between what the measurements from the
|
||||
@@ -441,10 +439,10 @@ the offline state.
|
||||
the name of the server or peer was not resolved to an address yet; this source is
|
||||
not visible in the *sources* and *sourcestats* reports.
|
||||
|
||||
[[ntpdata]]*ntpdata* _address_::
|
||||
[[ntpdata]]*ntpdata* [_address_]::
|
||||
The *ntpdata* command displays the last valid measurement and other
|
||||
NTP-specific information about the NTP source. An example of the output is
|
||||
shown below.
|
||||
NTP-specific information about the specified NTP source, or all NTP sources if
|
||||
no address was specified. An example of the output is shown below.
|
||||
+
|
||||
----
|
||||
Remote address : 203.0.113.15 (CB00710F)
|
||||
@@ -454,11 +452,11 @@ Leap status : Normal
|
||||
Version : 4
|
||||
Mode : Server
|
||||
Stratum : 1
|
||||
Poll : 10
|
||||
Precision : 0.000000060 seconds
|
||||
Poll interval : 10 (1024 seconds)
|
||||
Precision : -24 (0.000000060 seconds)
|
||||
Root delay : 0.000015 seconds
|
||||
Root dispersion : 0.000015 seconds
|
||||
Reference ID : 50505331
|
||||
Reference ID : 47505300 (GPS)
|
||||
Reference time : Fri Nov 25 15:22:12 2016
|
||||
Offset : -0.000060878 seconds
|
||||
Peer delay : 0.000175634 seconds
|
||||
@@ -489,7 +487,7 @@ reference ID.
|
||||
*Version*:::
|
||||
*Mode*:::
|
||||
*Stratum*:::
|
||||
*Poll*:::
|
||||
*Poll interval*:::
|
||||
*Precision*:::
|
||||
*Root delay*:::
|
||||
*Root dispersion*:::
|
||||
@@ -1120,17 +1118,15 @@ 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
|
||||
configuration file by the <<chrony.conf.adoc#keyfile,*keyfile*>> directive.
|
||||
|
||||
=== Client commands
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
53
doc/faq.adoc
53
doc/faq.adoc
@@ -79,7 +79,7 @@ rtcsync
|
||||
|
||||
You need to add an `allow` directive to the _chrony.conf_ file in order to open
|
||||
the NTP port and allow `chronyd` to reply to client requests. `allow` with no
|
||||
specified subnet allows all IPv4 and IPv6 addresses.
|
||||
specified subnet allows access from all IPv4 and IPv6 addresses.
|
||||
|
||||
=== I have several computers on a LAN. Should be all clients of an external server?
|
||||
|
||||
@@ -97,7 +97,7 @@ _chrony.conf_ file. This configuration will be better because
|
||||
No. Starting from version 1.25, `chronyd` will keep trying to resolve
|
||||
the names specified by the `server`, `pool`, and `peer` directives in an
|
||||
increasing interval until it succeeds. The `online` command can be issued from
|
||||
`chronyc` to try to resolve them immediately.
|
||||
`chronyc` to force `chronyd` to try to resolve the names immediately.
|
||||
|
||||
=== How can I make `chronyd` more secure?
|
||||
|
||||
@@ -161,7 +161,7 @@ The first three options set the minimum and maximum allowed polling interval,
|
||||
and how should be the actual interval adjusted in the specified range. Their
|
||||
default values are 6 (64 seconds) for `minpoll`, 10 (1024 seconds) for
|
||||
`maxpoll` and 8 (samples) for `polltarget`. The default values should be used
|
||||
for general servers on the Internet. With your own NTP servers or if have
|
||||
for general servers on the Internet. With your own NTP servers, or if you have
|
||||
permission to poll some servers more frequently, setting these options for
|
||||
shorter polling intervals may significantly improve the accuracy of the system
|
||||
clock.
|
||||
@@ -195,15 +195,27 @@ server ntp.local minpoll 2 maxpoll 4 polltarget 30 maxdelaydevratio 2
|
||||
----
|
||||
|
||||
If your server supports the interleaved mode, the `xleave` option should be
|
||||
added to the `server` directive in order to receive server's more accurate
|
||||
hardware or kernel transmit timestamps. When combined with local hardware
|
||||
timestamping, a sub-microsecond accuracy may be possible. An example could be
|
||||
added to the `server` directive in order to allow the server to send the
|
||||
client more accurate hardware or kernel transmit timestamps. When combined with
|
||||
local hardware timestamping, sub-microsecond accuracy may be possible. An
|
||||
example could be
|
||||
|
||||
----
|
||||
server ntp.local minpoll 2 maxpoll 2 xleave
|
||||
hwtimestamp eth0
|
||||
----
|
||||
|
||||
=== Does `chronyd` have an ntpdate mode?
|
||||
|
||||
Yes. With the `-q` option `chronyd` will set the system clock once and exit.
|
||||
With the `-Q` option it will print the measured offset without setting the
|
||||
clock. If you don't want to use a configuration file, NTP servers can be
|
||||
specified on the command line. For example:
|
||||
|
||||
----
|
||||
# chronyd -q 'pool pool.ntp.org iburst'
|
||||
----
|
||||
|
||||
=== What happened to the `commandkey` and `generatecommandkey` directives?
|
||||
|
||||
They were removed in version 2.2. Authentication is no longer supported in the
|
||||
@@ -242,8 +254,17 @@ MS Name/IP address Stratum Poll Reach LastRx Last sample
|
||||
=== Are NTP servers specified with the `offline` option?
|
||||
|
||||
Check that you're using ``chronyc``'s `online` and `offline` commands
|
||||
appropriately. Again, check in _measurements.log_ to see if you're getting any
|
||||
data back from the server.
|
||||
appropriately. The `activity` command prints the number of sources that are
|
||||
currently online and offline. For example:
|
||||
|
||||
----
|
||||
200 OK
|
||||
3 sources online
|
||||
0 sources offline
|
||||
0 sources doing burst (return to online)
|
||||
0 sources doing burst (return to offline)
|
||||
0 sources with unknown address
|
||||
----
|
||||
|
||||
=== Is `chronyd` allowed to step the system clock?
|
||||
|
||||
@@ -396,15 +417,15 @@ option for all time sources in the _chrony.conf_ file.
|
||||
|
||||
=== What happens if the network connection is dropped without using ``chronyc``'s `offline` command first?
|
||||
|
||||
`chronyd` will keep trying to access the server(s) that it thinks are online.
|
||||
When the network is connected again, it will take some time (on average half of
|
||||
the maximum polling interval) before new measurements are made and the clock is
|
||||
corrected. If the servers were set to offline and the `online` command was
|
||||
issued when the network was connected, `chronyd` would make new measurements
|
||||
immediately.
|
||||
`chronyd` will keep trying to access the sources that it thinks are online, and
|
||||
it will take longer before new measurements are actually made and the clock is
|
||||
corrected when the network is connected again. If the sources were set to
|
||||
offline, `chronyd` would make new measurements immediately after issuing the
|
||||
`online` command.
|
||||
|
||||
The `auto_offline` option to the `server` entry in the _chrony.conf_ file may
|
||||
be useful to switch the servers to the offline state automatically.
|
||||
Unless the network connection lasts only few minutes (less than the maximum
|
||||
polling interval), the delay is usually not a problem, and it may be acceptable
|
||||
to keep all sources online all the time.
|
||||
|
||||
== Operating systems
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
[Unit]
|
||||
Description=Wait for chrony to synchronize system clock
|
||||
Documentation=man:chronyc(1)
|
||||
After=chronyd.service
|
||||
Requires=chronyd.service
|
||||
Before=time-sync.target
|
||||
@@ -9,7 +10,7 @@ Wants=time-sync.target
|
||||
Type=oneshot
|
||||
# Wait up to ~10 minutes for chronyd to synchronize and the remaining
|
||||
# clock correction to be less than 0.1 seconds
|
||||
ExecStart=/usr/bin/chronyc waitsync 600 0.1 0.0 1
|
||||
ExecStart=/usr/bin/chronyc -h 127.0.0.1,::1 waitsync 600 0.1 0.0 1
|
||||
RemainAfterExit=yes
|
||||
StandardOutput=null
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ pool pool.ntp.org iburst
|
||||
# Record the rate at which the system clock gains/losses time.
|
||||
driftfile /var/lib/chrony/drift
|
||||
|
||||
# In first three updates step the system clock instead of slew
|
||||
# if the adjustment is larger than 1 second.
|
||||
# Allow the system clock to be stepped in the first three updates
|
||||
# if its offset is larger than 1 second.
|
||||
makestep 1.0 3
|
||||
|
||||
# Enable kernel synchronization of the real-time clock (RTC).
|
||||
|
||||
@@ -5,17 +5,24 @@ pool pool.ntp.org iburst
|
||||
# Record the rate at which the system clock gains/losses time.
|
||||
driftfile /var/lib/chrony/drift
|
||||
|
||||
# In first three updates step the system clock instead of slew
|
||||
# if the adjustment is larger than 1 second.
|
||||
# Allow the system clock to be stepped in the first three updates
|
||||
# if its offset is larger than 1 second.
|
||||
makestep 1.0 3
|
||||
|
||||
# Enable kernel synchronization of the real-time clock (RTC).
|
||||
rtcsync
|
||||
|
||||
# Allow NTP client access from local network.
|
||||
#allow 192.168/16
|
||||
# Enable hardware timestamping on all interfaces that support it.
|
||||
#hwtimestamp *
|
||||
|
||||
# Serve time even if not synchronized to any NTP server.
|
||||
# Increase the minimum number of selectable sources required to adjust
|
||||
# the system clock.
|
||||
#minsources 2
|
||||
|
||||
# Allow NTP client access from local network.
|
||||
#allow 192.168.0.0/16
|
||||
|
||||
# Serve time even if not synchronized to a time source.
|
||||
#local stratum 10
|
||||
|
||||
# Specify file containing keys for NTP authentication.
|
||||
|
||||
@@ -33,42 +33,30 @@
|
||||
|
||||
! pool pool.ntp.org iburst
|
||||
|
||||
# However, for dial-up use you probably want these instead. The word
|
||||
# 'offline' means that the server is not visible at boot time. Use
|
||||
# chronyc's 'online' command to tell chronyd that these servers have
|
||||
# become visible after you go on-line.
|
||||
|
||||
! server foo.example.net offline
|
||||
! server bar.example.net offline
|
||||
! server baz.example.net offline
|
||||
|
||||
! pool pool.ntp.org offline
|
||||
|
||||
# You may want to specify NTP 'peers' instead. If you run a network
|
||||
# with a lot of computers and want several computers running chrony to
|
||||
# have the 'front-line' interface to the public NTP servers, you can
|
||||
# 'peer' these machines together to increase robustness.
|
||||
|
||||
! peer foo.example.net
|
||||
|
||||
# There are other options to the 'server' and 'peer' directives that you
|
||||
# might want to use. For example, you can ignore measurements whose
|
||||
# round-trip-time is too large (indicating that the measurement is
|
||||
# probably useless, because you don't know which way the measurement
|
||||
# message got held up.) Consult the full documentation for details.
|
||||
|
||||
#######################################################################
|
||||
### AVOIDING POTENTIALLY BOGUS CHANGES TO YOUR CLOCK
|
||||
#
|
||||
# To avoid changes being made to your computer's gain/loss compensation
|
||||
# when the measurement history is too erratic, you might want to enable
|
||||
# one of the following lines. The first seems good for dial-up (or
|
||||
# other high-latency connections like slow leased lines), the second
|
||||
# seems OK for a LAN environment.
|
||||
# one of the following lines. The first seems good with servers on the
|
||||
# Internet, the second seems OK for a LAN environment.
|
||||
|
||||
! maxupdateskew 100
|
||||
! maxupdateskew 5
|
||||
|
||||
# If you want to increase the minimum number of selectable sources
|
||||
# required to update the system clock in order to make the
|
||||
# synchronisation more reliable, uncomment (and edit) the following
|
||||
# line.
|
||||
|
||||
! minsources 2
|
||||
|
||||
# If your computer has a good stable clock (e.g. it is not a virtual
|
||||
# machine), you might also want to reduce the maximum assumed drift
|
||||
# (frequency error) of the clock (the value is specified in ppm).
|
||||
|
||||
! maxdrift 100
|
||||
|
||||
#######################################################################
|
||||
### FILENAMES ETC
|
||||
# Chrony likes to keep information about your computer's clock in files.
|
||||
@@ -181,13 +169,12 @@ driftfile /var/lib/chrony/drift
|
||||
# machine accesses it. The information can be accessed by the 'clients'
|
||||
# command of chronyc. You can disable this facility by uncommenting the
|
||||
# following line. This will save a bit of memory if you have many
|
||||
# clients.
|
||||
# clients and it will also disable support for the interleaved mode.
|
||||
|
||||
! noclientlog
|
||||
|
||||
# The clientlog size is limited to 512KB by default. If you have many
|
||||
# clients, especially in many different subnets, you might want to
|
||||
# increase the limit.
|
||||
# clients, you might want to increase the limit.
|
||||
|
||||
! clientloglimit 4194304
|
||||
|
||||
@@ -196,7 +183,7 @@ driftfile /var/lib/chrony/drift
|
||||
# clients that are sending requests too frequently, uncomment and edit
|
||||
# the following line.
|
||||
|
||||
! limitrate interval 3 burst 8
|
||||
! ratelimit interval 3 burst 8
|
||||
|
||||
#######################################################################
|
||||
### REPORTING BIG CLOCK CHANGES
|
||||
@@ -243,7 +230,17 @@ driftfile /var/lib/chrony/drift
|
||||
# Rate limiting can be enabled also for command packets. (Note,
|
||||
# commands from localhost are never limited.)
|
||||
|
||||
! cmdratelimit interval 1 burst 16
|
||||
! cmdratelimit interval -4 burst 16
|
||||
|
||||
#######################################################################
|
||||
### HARDWARE TIMESTAMPING
|
||||
# On Linux, if the network interface controller and its driver support
|
||||
# hardware timestamping, it can significantly improve the accuracy of
|
||||
# synchronisation. It can be enabled on specified interfaces only, or it
|
||||
# can be enabled on all interfaces that support it.
|
||||
|
||||
! hwtimestamp eth0
|
||||
! hwtimestamp *
|
||||
|
||||
#######################################################################
|
||||
### REAL TIME CLOCK
|
||||
@@ -274,6 +271,12 @@ driftfile /var/lib/chrony/drift
|
||||
|
||||
! rtcdevice /dev/misc/rtc
|
||||
|
||||
# Alternatively, if not using the -s option, this directive can be used
|
||||
# to enable a mode in which the RTC is periodically set to the system
|
||||
# time, with no tracking of its drift.
|
||||
|
||||
! rtcsync
|
||||
|
||||
#######################################################################
|
||||
### REAL TIME SCHEDULER
|
||||
# This directive tells chronyd to use the real-time FIFO scheduler with the
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
[Unit]
|
||||
Description=NTP client/server
|
||||
Documentation=man:chronyd(8) man:chrony.conf(5)
|
||||
After=ntpdate.service sntp.service ntpd.service
|
||||
Conflicts=ntpd.service systemd-timesyncd.service
|
||||
ConditionCapability=CAP_SYS_TIME
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
PIDFile=/var/run/chronyd.pid
|
||||
EnvironmentFile=-/etc/sysconfig/chronyd
|
||||
ExecStart=/usr/sbin/chronyd $OPTIONS
|
||||
PrivateTmp=yes
|
||||
ProtectHome=yes
|
||||
ProtectSystem=full
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
31
hwclock.c
31
hwclock.c
@@ -39,9 +39,6 @@
|
||||
/* Maximum number of samples per clock */
|
||||
#define MAX_SAMPLES 16
|
||||
|
||||
/* Minimum interval between samples (in seconds) */
|
||||
#define MIN_SAMPLE_SEPARATION 1.0
|
||||
|
||||
struct HCL_Instance_Record {
|
||||
/* HW and local reference timestamp */
|
||||
struct timespec hw_ref;
|
||||
@@ -55,6 +52,12 @@ struct HCL_Instance_Record {
|
||||
/* Number of samples */
|
||||
int n_samples;
|
||||
|
||||
/* Maximum error of the last sample */
|
||||
double last_err;
|
||||
|
||||
/* Minimum interval between samples */
|
||||
double min_separation;
|
||||
|
||||
/* Flag indicating the offset and frequency values are valid */
|
||||
int valid_coefs;
|
||||
|
||||
@@ -83,7 +86,7 @@ handle_slew(struct timespec *raw, struct timespec *cooked, double dfreq,
|
||||
/* ================================================== */
|
||||
|
||||
HCL_Instance
|
||||
HCL_CreateInstance(void)
|
||||
HCL_CreateInstance(double min_separation)
|
||||
{
|
||||
HCL_Instance clock;
|
||||
|
||||
@@ -92,6 +95,7 @@ HCL_CreateInstance(void)
|
||||
clock->y_data[MAX_SAMPLES - 1] = 0.0;
|
||||
clock->n_samples = 0;
|
||||
clock->valid_coefs = 0;
|
||||
clock->min_separation = min_separation;
|
||||
|
||||
LCL_AddParameterChangeHandler(handle_slew, clock);
|
||||
|
||||
@@ -112,7 +116,7 @@ int
|
||||
HCL_NeedsNewSample(HCL_Instance clock, struct timespec *now)
|
||||
{
|
||||
if (!clock->n_samples ||
|
||||
fabs(UTI_DiffTimespecsToDouble(now, &clock->local_ref)) >= MIN_SAMPLE_SEPARATION)
|
||||
fabs(UTI_DiffTimespecsToDouble(now, &clock->local_ref)) >= clock->min_separation)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
@@ -137,9 +141,9 @@ HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
|
||||
hw_delta = UTI_DiffTimespecsToDouble(hw_ts, &clock->hw_ref);
|
||||
local_delta = UTI_DiffTimespecsToDouble(local_ts, &clock->local_ref) / local_freq;
|
||||
|
||||
if (hw_delta <= 0.0 || local_delta < MIN_SAMPLE_SEPARATION / 2.0) {
|
||||
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++) {
|
||||
@@ -151,16 +155,17 @@ HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
|
||||
clock->n_samples++;
|
||||
clock->hw_ref = *hw_ts;
|
||||
clock->local_ref = *local_ts;
|
||||
clock->last_err = err;
|
||||
|
||||
/* Get new coefficients */
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -172,12 +177,12 @@ HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
|
||||
/* 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);
|
||||
DEBUG_LOG("HW clock reset offset=%e", clock->offset);
|
||||
clock->offset = 0.0;
|
||||
clock->n_samples = 1;
|
||||
}
|
||||
|
||||
DEBUG_LOG(LOGF_HwClocks, "HW clock samples=%d offset=%e freq=%.9e raw_freq=%.9e err=%e ref_diff=%e",
|
||||
DEBUG_LOG("HW clock samples=%d offset=%e freq=%.9e raw_freq=%.9e err=%e ref_diff=%e",
|
||||
clock->n_samples, clock->offset, clock->frequency, raw_freq, err,
|
||||
UTI_DiffTimespecsToDouble(&clock->hw_ref, &clock->local_ref));
|
||||
}
|
||||
@@ -196,9 +201,9 @@ HCL_CookTime(HCL_Instance clock, struct timespec *raw, struct timespec *cooked,
|
||||
offset = clock->offset + elapsed / clock->frequency;
|
||||
UTI_AddDoubleToTimespec(&clock->local_ref, offset, cooked);
|
||||
|
||||
/* Estimation of the error is not implemented yet */
|
||||
/* Fow now, just return the error of the last sample */
|
||||
if (err)
|
||||
*err = 0.0;
|
||||
*err = clock->last_err;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
typedef struct HCL_Instance_Record *HCL_Instance;
|
||||
|
||||
/* Create a new HW clock instance */
|
||||
extern HCL_Instance HCL_CreateInstance(void);
|
||||
extern HCL_Instance HCL_CreateInstance(double min_separation);
|
||||
|
||||
/* Destroy a HW clock instance */
|
||||
extern void HCL_DestroyInstance(HCL_Instance clock);
|
||||
|
||||
12
keys.c
12
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 */
|
||||
|
||||
24
local.c
24
local.c
@@ -144,7 +144,9 @@ calculate_sys_precision(void)
|
||||
best *= 2;
|
||||
}
|
||||
|
||||
DEBUG_LOG(LOGF_Local, "Clock precision %.9f (%d)", precision_quantum, precision_log);
|
||||
assert(precision_log >= -30);
|
||||
|
||||
DEBUG_LOG("Clock precision %.9f (%d)", precision_quantum, precision_log);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -356,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
|
||||
@@ -424,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);
|
||||
}
|
||||
@@ -438,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;
|
||||
}
|
||||
|
||||
@@ -544,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;
|
||||
}
|
||||
|
||||
@@ -611,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 */
|
||||
@@ -658,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);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -682,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;
|
||||
}
|
||||
@@ -698,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
9
local.h
9
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
|
||||
|
||||
4
localp.h
4
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);
|
||||
|
||||
32
logging.c
32
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
|
||||
}
|
||||
|
||||
@@ -174,6 +177,21 @@ 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);
|
||||
|
||||
file_log = f;
|
||||
}
|
||||
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
@@ -241,7 +259,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 +267,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;
|
||||
}
|
||||
|
||||
68
logging.h
68
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);
|
||||
|
||||
|
||||
285
main.c
285
main.c
@@ -4,7 +4,7 @@
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) John G. Hasler 2009
|
||||
* Copyright (C) Miroslav Lichvar 2012-2015
|
||||
* Copyright (C) Miroslav Lichvar 2012-2016
|
||||
*
|
||||
* 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];
|
||||
@@ -325,7 +318,8 @@ go_daemon(void)
|
||||
if (r) {
|
||||
if (r > 0) {
|
||||
/* Print the error message from the child */
|
||||
fprintf(stderr, "%.1024s\n", message);
|
||||
message[sizeof (message) - 1] = '\0';
|
||||
fprintf(stderr, "%s\n", message);
|
||||
}
|
||||
exit(1);
|
||||
} else
|
||||
@@ -339,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 {
|
||||
@@ -347,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
|
||||
@@ -364,142 +358,171 @@ 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':
|
||||
case 'Q':
|
||||
ref_mode = opt == 'q' ? REF_ModeUpdateOnce : 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();
|
||||
@@ -528,13 +551,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();
|
||||
@@ -563,7 +586,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) {
|
||||
@@ -576,7 +599,7 @@ int main
|
||||
the scheduler. */
|
||||
SCH_MainLoop();
|
||||
|
||||
LOG(LOGS_INFO, LOGF_Main, "chronyd exiting");
|
||||
LOG(LOGS_INFO, "chronyd exiting");
|
||||
|
||||
MAI_CleanupAndExit();
|
||||
|
||||
|
||||
46
manual.c
46
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;
|
||||
|
||||
|
||||
2
manual.h
2
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);
|
||||
|
||||
6
memory.c
6
memory.c
@@ -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,7 +49,7 @@ 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;
|
||||
}
|
||||
@@ -61,7 +61,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;
|
||||
}
|
||||
|
||||
@@ -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,14 +110,17 @@ 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]);
|
||||
UTI_FdSetCloexec(inst->pipe[1]);
|
||||
|
||||
resolving_threads++;
|
||||
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);
|
||||
|
||||
3
ntp.h
3
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
|
||||
|
||||
|
||||
533
ntp_core.c
533
ntp_core.c
File diff suppressed because it is too large
Load Diff
84
ntp_io.c
84
ntp_io.c
@@ -4,7 +4,7 @@
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Timo Teras 2009
|
||||
* Copyright (C) Miroslav Lichvar 2009, 2013-2015
|
||||
* Copyright (C) Miroslav Lichvar 2009, 2013-2016
|
||||
*
|
||||
* 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
|
||||
@@ -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)
|
||||
#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 */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Enable kernel/HW timestamping of packets */
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
NIO_Linux_SetTimestampSocketOptions(sock_fd, client_only, &events);
|
||||
if (!NIO_Linux_SetTimestampSocketOptions(sock_fd, client_only, &events))
|
||||
#endif
|
||||
#ifdef SO_TIMESTAMPNS
|
||||
if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPNS, (char *)&on_off, sizeof(on_off)) < 0)
|
||||
#endif
|
||||
#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;
|
||||
@@ -364,8 +361,11 @@ NIO_Initialise(int family)
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
NIO_Linux_Initialise();
|
||||
#else
|
||||
if (ARR_GetSize(CNF_GetHwTsInterfaces()))
|
||||
LOG_FATAL(LOGF_NtpIO, "HW timestamping not supported");
|
||||
if (1) {
|
||||
CNF_HwTsInterface *conf_iface;
|
||||
if (CNF_GetHwTsInterface(0, &conf_iface))
|
||||
LOG_FATAL("HW timestamping not supported");
|
||||
}
|
||||
#endif
|
||||
|
||||
recv_messages = ARR_CreateInstance(sizeof (struct Message));
|
||||
@@ -427,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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,14 +575,13 @@ process_message(struct msghdr *hdr, int length, int sock_fd)
|
||||
NTP_Local_Timestamp local_ts;
|
||||
struct timespec sched_ts;
|
||||
struct cmsghdr *cmsg;
|
||||
int if_index;
|
||||
|
||||
SCH_GetLastEventTime(&local_ts.ts, &local_ts.err, NULL);
|
||||
local_ts.source = NTP_TS_DAEMON;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -595,17 +594,17 @@ process_message(struct msghdr *hdr, int length, int sock_fd)
|
||||
}
|
||||
|
||||
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||
local_addr.if_index = INVALID_IF_INDEX;
|
||||
local_addr.sock_fd = sock_fd;
|
||||
if_index = -1;
|
||||
|
||||
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 */
|
||||
}
|
||||
|
||||
@@ -617,7 +616,7 @@ process_message(struct msghdr *hdr, int length, int sock_fd)
|
||||
memcpy(&ipi, CMSG_DATA(cmsg), sizeof(ipi));
|
||||
local_addr.ip_addr.addr.in4 = ntohl(ipi.ipi_addr.s_addr);
|
||||
local_addr.ip_addr.family = IPADDR_INET4;
|
||||
if_index = ipi.ipi_ifindex;
|
||||
local_addr.if_index = ipi.ipi_ifindex;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -629,7 +628,7 @@ process_message(struct msghdr *hdr, int length, int sock_fd)
|
||||
memcpy(&local_addr.ip_addr.addr.in6, &ipi.ipi6_addr.s6_addr,
|
||||
sizeof (local_addr.ip_addr.addr.in6));
|
||||
local_addr.ip_addr.family = IPADDR_INET6;
|
||||
if_index = ipi.ipi6_ifindex;
|
||||
local_addr.if_index = ipi.ipi6_ifindex;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -657,14 +656,13 @@ process_message(struct msghdr *hdr, int length, int sock_fd)
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
if (NIO_Linux_ProcessMessage(&remote_addr, &local_addr, &local_ts,
|
||||
hdr, length, sock_fd, if_index))
|
||||
if (NIO_Linux_ProcessMessage(&remote_addr, &local_addr, &local_ts, hdr, length))
|
||||
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, if_index,
|
||||
UTI_IPToString(&local_addr.ip_addr), local_addr.sock_fd, local_addr.if_index,
|
||||
local_ts.source, UTI_DiffTimespecsToDouble(&sched_ts, &local_ts.ts));
|
||||
|
||||
/* Just ignore the packet if it's not of a recognized length */
|
||||
@@ -711,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;
|
||||
}
|
||||
@@ -742,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;
|
||||
}
|
||||
@@ -818,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);
|
||||
|
||||
|
||||
349
ntp_io_linux.c
349
ntp_io_linux.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
|
||||
@@ -28,10 +28,10 @@
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include <ifaddrs.h>
|
||||
#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>
|
||||
|
||||
@@ -60,17 +60,30 @@ struct Interface {
|
||||
char name[IF_NAMESIZE];
|
||||
int if_index;
|
||||
int phc_fd;
|
||||
int phc_mode;
|
||||
int phc_nocrossts;
|
||||
/* Link speed in mbit/s */
|
||||
int link_speed;
|
||||
/* Start of UDP data at layer 2 for IPv4 and IPv6 */
|
||||
int l2_udp4_ntp_start;
|
||||
int l2_udp6_ntp_start;
|
||||
/* Precision of PHC readings */
|
||||
double precision;
|
||||
/* Compensation of errors in TX and RX timestamping */
|
||||
double tx_comp;
|
||||
double rx_comp;
|
||||
HCL_Instance clock;
|
||||
};
|
||||
|
||||
/* Number of PHC readings per HW clock sample */
|
||||
#define PHC_READINGS 10
|
||||
|
||||
/* Minimum interval between PHC readings */
|
||||
#define MIN_PHC_POLL -6
|
||||
|
||||
/* Maximum acceptable offset between HW and daemon/kernel timestamp */
|
||||
#define MAX_TS_DELAY 1.0
|
||||
|
||||
/* Array of Interfaces */
|
||||
static ARR_Instance interfaces;
|
||||
|
||||
@@ -84,14 +97,20 @@ static int permanent_ts_options;
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
add_interface(const char *name)
|
||||
add_interface(CNF_HwTsInterface *conf_iface)
|
||||
{
|
||||
struct ethtool_ts_info ts_info;
|
||||
struct hwtstamp_config ts_config;
|
||||
struct ifreq req;
|
||||
int sock_fd, if_index, phc_index, phc_fd;
|
||||
int sock_fd, if_index, phc_fd, req_hwts_flags;
|
||||
unsigned int i;
|
||||
struct Interface *iface;
|
||||
char phc_path[64];
|
||||
|
||||
/* Check if the interface was not already added */
|
||||
for (i = 0; i < ARR_GetSize(interfaces); i++) {
|
||||
if (!strcmp(conf_iface->name, ((struct Interface *)ARR_GetElement(interfaces, i))->name))
|
||||
return 1;
|
||||
}
|
||||
|
||||
sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock_fd < 0)
|
||||
@@ -100,13 +119,14 @@ add_interface(const char *name)
|
||||
memset(&req, 0, sizeof (req));
|
||||
memset(&ts_info, 0, sizeof (ts_info));
|
||||
|
||||
if (snprintf(req.ifr_name, sizeof (req.ifr_name), "%s", name) >= sizeof (req.ifr_name)) {
|
||||
if (snprintf(req.ifr_name, sizeof (req.ifr_name), "%s", conf_iface->name) >=
|
||||
sizeof (req.ifr_name)) {
|
||||
close(sock_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -117,54 +137,107 @@ add_interface(const char *name)
|
||||
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;
|
||||
}
|
||||
|
||||
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("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_NONE:
|
||||
ts_config.rx_filter = HWTSTAMP_FILTER_NONE;
|
||||
break;
|
||||
case CNF_HWTS_RXFILTER_NTP:
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP
|
||||
if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_NTP_ALL)) {
|
||||
ts_config.rx_filter = HWTSTAMP_FILTER_NTP_ALL;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
/* Fall through */
|
||||
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;
|
||||
}
|
||||
|
||||
close(sock_fd);
|
||||
phc_index = ts_info.phc_index;
|
||||
|
||||
if (snprintf(phc_path, sizeof (phc_path), "/dev/ptp%d", phc_index) >= sizeof (phc_path))
|
||||
phc_fd = SYS_Linux_OpenPHC(NULL, ts_info.phc_index);
|
||||
if (phc_fd < 0)
|
||||
return 0;
|
||||
|
||||
phc_fd = open(phc_path, O_RDONLY);
|
||||
if (phc_fd < 0) {
|
||||
LOG(LOGS_ERR, LOGF_NtpIOLinux, "Could not open %s : %s", phc_path, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
UTI_FdSetCloexec(phc_fd);
|
||||
|
||||
iface = ARR_GetNewElement(interfaces);
|
||||
|
||||
snprintf(iface->name, sizeof (iface->name), "%s", name);
|
||||
snprintf(iface->name, sizeof (iface->name), "%s", conf_iface->name);
|
||||
iface->if_index = if_index;
|
||||
iface->phc_fd = phc_fd;
|
||||
iface->phc_mode = 0;
|
||||
iface->phc_nocrossts = conf_iface->nocrossts;
|
||||
|
||||
/* Start with 1 gbit and no VLANs or IPv4/IPv6 options */
|
||||
iface->link_speed = 1000;
|
||||
iface->l2_udp4_ntp_start = 42;
|
||||
iface->l2_udp6_ntp_start = 62;
|
||||
|
||||
iface->clock = HCL_CreateInstance();
|
||||
iface->precision = conf_iface->precision;
|
||||
iface->tx_comp = conf_iface->tx_comp;
|
||||
iface->rx_comp = conf_iface->rx_comp;
|
||||
|
||||
iface->clock = HCL_CreateInstance(UTI_Log2ToDouble(MAX(conf_iface->minpoll, MIN_PHC_POLL)));
|
||||
|
||||
LOG(LOGS_INFO, "Enabled HW timestamping on %s", iface->name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
add_all_interfaces(CNF_HwTsInterface *conf_iface_all)
|
||||
{
|
||||
CNF_HwTsInterface conf_iface;
|
||||
struct ifaddrs *ifaddr, *ifa;
|
||||
int r;
|
||||
|
||||
conf_iface = *conf_iface_all;
|
||||
|
||||
if (getifaddrs(&ifaddr)) {
|
||||
DEBUG_LOG("getifaddrs() failed : %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (r = 0, ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
|
||||
conf_iface.name = ifa->ifa_name;
|
||||
if (add_interface(&conf_iface))
|
||||
r = 1;
|
||||
}
|
||||
|
||||
freeifaddrs(ifaddr);
|
||||
|
||||
/* Return success if at least one interface was added */
|
||||
return r;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
update_interface_speed(struct Interface *iface)
|
||||
{
|
||||
@@ -184,7 +257,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;
|
||||
}
|
||||
@@ -196,30 +269,71 @@ 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)
|
||||
{
|
||||
ARR_Instance config_hwts_ifaces;
|
||||
char *if_name;
|
||||
CNF_HwTsInterface *conf_iface;
|
||||
unsigned int i;
|
||||
int hwts;
|
||||
|
||||
interfaces = ARR_CreateInstance(sizeof (struct Interface));
|
||||
|
||||
config_hwts_ifaces = CNF_GetHwTsInterfaces();
|
||||
/* Enable HW timestamping on specified interfaces. If "*" was specified, try
|
||||
all interfaces. If no interface was specified, enable SW timestamping. */
|
||||
|
||||
/* Enable HW timestamping on all specified interfaces. If no interface was
|
||||
specified, use SW timestamping. */
|
||||
if (ARR_GetSize(config_hwts_ifaces)) {
|
||||
for (i = 0; i < ARR_GetSize(config_hwts_ifaces); i++) {
|
||||
if_name = *(char **)ARR_GetElement(config_hwts_ifaces, i);
|
||||
if (!add_interface(if_name))
|
||||
LOG_FATAL(LOGF_NtpIO, "Could not enable HW timestamping on %s", if_name);
|
||||
}
|
||||
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;
|
||||
for (i = hwts = 0; CNF_GetHwTsInterface(i, &conf_iface); i++) {
|
||||
if (!strcmp("*", conf_iface->name))
|
||||
continue;
|
||||
if (!add_interface(conf_iface))
|
||||
LOG_FATAL("Could not enable HW timestamping on %s", conf_iface->name);
|
||||
hwts = 1;
|
||||
}
|
||||
|
||||
for (i = 0; CNF_GetHwTsInterface(i, &conf_iface); i++) {
|
||||
if (strcmp("*", conf_iface->name))
|
||||
continue;
|
||||
if (add_all_interfaces(conf_iface))
|
||||
hwts = 1;
|
||||
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;
|
||||
#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 */
|
||||
@@ -266,13 +380,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;
|
||||
}
|
||||
@@ -283,68 +397,6 @@ NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
get_phc_sample(int phc_fd, struct timespec *phc_ts, struct timespec *local_ts, double *p_delay)
|
||||
{
|
||||
struct ptp_sys_offset sys_off;
|
||||
struct timespec ts1, ts2, ts3, phc_tss[PHC_READINGS], sys_tss[PHC_READINGS];
|
||||
double min_delay = 0.0, delays[PHC_READINGS], phc_sum, local_sum, local_prec;
|
||||
int i, n;
|
||||
|
||||
/* Silence valgrind */
|
||||
memset(&sys_off, 0, sizeof (sys_off));
|
||||
|
||||
sys_off.n_samples = PHC_READINGS;
|
||||
|
||||
if (ioctl(phc_fd, PTP_SYS_OFFSET, &sys_off)) {
|
||||
DEBUG_LOG(LOGF_NtpIOLinux, "ioctl(%s) failed : %s", "PTP_SYS_OFFSET", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < PHC_READINGS; i++) {
|
||||
ts1.tv_sec = sys_off.ts[i * 2].sec;
|
||||
ts1.tv_nsec = sys_off.ts[i * 2].nsec;
|
||||
ts2.tv_sec = sys_off.ts[i * 2 + 1].sec;
|
||||
ts2.tv_nsec = sys_off.ts[i * 2 + 1].nsec;
|
||||
ts3.tv_sec = sys_off.ts[i * 2 + 2].sec;
|
||||
ts3.tv_nsec = sys_off.ts[i * 2 + 2].nsec;
|
||||
|
||||
sys_tss[i] = ts1;
|
||||
phc_tss[i] = ts2;
|
||||
delays[i] = UTI_DiffTimespecsToDouble(&ts3, &ts1);
|
||||
|
||||
if (delays[i] <= 0.0)
|
||||
/* Step in the middle of a PHC reading? */
|
||||
return 0;
|
||||
|
||||
if (!i || delays[i] < min_delay)
|
||||
min_delay = delays[i];
|
||||
}
|
||||
|
||||
local_prec = LCL_GetSysPrecisionAsQuantum();
|
||||
|
||||
/* Combine best readings */
|
||||
for (i = n = 0, phc_sum = local_sum = 0.0; i < PHC_READINGS; i++) {
|
||||
if (delays[i] > min_delay + local_prec)
|
||||
continue;
|
||||
|
||||
phc_sum += UTI_DiffTimespecsToDouble(&phc_tss[i], &phc_tss[0]);
|
||||
local_sum += UTI_DiffTimespecsToDouble(&sys_tss[i], &sys_tss[0]) + delays[i] / 2.0;
|
||||
n++;
|
||||
}
|
||||
|
||||
assert(n);
|
||||
|
||||
UTI_AddDoubleToTimespec(&phc_tss[0], phc_sum / n, phc_ts);
|
||||
UTI_AddDoubleToTimespec(&sys_tss[0], local_sum / n, &ts1);
|
||||
LCL_CookTime(&ts1, local_ts, NULL);
|
||||
*p_delay = min_delay;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static struct Interface *
|
||||
get_interface(int if_index)
|
||||
{
|
||||
@@ -366,38 +418,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_local_ts;
|
||||
double sample_delay, rx_correction;
|
||||
int l2_length;
|
||||
struct timespec sample_phc_ts, sample_sys_ts, sample_local_ts, ts;
|
||||
double rx_correction, ts_delay, phc_err, local_err;
|
||||
|
||||
if (HCL_NeedsNewSample(iface->clock, &local_ts->ts)) {
|
||||
if (!get_phc_sample(iface->phc_fd, &sample_phc_ts, &sample_local_ts, &sample_delay))
|
||||
if (!SYS_Linux_GetPHCSample(iface->phc_fd, iface->phc_nocrossts, iface->precision,
|
||||
&iface->phc_mode, &sample_phc_ts, &sample_sys_ts,
|
||||
&phc_err))
|
||||
return;
|
||||
|
||||
LCL_CookTime(&sample_sys_ts, &sample_local_ts, &local_err);
|
||||
HCL_AccumulateSample(iface->clock, &sample_phc_ts, &sample_local_ts,
|
||||
sample_delay / 2.0);
|
||||
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, &local_ts->ts, &local_ts->err))
|
||||
if (!HCL_CookTime(iface->clock, hw_ts, &ts, &local_err))
|
||||
return;
|
||||
|
||||
if (!rx_ntp_length && iface->tx_comp)
|
||||
UTI_AddDoubleToTimespec(&ts, iface->tx_comp, &ts);
|
||||
else if (rx_ntp_length && iface->rx_comp)
|
||||
UTI_AddDoubleToTimespec(&ts, -iface->rx_comp, &ts);
|
||||
|
||||
ts_delay = UTI_DiffTimespecsToDouble(&local_ts->ts, &ts);
|
||||
|
||||
if (fabs(ts_delay) > MAX_TS_DELAY) {
|
||||
DEBUG_LOG("Unacceptable timestamp delay %.9f", ts_delay);
|
||||
return;
|
||||
}
|
||||
|
||||
local_ts->ts = ts;
|
||||
local_ts->err = local_err;
|
||||
local_ts->source = NTP_TS_HARDWARE;
|
||||
}
|
||||
|
||||
@@ -468,34 +538,51 @@ extract_udp_data(unsigned char *msg, NTP_Remote_Address *remote_addr, int len)
|
||||
|
||||
int
|
||||
NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
|
||||
NTP_Local_Timestamp *local_ts, struct msghdr *hdr,
|
||||
int length, int sock_fd, int if_index)
|
||||
NTP_Local_Timestamp *local_ts, struct msghdr *hdr, int length)
|
||||
{
|
||||
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 {
|
||||
iface = get_interface(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", 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) ||
|
||||
@@ -506,7 +593,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;
|
||||
}
|
||||
@@ -523,9 +610,9 @@ 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,
|
||||
sock_fd, if_index, local_ts->source);
|
||||
local_addr->sock_fd, local_addr->if_index, local_ts->source);
|
||||
|
||||
/* Update assumed position of UDP data at layer 2 for next received packet */
|
||||
if (iface && length) {
|
||||
@@ -535,9 +622,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ extern void NIO_Linux_Finalise(void);
|
||||
extern int NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events);
|
||||
|
||||
extern int NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
|
||||
NTP_Local_Timestamp *local_ts, struct msghdr *hdr, int length,
|
||||
int sock_fd, int if_index);
|
||||
NTP_Local_Timestamp *local_ts, struct msghdr *hdr, int length);
|
||||
|
||||
extern int NIO_Linux_RequestTxTimestamp(struct msghdr *msg, int cmsglen, int sock_fd);
|
||||
|
||||
41
ntp_signd.c
41
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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -123,7 +123,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 +136,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 */
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
65
privops.c
65
privops.c
@@ -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
|
||||
@@ -343,6 +355,11 @@ helper_main(int fd)
|
||||
case OP_NAME2IPADDRESS:
|
||||
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;
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
160
refclock.c
160
refclock.c
@@ -2,7 +2,7 @@
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2009-2011, 2013-2014
|
||||
* Copyright (C) Miroslav Lichvar 2009-2011, 2013-2014, 2016
|
||||
*
|
||||
* 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,7 +253,7 @@ 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;
|
||||
}
|
||||
|
||||
@@ -269,7 +262,7 @@ RCL_AddRefclock(RefclockParameters *params)
|
||||
inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, params->sel_options, NULL,
|
||||
params->min_samples, params->max_samples);
|
||||
|
||||
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;
|
||||
|
||||
LCL_GetOffsetCorrection(pulse_time, &correction, &dispersion);
|
||||
UTI_AddDoubleToTimespec(pulse_time, correction, &cooked_time);
|
||||
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;
|
||||
|
||||
leap = LEAP_Normal;
|
||||
LCL_GetOffsetCorrection(pulse_time, &correction, &dispersion);
|
||||
UTI_AddDoubleToTimespec(pulse_time, correction, &cooked_time);
|
||||
dispersion += instance->precision;
|
||||
|
||||
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)
|
||||
@@ -505,23 +541,35 @@ RCL_AddPulse(RCL_Instance instance, struct timespec *pulse_time, double second)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
valid_sample_time(RCL_Instance instance, struct timespec *raw, struct timespec *cooked)
|
||||
double
|
||||
RCL_GetPrecision(RCL_Instance instance)
|
||||
{
|
||||
struct timespec now_raw, last_sample_time;
|
||||
return instance->precision;
|
||||
}
|
||||
|
||||
int
|
||||
RCL_GetDriverPoll(RCL_Instance instance)
|
||||
{
|
||||
return instance->driver_poll;
|
||||
}
|
||||
|
||||
static int
|
||||
valid_sample_time(RCL_Instance instance, struct timespec *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;
|
||||
}
|
||||
|
||||
@@ -713,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);
|
||||
}
|
||||
|
||||
@@ -903,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;
|
||||
}
|
||||
|
||||
@@ -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,5 +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
|
||||
|
||||
204
refclock_phc.c
204
refclock_phc.c
@@ -2,7 +2,7 @@
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2013
|
||||
* Copyright (C) Miroslav Lichvar 2013, 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
|
||||
@@ -33,144 +33,134 @@
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include <linux/ptp_clock.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"
|
||||
|
||||
/* From linux/include/linux/posix-timers.h */
|
||||
#define CPUCLOCK_MAX 3
|
||||
#define CLOCKFD CPUCLOCK_MAX
|
||||
#define CLOCKFD_MASK (CPUCLOCK_PERTHREAD_MASK|CPUCLOCK_CLOCK_MASK)
|
||||
|
||||
#define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD)
|
||||
|
||||
#define NUM_READINGS 10
|
||||
|
||||
static int no_sys_offset_ioctl = 0;
|
||||
|
||||
struct phc_reading {
|
||||
struct timespec sys_ts1;
|
||||
struct timespec phc_ts;;
|
||||
struct timespec sys_ts2;
|
||||
struct phc_instance {
|
||||
int fd;
|
||||
int mode;
|
||||
int nocrossts;
|
||||
int extpps;
|
||||
int pin;
|
||||
int channel;
|
||||
HCL_Instance clock;
|
||||
};
|
||||
|
||||
static int read_phc_ioctl(struct phc_reading *readings, int phc_fd, int n)
|
||||
{
|
||||
#if defined(PTP_SYS_OFFSET) && NUM_READINGS <= PTP_MAX_SAMPLES
|
||||
struct ptp_sys_offset sys_off;
|
||||
int i;
|
||||
|
||||
/* Silence valgrind */
|
||||
memset(&sys_off, 0, sizeof (sys_off));
|
||||
|
||||
sys_off.n_samples = n;
|
||||
if (ioctl(phc_fd, PTP_SYS_OFFSET, &sys_off)) {
|
||||
LOG(LOGS_ERR, LOGF_Refclock, "ioctl(PTP_SYS_OFFSET) failed : %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
readings[i].sys_ts1.tv_sec = sys_off.ts[i * 2].sec;
|
||||
readings[i].sys_ts1.tv_nsec = sys_off.ts[i * 2].nsec;
|
||||
readings[i].phc_ts.tv_sec = sys_off.ts[i * 2 + 1].sec;
|
||||
readings[i].phc_ts.tv_nsec = sys_off.ts[i * 2 + 1].nsec;
|
||||
readings[i].sys_ts2.tv_sec = sys_off.ts[i * 2 + 2].sec;
|
||||
readings[i].sys_ts2.tv_nsec = sys_off.ts[i * 2 + 2].nsec;
|
||||
}
|
||||
|
||||
return 1;
|
||||
#else
|
||||
/* Not available */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int read_phc_user(struct phc_reading *readings, int phc_fd, int n)
|
||||
{
|
||||
clockid_t phc_id;
|
||||
int i;
|
||||
|
||||
phc_id = FD_TO_CLOCKID(phc_fd);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (clock_gettime(CLOCK_REALTIME, &readings[i].sys_ts1) ||
|
||||
clock_gettime(phc_id, &readings[i].phc_ts) ||
|
||||
clock_gettime(CLOCK_REALTIME, &readings[i].sys_ts2)) {
|
||||
LOG(LOGS_ERR, LOGF_Refclock, "clock_gettime() failed : %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
static void read_ext_pulse(int sockfd, int event, void *anything);
|
||||
|
||||
static int phc_initialise(RCL_Instance instance)
|
||||
{
|
||||
struct ptp_clock_caps caps;
|
||||
int phc_fd;
|
||||
char *path;
|
||||
struct phc_instance *phc;
|
||||
int phc_fd, rising_edge;
|
||||
char *path, *s;
|
||||
|
||||
path = RCL_GetDriverParameter(instance);
|
||||
|
||||
phc_fd = open(path, O_RDONLY);
|
||||
phc_fd = SYS_Linux_OpenPHC(path, 0);
|
||||
if (phc_fd < 0) {
|
||||
LOG_FATAL(LOGF_Refclock, "open() failed on %s", path);
|
||||
LOG_FATAL("Could not open PHC");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure it is a PHC */
|
||||
if (ioctl(phc_fd, PTP_CLOCK_GETCAPS, &caps)) {
|
||||
LOG_FATAL(LOGF_Refclock, "ioctl(PTP_CLOCK_GETCAPS) failed : %s", strerror(errno));
|
||||
return 0;
|
||||
phc = MallocNew(struct phc_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;
|
||||
}
|
||||
|
||||
UTI_FdSetCloexec(phc_fd);
|
||||
|
||||
RCL_SetDriverData(instance, (void *)(long)phc_fd);
|
||||
RCL_SetDriverData(instance, phc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void phc_finalise(RCL_Instance instance)
|
||||
{
|
||||
close((long)RCL_GetDriverData(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_reading readings[NUM_READINGS];
|
||||
double offset = 0.0, delay, best_delay = 0.0;
|
||||
int i, phc_fd, best;
|
||||
|
||||
phc_fd = (long)RCL_GetDriverData(instance);
|
||||
struct phc_instance *phc;
|
||||
struct timespec phc_ts, sys_ts, local_ts;
|
||||
double offset, phc_err, local_err;
|
||||
|
||||
if (!no_sys_offset_ioctl) {
|
||||
if (!read_phc_ioctl(readings, phc_fd, NUM_READINGS)) {
|
||||
no_sys_offset_ioctl = 1;
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (!read_phc_user(readings, phc_fd, NUM_READINGS))
|
||||
return 0;
|
||||
phc = (struct phc_instance *)RCL_GetDriverData(instance);
|
||||
|
||||
if (!SYS_Linux_GetPHCSample(phc->fd, phc->nocrossts, RCL_GetPrecision(instance),
|
||||
&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;
|
||||
}
|
||||
|
||||
/* Find the fastest reading */
|
||||
for (i = 0; i < NUM_READINGS; i++) {
|
||||
delay = UTI_DiffTimespecsToDouble(&readings[i].sys_ts2, &readings[i].sys_ts1);
|
||||
offset = UTI_DiffTimespecsToDouble(&phc_ts, &sys_ts);
|
||||
|
||||
if (!i || best_delay > delay) {
|
||||
best = i;
|
||||
best_delay = delay;
|
||||
}
|
||||
}
|
||||
DEBUG_LOG("PHC offset: %+.9f err: %.9f", offset, phc_err);
|
||||
|
||||
offset = UTI_DiffTimespecsToDouble(&readings[best].phc_ts, &readings[best].sys_ts2) +
|
||||
best_delay / 2.0;
|
||||
|
||||
DEBUG_LOG(LOGF_Refclock, "PHC offset: %+.9f delay: %.9f", offset, best_delay);
|
||||
|
||||
return RCL_AddSample(instance, &readings[best].sys_ts2, offset, LEAP_Normal);
|
||||
return RCL_AddSample(instance, &sys_ts, offset, LEAP_Normal);
|
||||
}
|
||||
|
||||
RefclockDriver RCL_PHC_driver = {
|
||||
|
||||
@@ -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, ¶ms) < 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, ¶ms) < 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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
116
reference.c
116
reference.c
@@ -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);
|
||||
|
||||
/* ================================================== */
|
||||
@@ -181,11 +180,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 +206,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,7 +220,7 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,11 +244,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;
|
||||
}
|
||||
}
|
||||
@@ -364,7 +365,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 +375,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 +385,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 +395,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 +443,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 +457,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 +492,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 +531,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 +557,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 +592,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)
|
||||
@@ -618,12 +616,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)
|
||||
{
|
||||
static time_t last_tz_leap_check;
|
||||
static NTP_Leap tz_leap;
|
||||
static int tz_tai_offset;
|
||||
|
||||
struct tm stm;
|
||||
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 +635,10 @@ 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))
|
||||
return tz_leap;
|
||||
|
||||
/* Temporarily switch to the timezone containing leap seconds */
|
||||
tz_env = getenv("TZ");
|
||||
if (tz_env) {
|
||||
@@ -647,6 +649,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 +675,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 +687,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 +709,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,12 +767,17 @@ 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 */
|
||||
@@ -776,12 +793,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:
|
||||
@@ -825,15 +844,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 +865,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)
|
||||
@@ -928,7 +946,7 @@ REF_SetReference(int stratum,
|
||||
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");
|
||||
LOG(LOGS_WARN, "Bogus skew value encountered");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1025,7 +1043,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 +1055,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);
|
||||
@@ -1214,7 +1232,7 @@ REF_GetReferenceParams
|
||||
*leap_status = LEAP_Normal;
|
||||
|
||||
*root_delay = 0.0;
|
||||
*root_dispersion = LCL_GetSysPrecisionAsQuantum();
|
||||
*root_dispersion = 0.0;
|
||||
|
||||
} else {
|
||||
|
||||
@@ -1348,7 +1366,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;
|
||||
|
||||
59
regress.c
59
regress.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2011
|
||||
* Copyright (C) Miroslav Lichvar 2011, 2016
|
||||
*
|
||||
* 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);
|
||||
@@ -429,6 +429,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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
6
rtc.c
6
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
55
rtc_linux.c
55
rtc_linux.c
@@ -187,6 +187,11 @@ accumulate_sample(time_t rtc, struct timespec *sys)
|
||||
discard_samples(NEW_FIRST_WHEN_FULL);
|
||||
}
|
||||
|
||||
/* 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("RTC samples discarded");
|
||||
n_samples = 0;
|
||||
}
|
||||
|
||||
/* Always use most recent sample as reference */
|
||||
/* use sample only if n_sample is not negative*/
|
||||
@@ -289,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);
|
||||
@@ -366,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;
|
||||
}
|
||||
@@ -385,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;
|
||||
}
|
||||
@@ -403,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,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);
|
||||
}
|
||||
@@ -480,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;
|
||||
}
|
||||
@@ -491,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;
|
||||
}
|
||||
@@ -501,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);
|
||||
}
|
||||
@@ -512,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;
|
||||
}
|
||||
@@ -545,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;
|
||||
}
|
||||
@@ -606,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;
|
||||
}
|
||||
}
|
||||
@@ -653,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");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -696,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;
|
||||
@@ -724,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;
|
||||
@@ -819,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);
|
||||
@@ -843,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;
|
||||
}
|
||||
@@ -884,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);
|
||||
|
||||
@@ -897,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);
|
||||
@@ -1036,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;
|
||||
}
|
||||
|
||||
@@ -1045,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;
|
||||
@@ -1090,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
|
||||
|
||||
16
sched.c
16
sched.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2011, 2013-2015
|
||||
* Copyright (C) Miroslav Lichvar 2011, 2013-2016
|
||||
*
|
||||
* 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
|
||||
@@ -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 */
|
||||
|
||||
6
smooth.c
6
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
|
||||
@@ -295,7 +295,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;
|
||||
|
||||
40
sources.c
40
sources.c
@@ -348,12 +348,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;
|
||||
}
|
||||
|
||||
@@ -425,10 +425,11 @@ SRC_UpdateReachability(SRC_Instance inst, int reachable)
|
||||
}
|
||||
|
||||
/* Try to replace NTP sources that are unreachable, falsetickers, or
|
||||
have root distance larger than the allowed maximum */
|
||||
have root distance or jitter larger than the allowed maximums */
|
||||
if (inst->type == SRC_NTP &&
|
||||
((!inst->reachability && inst->reachability_size == SOURCE_REACH_BITS) ||
|
||||
inst->status == SRC_FALSETICKER || inst->status == SRC_BAD_DISTANCE)) {
|
||||
inst->status == SRC_BAD_DISTANCE || inst->status == SRC_JITTERY ||
|
||||
inst->status == SRC_FALSETICKER)) {
|
||||
NSR_HandleBadSource(inst->ip_addr);
|
||||
}
|
||||
}
|
||||
@@ -450,7 +451,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);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -562,7 +563,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;
|
||||
@@ -583,7 +584,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;
|
||||
@@ -735,12 +736,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -764,7 +764,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);
|
||||
|
||||
@@ -1002,7 +1002,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);
|
||||
@@ -1026,7 +1026,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;
|
||||
}
|
||||
|
||||
@@ -1097,7 +1097,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1152,7 +1152,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;
|
||||
}
|
||||
|
||||
@@ -1163,13 +1163,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;
|
||||
@@ -1206,10 +1206,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);
|
||||
}
|
||||
@@ -1247,7 +1247,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]);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2011-2014
|
||||
* Copyright (C) Miroslav Lichvar 2011-2014, 2016
|
||||
*
|
||||
* 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
|
||||
@@ -47,8 +47,9 @@
|
||||
2000ppm, which would be pretty bad */
|
||||
#define WORST_CASE_FREQ_BOUND (2000.0/1.0e6)
|
||||
|
||||
/* The minimum allowed skew */
|
||||
/* The minimum and maximum assumed skew */
|
||||
#define MIN_SKEW 1.0e-12
|
||||
#define MAX_SKEW 1.0e+02
|
||||
|
||||
/* The asymmetry of network jitter when all jitter is in one direction */
|
||||
#define MAX_ASYMMETRY 0.5
|
||||
@@ -291,7 +292,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);
|
||||
}
|
||||
@@ -462,7 +463,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
|
||||
@@ -482,9 +483,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);
|
||||
|
||||
@@ -493,25 +495,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;
|
||||
if (sd > min_distance || sd <= 0.0)
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -539,12 +544,10 @@ SST_DoNewRegression(SST_Stats inst)
|
||||
inst->std_dev = sqrt(est_var);
|
||||
inst->nruns = nruns;
|
||||
|
||||
if (inst->skew < MIN_SKEW)
|
||||
inst->skew = MIN_SKEW;
|
||||
|
||||
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);
|
||||
@@ -623,7 +626,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;
|
||||
@@ -652,7 +655,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);
|
||||
}
|
||||
@@ -683,8 +686,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);
|
||||
|
||||
}
|
||||
|
||||
@@ -718,7 +722,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,
|
||||
@@ -780,7 +784,7 @@ SST_IsGoodSample(SST_Stats inst, double offset, double delay,
|
||||
{
|
||||
double elapsed, allowed_increase, delay_increase;
|
||||
|
||||
if (inst->n_samples < 3)
|
||||
if (inst->n_samples < 6)
|
||||
return 1;
|
||||
|
||||
elapsed = UTI_DiffTimespecsToDouble(when, &inst->offset_time);
|
||||
@@ -804,8 +808,8 @@ SST_IsGoodSample(SST_Stats inst, double offset, double delay,
|
||||
if (fabs(offset) - delay_increase > allowed_increase)
|
||||
return 1;
|
||||
|
||||
DEBUG_LOG(LOGF_SourceStats, "Bad sample: offset=%f delay=%f incr_delay=%f allowed=%f",
|
||||
offset, delay, allowed_increase, delay_increase);
|
||||
DEBUG_LOG("Bad sample: offset=%f delay=%f incr_delay=%f allowed=%f",
|
||||
offset, delay, delay_increase, allowed_increase);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -844,6 +848,8 @@ SST_SaveToFile(SST_Stats inst, FILE *out)
|
||||
inst->strata[j]);
|
||||
|
||||
}
|
||||
|
||||
fprintf(out, "%d\n", inst->asymmetry_run);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -898,6 +904,10 @@ SST_LoadFromFile(SST_Stats inst, FILE *in)
|
||||
UTI_NormaliseTimespec(&inst->sample_times[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* This field was not saved in older versions */
|
||||
if (!fgets(line, sizeof(line), in) || sscanf(line, "%d\n", &inst->asymmetry_run) != 1)
|
||||
inst->asymmetry_run = 0;
|
||||
} else {
|
||||
inst->n_samples = 0; /* Load abandoned if any sign of corruption */
|
||||
return 0;
|
||||
@@ -921,7 +931,7 @@ void
|
||||
SST_DoSourceReport(SST_Stats inst, RPT_SourceReport *report, struct timespec *now)
|
||||
{
|
||||
int i, j;
|
||||
struct timespec ago;
|
||||
struct timespec last_sample_time;
|
||||
|
||||
if (inst->n_samples > 0) {
|
||||
i = get_runsbuf_index(inst, inst->n_samples - 1);
|
||||
@@ -931,8 +941,10 @@ SST_DoSourceReport(SST_Stats inst, RPT_SourceReport *report, struct timespec *no
|
||||
report->latest_meas_err = 0.5*inst->root_delays[j] + inst->root_dispersions[j];
|
||||
report->stratum = inst->strata[j];
|
||||
|
||||
UTI_DiffTimespecs(&ago, now, &inst->sample_times[i]);
|
||||
report->latest_meas_ago = ago.tv_sec;
|
||||
/* Align the sample time to reduce the leak of the receive timestamp */
|
||||
last_sample_time = inst->sample_times[i];
|
||||
last_sample_time.tv_nsec = 0;
|
||||
report->latest_meas_ago = UTI_DiffTimespecsToDouble(now, &last_sample_time);
|
||||
} else {
|
||||
report->latest_meas_ago = (uint32_t)-1;
|
||||
report->orig_latest_meas = 0;
|
||||
|
||||
22
stubs.c
22
stubs.c
@@ -2,7 +2,7 @@
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2014-2015
|
||||
* Copyright (C) Miroslav Lichvar 2014-2016
|
||||
*
|
||||
* 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
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "privops.h"
|
||||
#include "refclock.h"
|
||||
#include "sched.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifndef FEAT_ASYNCDNS
|
||||
|
||||
@@ -51,10 +52,11 @@ struct DNS_Async_Instance {
|
||||
const char *name;
|
||||
DNS_NameResolveHandler handler;
|
||||
void *arg;
|
||||
int pipe[2];
|
||||
};
|
||||
|
||||
static void
|
||||
resolve_name(void *anything)
|
||||
resolve_name(int fd, int event, void *anything)
|
||||
{
|
||||
struct DNS_Async_Instance *inst;
|
||||
IPAddr addrs[DNS_MAX_ADDRESSES];
|
||||
@@ -62,6 +64,11 @@ resolve_name(void *anything)
|
||||
int i;
|
||||
|
||||
inst = (struct DNS_Async_Instance *)anything;
|
||||
|
||||
SCH_RemoveFileHandler(inst->pipe[0]);
|
||||
close(inst->pipe[0]);
|
||||
close(inst->pipe[1]);
|
||||
|
||||
status = PRV_Name2IPAddress(inst->name, addrs, DNS_MAX_ADDRESSES);
|
||||
|
||||
for (i = 0; status == DNS_Success && i < DNS_MAX_ADDRESSES &&
|
||||
@@ -83,7 +90,16 @@ DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *
|
||||
inst->handler = handler;
|
||||
inst->arg = anything;
|
||||
|
||||
SCH_AddTimeoutByDelay(0.0, resolve_name, inst);
|
||||
if (pipe(inst->pipe))
|
||||
LOG_FATAL("pipe() failed");
|
||||
|
||||
UTI_FdSetCloexec(inst->pipe[0]);
|
||||
UTI_FdSetCloexec(inst->pipe[1]);
|
||||
|
||||
SCH_AddFileHandler(inst->pipe[0], SCH_FILE_INPUT, resolve_name, inst);
|
||||
|
||||
if (write(inst->pipe[1], "", 1) < 0)
|
||||
;
|
||||
}
|
||||
|
||||
#endif /* !FEAT_ASYNCDNS */
|
||||
|
||||
24
sys.c
24
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
|
||||
}
|
||||
|
||||
|
||||
2
sys.h
2
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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
268
sys_linux.c
268
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-2015
|
||||
* Copyright (C) Miroslav Lichvar 2009-2012, 2014-2016
|
||||
*
|
||||
* 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
|
||||
@@ -47,13 +47,14 @@
|
||||
#include <sys/capability.h>
|
||||
#endif
|
||||
|
||||
#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
|
||||
#include <linux/ptp_clock.h>
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_SCFILTER
|
||||
#include <sys/prctl.h>
|
||||
#include <seccomp.h>
|
||||
#include <termios.h>
|
||||
#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
|
||||
#include <linux/ptp_clock.h>
|
||||
#endif
|
||||
#ifdef FEAT_PPS
|
||||
#include <linux/pps.h>
|
||||
#endif
|
||||
@@ -68,6 +69,7 @@
|
||||
#include "sys_linux.h"
|
||||
#include "sys_timex.h"
|
||||
#include "conf.h"
|
||||
#include "local.h"
|
||||
#include "logging.h"
|
||||
#include "privops.h"
|
||||
#include "util.h"
|
||||
@@ -238,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;
|
||||
}
|
||||
@@ -281,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");
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -312,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 &&
|
||||
@@ -332,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);
|
||||
}
|
||||
|
||||
@@ -389,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;
|
||||
}
|
||||
|
||||
@@ -419,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);
|
||||
@@ -429,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);
|
||||
@@ -452,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");
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -465,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),
|
||||
@@ -487,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[] = {
|
||||
@@ -514,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_PIN_SETFUNC, PTP_SYS_OFFSET,
|
||||
#ifdef PTP_SYS_OFFSET_PRECISE
|
||||
PTP_SYS_OFFSET_PRECISE,
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FEAT_PPS
|
||||
PPS_FETCH,
|
||||
@@ -541,7 +547,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++) {
|
||||
@@ -582,14 +588,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
|
||||
|
||||
@@ -603,7 +609,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);
|
||||
@@ -615,10 +621,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);
|
||||
}
|
||||
}
|
||||
@@ -636,14 +642,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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -661,3 +667,205 @@ SYS_Linux_CheckKernelVersion(int req_major, int req_minor)
|
||||
|
||||
return kernelvercmp(req_major, req_minor, 0, major, minor, patch) <= 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
|
||||
|
||||
#define PHC_READINGS 10
|
||||
|
||||
static int
|
||||
get_phc_sample(int phc_fd, double precision, struct timespec *phc_ts,
|
||||
struct timespec *sys_ts, double *err)
|
||||
{
|
||||
struct ptp_sys_offset sys_off;
|
||||
struct timespec ts1, ts2, ts3, phc_tss[PHC_READINGS], sys_tss[PHC_READINGS];
|
||||
double min_delay = 0.0, delays[PHC_READINGS], phc_sum, sys_sum, sys_prec;
|
||||
int i, n;
|
||||
|
||||
/* Silence valgrind */
|
||||
memset(&sys_off, 0, sizeof (sys_off));
|
||||
|
||||
sys_off.n_samples = PHC_READINGS;
|
||||
|
||||
if (ioctl(phc_fd, PTP_SYS_OFFSET, &sys_off)) {
|
||||
DEBUG_LOG("ioctl(%s) failed : %s", "PTP_SYS_OFFSET", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < PHC_READINGS; i++) {
|
||||
ts1.tv_sec = sys_off.ts[i * 2].sec;
|
||||
ts1.tv_nsec = sys_off.ts[i * 2].nsec;
|
||||
ts2.tv_sec = sys_off.ts[i * 2 + 1].sec;
|
||||
ts2.tv_nsec = sys_off.ts[i * 2 + 1].nsec;
|
||||
ts3.tv_sec = sys_off.ts[i * 2 + 2].sec;
|
||||
ts3.tv_nsec = sys_off.ts[i * 2 + 2].nsec;
|
||||
|
||||
sys_tss[i] = ts1;
|
||||
phc_tss[i] = ts2;
|
||||
delays[i] = UTI_DiffTimespecsToDouble(&ts3, &ts1);
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
sys_prec = LCL_GetSysPrecisionAsQuantum();
|
||||
|
||||
/* Combine best readings */
|
||||
for (i = n = 0, phc_sum = sys_sum = 0.0; i < PHC_READINGS; i++) {
|
||||
if (delays[i] > min_delay + MAX(sys_prec, precision))
|
||||
continue;
|
||||
|
||||
phc_sum += UTI_DiffTimespecsToDouble(&phc_tss[i], &phc_tss[0]);
|
||||
sys_sum += UTI_DiffTimespecsToDouble(&sys_tss[i], &sys_tss[0]) + delays[i] / 2.0;
|
||||
n++;
|
||||
}
|
||||
|
||||
assert(n);
|
||||
|
||||
UTI_AddDoubleToTimespec(&phc_tss[0], phc_sum / n, phc_ts);
|
||||
UTI_AddDoubleToTimespec(&sys_tss[0], sys_sum / n, sys_ts);
|
||||
*err = MAX(min_delay / 2.0, precision);
|
||||
|
||||
return 1;
|
||||
}
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
get_precise_phc_sample(int phc_fd, double precision, struct timespec *phc_ts,
|
||||
struct timespec *sys_ts, double *err)
|
||||
{
|
||||
#ifdef PTP_SYS_OFFSET_PRECISE
|
||||
struct ptp_sys_offset_precise sys_off;
|
||||
|
||||
/* Silence valgrind */
|
||||
memset(&sys_off, 0, sizeof (sys_off));
|
||||
|
||||
if (ioctl(phc_fd, PTP_SYS_OFFSET_PRECISE, &sys_off)) {
|
||||
DEBUG_LOG("ioctl(%s) failed : %s", "PTP_SYS_OFFSET_PRECISE",
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
phc_ts->tv_sec = sys_off.device.sec;
|
||||
phc_ts->tv_nsec = sys_off.device.nsec;
|
||||
sys_ts->tv_sec = sys_off.sys_realtime.sec;
|
||||
sys_ts->tv_nsec = sys_off.sys_realtime.nsec;
|
||||
*err = MAX(LCL_GetSysPrecisionAsQuantum(), precision);
|
||||
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SYS_Linux_OpenPHC(const char *path, int phc_index)
|
||||
{
|
||||
struct ptp_clock_caps caps;
|
||||
char phc_path[64];
|
||||
int phc_fd;
|
||||
|
||||
if (!path) {
|
||||
if (snprintf(phc_path, sizeof (phc_path), "/dev/ptp%d", phc_index) >= sizeof (phc_path))
|
||||
return -1;
|
||||
path = phc_path;
|
||||
}
|
||||
|
||||
phc_fd = open(path, O_RDONLY);
|
||||
if (phc_fd < 0) {
|
||||
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, "ioctl(%s) failed : %s", "PTP_CLOCK_GETCAPS", strerror(errno));
|
||||
close(phc_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
UTI_FdSetCloexec(phc_fd);
|
||||
|
||||
return phc_fd;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SYS_Linux_GetPHCSample(int fd, int nocrossts, double precision, int *reading_mode,
|
||||
struct timespec *phc_ts, struct timespec *sys_ts, double *err)
|
||||
{
|
||||
if ((*reading_mode == 2 || !*reading_mode) && !nocrossts &&
|
||||
get_precise_phc_sample(fd, precision, phc_ts, sys_ts, err)) {
|
||||
*reading_mode = 2;
|
||||
return 1;
|
||||
} else if ((*reading_mode == 1 || !*reading_mode) &&
|
||||
get_phc_sample(fd, precision, phc_ts, sys_ts, err)) {
|
||||
*reading_mode = 1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SYS_Linux_SetPHCExtTimestamping(int fd, int pin, int channel,
|
||||
int rising, int falling, int enable)
|
||||
{
|
||||
struct ptp_pin_desc pin_desc;
|
||||
struct ptp_extts_request extts_req;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
10
sys_linux.h
10
sys_linux.h
@@ -41,4 +41,14 @@ extern void SYS_Linux_SetScheduler(int SchedPriority);
|
||||
|
||||
extern int SYS_Linux_CheckKernelVersion(int req_major, int req_minor);
|
||||
|
||||
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 */
|
||||
|
||||
101
sys_macosx.c
101
sys_macosx.c
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ get_offset_correction(struct timespec *raw,
|
||||
double adjustment_remaining;
|
||||
|
||||
if (PRV_AdjustTime(NULL, &remadj) < 0)
|
||||
LOG_FATAL(LOGF_SysNetBSD, "adjtime() failed");
|
||||
LOG_FATAL("adjtime() failed");
|
||||
|
||||
adjustment_remaining = UTI_TimevalToDouble(&remadj);
|
||||
|
||||
@@ -138,7 +138,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
|
||||
}
|
||||
|
||||
140
sys_null.c
Normal file
140
sys_null.c
Normal file
@@ -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)
|
||||
{
|
||||
}
|
||||
34
sys_null.h
Normal file
34
sys_null.h
Normal file
@@ -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
|
||||
71
sys_timex.c
71
sys_timex.c
@@ -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,16 +166,17 @@ 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;
|
||||
|
||||
SYS_Timex_Adjust(&txc, 1);
|
||||
if (SYS_Timex_Adjust(&txc, 1) < 0)
|
||||
;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -168,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);
|
||||
}
|
||||
|
||||
@@ -238,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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
14
tempcomp.c
14
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
|
||||
|
||||
@@ -20,8 +20,8 @@ RMS offset : 0\.000...... seconds
|
||||
Frequency : (99|100)\.... ppm fast
|
||||
Residual freq : [+-][0-9]\.... ppm
|
||||
Skew : [0-9]\.... ppm
|
||||
Root delay : 0\.000... seconds
|
||||
Root dispersion : 0\.000... seconds
|
||||
Root delay : 0\.000...... seconds
|
||||
Root dispersion : 0\.000...... seconds
|
||||
Update interval : [0-9]+\.. seconds
|
||||
Leap status : Normal
|
||||
210 Number of sources = 1
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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" "maxpoll 6 maxdelayratio 1.001"; do
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_packet_interval || test_fail
|
||||
|
||||
@@ -25,13 +25,21 @@ time_offset=-10
|
||||
client_server_options="minpoll 6 maxpoll 6"
|
||||
client_conf="corrtimeratio 100"
|
||||
min_sync_time=8000
|
||||
max_sync_time=8500
|
||||
max_sync_time=9000
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
client_server_options="minpoll 6 maxpoll 6 xleave maxdelay 1e-1"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
client_server_options="minpoll 6 maxpoll 6"
|
||||
min_sync_time=$default_min_sync_time
|
||||
max_sync_time=$default_max_sync_time
|
||||
time_max_limit=11
|
||||
|
||||
@@ -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 ]
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -31,7 +31,7 @@ test_unit(void)
|
||||
|
||||
LCL_Initialise();
|
||||
|
||||
clock = HCL_CreateInstance();
|
||||
clock = HCL_CreateInstance(1.0);
|
||||
|
||||
for (i = 0; i < 2000; i++) {
|
||||
UTI_ZeroTimespec(&start_hw_ts);
|
||||
@@ -39,11 +39,11 @@ test_unit(void)
|
||||
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);
|
||||
interval = TST_GetRandomDouble(MIN_SAMPLE_SEPARATION / 10, MIN_SAMPLE_SEPARATION * 10.0);
|
||||
interval = TST_GetRandomDouble(0.1, 10.0);
|
||||
|
||||
clock->n_samples = 0;
|
||||
clock->valid_coefs = 0;
|
||||
@@ -68,5 +68,7 @@ test_unit(void)
|
||||
}
|
||||
}
|
||||
|
||||
HCL_DestroyInstance(clock);
|
||||
|
||||
LCL_Finalise();
|
||||
}
|
||||
|
||||
147
test/unit/keys.c
Normal file
147
test/unit/keys.c
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
**********************************************************************
|
||||
* 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 <keys.c>
|
||||
#include "test.h"
|
||||
|
||||
#define KEYS 100
|
||||
#define KEYFILE "keys.test-keys"
|
||||
|
||||
static
|
||||
uint32_t write_random_key(FILE *f)
|
||||
{
|
||||
const char *hash_name;
|
||||
char key[128];
|
||||
uint32_t id;
|
||||
int i, length;
|
||||
|
||||
length = random() % sizeof (key) + 1;
|
||||
length = MAX(length, 4);
|
||||
UTI_GetRandomBytes(&id, sizeof (id));
|
||||
UTI_GetRandomBytes(key, length);
|
||||
|
||||
switch (random() % 6) {
|
||||
#ifdef FEAT_SECHASH
|
||||
case 0:
|
||||
hash_name = "SHA1";
|
||||
break;
|
||||
case 1:
|
||||
hash_name = "SHA256";
|
||||
break;
|
||||
case 2:
|
||||
hash_name = "SHA384";
|
||||
break;
|
||||
case 3:
|
||||
hash_name = "SHA512";
|
||||
break;
|
||||
#endif
|
||||
case 4:
|
||||
hash_name = "MD5";
|
||||
break;
|
||||
default:
|
||||
hash_name = "";
|
||||
}
|
||||
|
||||
fprintf(f, "%u %s %s", id, hash_name, random() % 2 ? "HEX:" : "");
|
||||
for (i = 0; i < length; i++)
|
||||
fprintf(f, "%02hhX", key[i]);
|
||||
fprintf(f, "\n");
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static void
|
||||
generate_key_file(const char *name, uint32_t *keys)
|
||||
{
|
||||
FILE *f;
|
||||
int i;
|
||||
|
||||
f = fopen(name, "w");
|
||||
TEST_CHECK(f);
|
||||
for (i = 0; i < KEYS; i++)
|
||||
keys[i] = write_random_key(f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void
|
||||
test_unit(void)
|
||||
{
|
||||
int i, j, data_len, auth_len;
|
||||
uint32_t keys[KEYS], key;
|
||||
unsigned char data[100], auth[MAX_HASH_LENGTH];
|
||||
char conf[][100] = {
|
||||
"keyfile "KEYFILE
|
||||
};
|
||||
|
||||
CNF_Initialise(0, 0);
|
||||
for (i = 0; i < sizeof conf / sizeof conf[0]; i++)
|
||||
CNF_ParseLine(NULL, i + 1, conf[i]);
|
||||
|
||||
generate_key_file(KEYFILE, keys);
|
||||
KEY_Initialise();
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
DEBUG_LOG("iteration %d", i);
|
||||
|
||||
if (i) {
|
||||
generate_key_file(KEYFILE, keys);
|
||||
KEY_Reload();
|
||||
}
|
||||
|
||||
UTI_GetRandomBytes(data, sizeof (data));
|
||||
|
||||
for (j = 0; j < KEYS; j++) {
|
||||
TEST_CHECK(KEY_KeyKnown(keys[j]));
|
||||
TEST_CHECK(KEY_GetAuthDelay(keys[j]) >= 0);
|
||||
TEST_CHECK(KEY_GetAuthLength(keys[j]) >= 16);
|
||||
|
||||
data_len = random() % (sizeof (data) + 1);
|
||||
auth_len = KEY_GenerateAuth(keys[j], data, data_len, auth, sizeof (auth));
|
||||
TEST_CHECK(auth_len >= 16);
|
||||
|
||||
TEST_CHECK(KEY_CheckAuth(keys[j], data, data_len, auth, auth_len, auth_len));
|
||||
|
||||
if (j > 0 && keys[j - 1] != keys[j])
|
||||
TEST_CHECK(!KEY_CheckAuth(keys[j - 1], data, data_len, auth, auth_len, auth_len));
|
||||
|
||||
auth_len = random() % auth_len + 1;
|
||||
if (auth_len < MAX_HASH_LENGTH)
|
||||
auth[auth_len]++;
|
||||
TEST_CHECK(KEY_CheckAuth(keys[j], data, data_len, auth, auth_len, auth_len));
|
||||
|
||||
auth[auth_len - 1]++;
|
||||
TEST_CHECK(!KEY_CheckAuth(keys[j], data, data_len, auth, auth_len, auth_len));
|
||||
}
|
||||
|
||||
for (j = 0; j < 1000; j++) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
unlink(KEYFILE);
|
||||
|
||||
KEY_Finalise();
|
||||
CNF_Finalise();
|
||||
HSH_Finalise();
|
||||
}
|
||||
299
test/unit/ntp_core.c
Normal file
299
test/unit/ntp_core.c
Normal file
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
**********************************************************************
|
||||
* 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 <config.h>
|
||||
#include <sysincl.h>
|
||||
#include <cmdparse.h>
|
||||
#include <conf.h>
|
||||
#include <keys.h>
|
||||
#include <ntp_io.h>
|
||||
#include <sched.h>
|
||||
#include <local.h>
|
||||
#include "test.h"
|
||||
|
||||
static struct timespec current_time;
|
||||
static NTP_Receive_Buffer req_buffer, res_buffer;
|
||||
static int req_length, res_length;
|
||||
|
||||
#define NIO_OpenServerSocket(addr) ((addr)->ip_addr.family != IPADDR_UNSPEC ? 100 : 0)
|
||||
#define NIO_CloseServerSocket(fd) assert(fd == 100)
|
||||
#define NIO_OpenClientSocket(addr) ((addr)->ip_addr.family != IPADDR_UNSPEC ? 101 : 0)
|
||||
#define NIO_CloseClientSocket(fd) assert(fd == 101)
|
||||
#define NIO_SendPacket(msg, to, from, len, process_tx) (memcpy(&req_buffer, msg, len), req_length = len, 1)
|
||||
#define SCH_AddTimeoutByDelay(delay, handler, arg) (1 ? 102 : (handler(arg), 1))
|
||||
#define SCH_AddTimeoutInClass(delay, separation, randomness, class, handler, arg) \
|
||||
add_timeout_in_class(delay, separation, randomness, class, handler, arg)
|
||||
#define SCH_RemoveTimeout(id) assert(!id || id == 102)
|
||||
#define LCL_ReadRawTime(ts) (*ts = current_time)
|
||||
#define LCL_ReadCookedTime(ts, err) do {double *p = err; *ts = current_time; if (p) *p = 0.0;} while (0)
|
||||
#define SRC_UpdateReachability(inst, reach)
|
||||
#define SRC_ResetReachability(inst)
|
||||
|
||||
static SCH_TimeoutID
|
||||
add_timeout_in_class(double min_delay, double separation, double randomness,
|
||||
SCH_TimeoutClass class, SCH_TimeoutHandler handler, SCH_ArbitraryArgument arg)
|
||||
{
|
||||
return 102;
|
||||
}
|
||||
|
||||
#include <ntp_core.c>
|
||||
|
||||
static NCR_Instance inst;
|
||||
|
||||
static void
|
||||
advance_time(double x)
|
||||
{
|
||||
UTI_AddDoubleToTimespec(¤t_time, x, ¤t_time);
|
||||
}
|
||||
|
||||
static void
|
||||
send_request(void)
|
||||
{
|
||||
NTP_Local_Address local_addr;
|
||||
NTP_Local_Timestamp local_ts;
|
||||
uint32_t prev_tx_count;
|
||||
|
||||
prev_tx_count = inst->report.total_tx_count;
|
||||
|
||||
transmit_timeout(inst);
|
||||
TEST_CHECK(!inst->valid_rx);
|
||||
TEST_CHECK(!inst->updated_timestamps);
|
||||
TEST_CHECK(prev_tx_count + 1 == inst->report.total_tx_count);
|
||||
|
||||
advance_time(1e-4);
|
||||
|
||||
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||
local_addr.if_index = INVALID_IF_INDEX;
|
||||
local_addr.sock_fd = 101;
|
||||
local_ts.ts = current_time;
|
||||
local_ts.err = 0.0;
|
||||
local_ts.source = NTP_TS_DAEMON;
|
||||
|
||||
NCR_ProcessTxKnown(inst, &local_addr, &local_ts, &req_buffer.ntp_pkt, req_length);
|
||||
}
|
||||
|
||||
static void
|
||||
send_response(int interleaved, int authenticated, int allow_update, int valid_ts, int valid_auth)
|
||||
{
|
||||
NTP_Packet *req, *res;
|
||||
|
||||
req = &req_buffer.ntp_pkt;
|
||||
res = &res_buffer.ntp_pkt;
|
||||
|
||||
TEST_CHECK(req_length >= NTP_NORMAL_PACKET_LENGTH);
|
||||
|
||||
res->lvm = NTP_LVM(LEAP_Normal, NTP_LVM_TO_VERSION(req->lvm),
|
||||
NTP_LVM_TO_MODE(req->lvm) == MODE_CLIENT ? MODE_SERVER : MODE_ACTIVE);
|
||||
res->stratum = 1;
|
||||
res->poll = req->poll;
|
||||
res->precision = -20;
|
||||
res->root_delay = UTI_DoubleToNtp32(0.1);
|
||||
res->root_dispersion = UTI_DoubleToNtp32(0.1);
|
||||
res->reference_id = 0;
|
||||
UTI_ZeroNtp64(&res->reference_ts);
|
||||
res->originate_ts = interleaved ? req->receive_ts : req->transmit_ts;
|
||||
|
||||
advance_time(TST_GetRandomDouble(1e-4, 1e-2));
|
||||
UTI_TimespecToNtp64(¤t_time, &res->receive_ts, NULL);
|
||||
advance_time(TST_GetRandomDouble(-1e-4, 1e-3));
|
||||
UTI_TimespecToNtp64(¤t_time, &res->transmit_ts, NULL);
|
||||
advance_time(TST_GetRandomDouble(1e-4, 1e-2));
|
||||
|
||||
if (!valid_ts) {
|
||||
switch (random() % (allow_update ? 4 : 5)) {
|
||||
case 0:
|
||||
res->originate_ts.hi = random();
|
||||
break;
|
||||
case 1:
|
||||
res->originate_ts.lo = random();
|
||||
break;
|
||||
case 2:
|
||||
UTI_ZeroNtp64(&res->originate_ts);
|
||||
break;
|
||||
case 3:
|
||||
UTI_ZeroNtp64(&res->receive_ts);
|
||||
break;
|
||||
case 4:
|
||||
UTI_ZeroNtp64(&res->transmit_ts);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (authenticated) {
|
||||
res->auth_keyid = req->auth_keyid;
|
||||
KEY_GenerateAuth(ntohl(res->auth_keyid), (unsigned char *)res, NTP_NORMAL_PACKET_LENGTH,
|
||||
res->auth_data, 16);
|
||||
res_length = NTP_NORMAL_PACKET_LENGTH + 4 + 16;
|
||||
} else {
|
||||
res_length = NTP_NORMAL_PACKET_LENGTH;
|
||||
}
|
||||
|
||||
if (!valid_auth) {
|
||||
switch (random() % 3) {
|
||||
case 0:
|
||||
res->auth_keyid++;
|
||||
break;
|
||||
case 1:
|
||||
res->auth_data[random() % 16]++;
|
||||
break;
|
||||
case 2:
|
||||
res_length = NTP_NORMAL_PACKET_LENGTH;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
process_response(int valid, int updated)
|
||||
{
|
||||
NTP_Local_Address local_addr;
|
||||
NTP_Local_Timestamp local_ts;
|
||||
NTP_Packet *res;
|
||||
uint32_t prev_rx_count, prev_valid_count;
|
||||
struct timespec prev_rx_ts;
|
||||
int prev_open_socket;
|
||||
|
||||
res = &res_buffer.ntp_pkt;
|
||||
|
||||
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||
local_addr.if_index = INVALID_IF_INDEX;
|
||||
local_addr.sock_fd = NTP_LVM_TO_MODE(res->lvm) == MODE_ACTIVE ? 100 : 101;
|
||||
local_ts.ts = current_time;
|
||||
local_ts.err = 0.0;
|
||||
local_ts.source = NTP_TS_DAEMON;
|
||||
|
||||
prev_rx_count = inst->report.total_rx_count;
|
||||
prev_valid_count = inst->report.total_valid_count;
|
||||
prev_rx_ts = inst->local_rx.ts;
|
||||
prev_open_socket = inst->local_addr.sock_fd != INVALID_SOCK_FD;
|
||||
|
||||
NCR_ProcessRxKnown(inst, &local_addr, &local_ts, res, res_length);
|
||||
|
||||
if (prev_open_socket)
|
||||
TEST_CHECK(prev_rx_count + 1 == inst->report.total_rx_count);
|
||||
else
|
||||
TEST_CHECK(prev_rx_count == inst->report.total_rx_count);
|
||||
|
||||
if (valid)
|
||||
TEST_CHECK(prev_valid_count + 1 == inst->report.total_valid_count);
|
||||
else
|
||||
TEST_CHECK(prev_valid_count == inst->report.total_valid_count);
|
||||
|
||||
if (updated)
|
||||
TEST_CHECK(UTI_CompareTimespecs(&inst->local_rx.ts, &prev_rx_ts));
|
||||
else
|
||||
TEST_CHECK(!UTI_CompareTimespecs(&inst->local_rx.ts, &prev_rx_ts));
|
||||
}
|
||||
|
||||
void
|
||||
test_unit(void)
|
||||
{
|
||||
char source_line[] = "127.0.0.1";
|
||||
char conf[][100] = {
|
||||
"port 0",
|
||||
"keyfile ntp_core.keys"
|
||||
};
|
||||
int i, j, interleaved, authenticated, valid, updated, has_updated;
|
||||
CPS_NTP_Source source;
|
||||
NTP_Remote_Address remote_addr;
|
||||
|
||||
CNF_Initialise(0, 0);
|
||||
for (i = 0; i < sizeof conf / sizeof conf[0]; i++)
|
||||
CNF_ParseLine(NULL, i + 1, conf[i]);
|
||||
|
||||
LCL_Initialise();
|
||||
TST_RegisterDummyDrivers();
|
||||
SCH_Initialise();
|
||||
SRC_Initialise();
|
||||
NIO_Initialise(IPADDR_UNSPEC);
|
||||
NCR_Initialise();
|
||||
REF_Initialise();
|
||||
KEY_Initialise();
|
||||
|
||||
for (i = 0; i < 1000; i++) {
|
||||
CPS_ParseNTPSourceAdd(source_line, &source);
|
||||
if (random() % 2)
|
||||
source.params.interleaved = 1;
|
||||
if (random() % 2)
|
||||
source.params.authkey = 1;
|
||||
|
||||
UTI_ZeroTimespec(¤t_time);
|
||||
advance_time(TST_GetRandomDouble(1.0, 1e9));
|
||||
|
||||
TST_GetRandomAddress(&remote_addr.ip_addr, IPADDR_UNSPEC, -1);
|
||||
remote_addr.port = 123;
|
||||
|
||||
inst = NCR_GetInstance(&remote_addr, random() % 2 ? NTP_SERVER : NTP_PEER, &source.params);
|
||||
NCR_StartInstance(inst);
|
||||
has_updated = 0;
|
||||
|
||||
for (j = 0; j < 50; j++) {
|
||||
DEBUG_LOG("iteration %d, %d", i, j);
|
||||
|
||||
interleaved = random() % 2;
|
||||
authenticated = random() % 2;
|
||||
valid = (!interleaved || (source.params.interleaved && has_updated)) &&
|
||||
(!source.params.authkey || authenticated);
|
||||
updated = (valid || inst->mode == MODE_ACTIVE) &&
|
||||
(!source.params.authkey || authenticated);
|
||||
has_updated = has_updated || updated;
|
||||
|
||||
send_request();
|
||||
|
||||
send_response(interleaved, authenticated, 1, 0, 1);
|
||||
process_response(0, inst->mode == MODE_CLIENT ? 0 : updated);
|
||||
|
||||
if (source.params.authkey) {
|
||||
send_response(interleaved, authenticated, 1, 1, 0);
|
||||
process_response(0, 0);
|
||||
}
|
||||
|
||||
send_response(interleaved, authenticated, 1, 1, 1);
|
||||
process_response(valid, updated);
|
||||
process_response(0, 0);
|
||||
|
||||
advance_time(-1.0);
|
||||
|
||||
send_response(interleaved, authenticated, 1, 1, 1);
|
||||
process_response(0, 0);
|
||||
|
||||
advance_time(1.0);
|
||||
|
||||
send_response(interleaved, authenticated, 1, 1, 1);
|
||||
process_response(0, inst->mode == MODE_CLIENT ? 0 : updated);
|
||||
}
|
||||
|
||||
NCR_DestroyInstance(inst);
|
||||
}
|
||||
|
||||
KEY_Finalise();
|
||||
REF_Finalise();
|
||||
NCR_Finalise();
|
||||
NIO_Finalise();
|
||||
SRC_Finalise();
|
||||
SCH_Finalise();
|
||||
LCL_Finalise();
|
||||
CNF_Finalise();
|
||||
HSH_Finalise();
|
||||
}
|
||||
2
test/unit/ntp_core.keys
Normal file
2
test/unit/ntp_core.keys
Normal file
@@ -0,0 +1,2 @@
|
||||
1 MD5 HEX:38979C567358C0896F4D9D459A3C8B8478654579
|
||||
2 MD5 HEX:38979C567358C0896F4D9D459A3C8B8478654579
|
||||
@@ -34,7 +34,7 @@ test_unit(void)
|
||||
|
||||
memset(¶ms, 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, ¶ms);
|
||||
@@ -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++) {
|
||||
@@ -96,4 +96,5 @@ test_unit(void)
|
||||
SCH_Finalise();
|
||||
LCL_Finalise();
|
||||
CNF_Finalise();
|
||||
HSH_Finalise();
|
||||
}
|
||||
|
||||
119
test/unit/regress.c
Normal file
119
test/unit/regress.c
Normal file
@@ -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))
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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,7 +51,7 @@ 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_UpdateReachability(srcs[j], 1);
|
||||
@@ -68,7 +68,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 +81,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 +114,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));
|
||||
@@ -134,4 +134,5 @@ test_unit(void)
|
||||
SCH_Finalise();
|
||||
LCL_Finalise();
|
||||
CNF_Finalise();
|
||||
HSH_Finalise();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -74,6 +79,14 @@ void test_unit(void) {
|
||||
TEST_CHECK(!UTI_IsZeroTimespec(&ts));
|
||||
TEST_CHECK(!UTI_IsZeroNtp64(&ntp_ts));
|
||||
|
||||
ntp_ts.hi = 0;
|
||||
ntp_ts.lo = 0;
|
||||
|
||||
UTI_Ntp64ToTimespec(&ntp_ts, &ts);
|
||||
TEST_CHECK(UTI_IsZeroTimespec(&ts));
|
||||
UTI_TimespecToNtp64(&ts, &ntp_ts, NULL);
|
||||
TEST_CHECK(UTI_IsZeroNtp64(&ntp_ts));
|
||||
|
||||
ntp_fuzz.hi = htonl(1);
|
||||
ntp_fuzz.lo = htonl(3);
|
||||
ntp_ts.hi = htonl(1);
|
||||
@@ -137,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] == '>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
94
util.c
94
util.c
@@ -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);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -329,12 +329,14 @@ UTI_StringToIP(const char *addr, IPAddr *ip)
|
||||
|
||||
if (inet_pton(AF_INET, addr, &in4) > 0) {
|
||||
ip->family = IPADDR_INET4;
|
||||
ip->_pad = 0;
|
||||
ip->addr.in4 = ntohl(in4.s_addr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (inet_pton(AF_INET6, addr, &in6) > 0) {
|
||||
ip->family = IPADDR_INET6;
|
||||
ip->_pad = 0;
|
||||
memcpy(ip->addr.in6, in6.s6_addr, sizeof (ip->addr.in6));
|
||||
return 1;
|
||||
}
|
||||
@@ -344,6 +346,7 @@ UTI_StringToIP(const char *addr, IPAddr *ip)
|
||||
n = sscanf(addr, "%lu.%lu.%lu.%lu", &a, &b, &c, &d);
|
||||
if (n == 4) {
|
||||
ip->family = IPADDR_INET4;
|
||||
ip->_pad = 0;
|
||||
ip->addr.in4 = ((a & 0xff) << 24) | ((b & 0xff) << 16) |
|
||||
((c & 0xff) << 8) | (d & 0xff);
|
||||
return 1;
|
||||
@@ -442,6 +445,7 @@ void
|
||||
UTI_IPNetworkToHost(IPAddr *src, IPAddr *dest)
|
||||
{
|
||||
dest->family = ntohs(src->family);
|
||||
dest->_pad = 0;
|
||||
|
||||
switch (dest->family) {
|
||||
case IPADDR_INET4:
|
||||
@@ -554,7 +558,7 @@ char *UTI_SockaddrToString(struct sockaddr *sa)
|
||||
{
|
||||
unsigned short port;
|
||||
IPAddr ip;
|
||||
char *result;
|
||||
char *result, *sun_path;
|
||||
|
||||
result = NEXT_BUFFER;
|
||||
|
||||
@@ -567,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]");
|
||||
@@ -754,8 +762,11 @@ UTI_Ntp64ToTimespec(NTP_int64 *src, struct timespec *dest)
|
||||
{
|
||||
uint32_t ntp_sec, ntp_frac;
|
||||
|
||||
/* As yet, there is no need to check for zero - all processing that
|
||||
has to detect that case is in the NTP layer */
|
||||
/* Zero is a special value */
|
||||
if (UTI_IsZeroNtp64(src)) {
|
||||
UTI_ZeroTimespec(dest);
|
||||
return;
|
||||
}
|
||||
|
||||
ntp_sec = ntohl(src->hi);
|
||||
ntp_frac = ntohl(src->lo);
|
||||
@@ -767,9 +778,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;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -829,12 +838,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);
|
||||
@@ -846,7 +854,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 = CLAMP(0U, nsec, 999999999U);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1031,25 +1040,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;
|
||||
@@ -1118,27 +1127,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;
|
||||
}
|
||||
|
||||
@@ -1152,17 +1161,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);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1177,18 +1186,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
|
||||
|
||||
Reference in New Issue
Block a user