mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-03 17:55:07 -05:00
Compare commits
278 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42a85f685e | ||
|
|
feca2399e4 | ||
|
|
d34e611ec8 | ||
|
|
02098ed830 | ||
|
|
aa4228bf1b | ||
|
|
b296441708 | ||
|
|
b827475378 | ||
|
|
78a6698ae1 | ||
|
|
e7b6feb34b | ||
|
|
84be834385 | ||
|
|
e83d808dfd | ||
|
|
35a68d5b59 | ||
|
|
3c593137b0 | ||
|
|
deaf0ffed3 | ||
|
|
af145e871e | ||
|
|
fbca570d0b | ||
|
|
448ef779c2 | ||
|
|
499a69e611 | ||
|
|
58c2915878 | ||
|
|
eda4b111d3 | ||
|
|
c6dd749687 | ||
|
|
d2a96f5fbc | ||
|
|
499f513d40 | ||
|
|
8b1f68b1b4 | ||
|
|
8e4c776900 | ||
|
|
d0eb9427c2 | ||
|
|
7d100b89fc | ||
|
|
a4bd7f1800 | ||
|
|
5308e0a25f | ||
|
|
da862158bf | ||
|
|
7b98443a13 | ||
|
|
4da9f74d24 | ||
|
|
e41042e258 | ||
|
|
5581466c63 | ||
|
|
e79a6c2116 | ||
|
|
666ece122e | ||
|
|
2c7ab98370 | ||
|
|
f0f18a02a7 | ||
|
|
c5d8af0285 | ||
|
|
0ce15a8472 | ||
|
|
da60629201 | ||
|
|
2343e7a89c | ||
|
|
45f27f4f5e | ||
|
|
0bc112f8b4 | ||
|
|
bfc2fa645c | ||
|
|
11111804fd | ||
|
|
87ec67247e | ||
|
|
0df8328ceb | ||
|
|
b563048ee2 | ||
|
|
e8096330be | ||
|
|
b1647dbcb7 | ||
|
|
4ddadd5622 | ||
|
|
3e854006c7 | ||
|
|
2c4c235147 | ||
|
|
6863e43269 | ||
|
|
de8708f331 | ||
|
|
d0b2486036 | ||
|
|
5384a93645 | ||
|
|
4bbc768652 | ||
|
|
fead915b45 | ||
|
|
5422e49026 | ||
|
|
77a1f27a1d | ||
|
|
b45d864f73 | ||
|
|
f35c81c871 | ||
|
|
a349b2803c | ||
|
|
f5d1b8fb74 | ||
|
|
a0fe71eef1 | ||
|
|
154b39cf7a | ||
|
|
6f54210db2 | ||
|
|
f6539449c5 | ||
|
|
b8d546a0d1 | ||
|
|
04e6474b75 | ||
|
|
eb51c500e8 | ||
|
|
6f8fba9a3f | ||
|
|
750afc30f2 | ||
|
|
e0e6ec0d84 | ||
|
|
c9f50fc686 | ||
|
|
83c26b458b | ||
|
|
b711873f45 | ||
|
|
c68ca40ce4 | ||
|
|
51fe80ad95 | ||
|
|
7ffee73524 | ||
|
|
f40b0024bd | ||
|
|
a06c9909a6 | ||
|
|
aee42fada8 | ||
|
|
3e93068c43 | ||
|
|
36291b707b | ||
|
|
6dad2c24bf | ||
|
|
27cbf20d23 | ||
|
|
5c571bbbe7 | ||
|
|
33d65c8614 | ||
|
|
d87db7cdb8 | ||
|
|
45fa4750da | ||
|
|
8472fd8133 | ||
|
|
5ab645e310 | ||
|
|
8ccda538d3 | ||
|
|
b06d74ab73 | ||
|
|
d0964ffa83 | ||
|
|
3d08815efb | ||
|
|
a83f0d3cdc | ||
|
|
702db726d3 | ||
|
|
ed5c43204b | ||
|
|
f91bdd604d | ||
|
|
3a1dbb1354 | ||
|
|
4b511143b8 | ||
|
|
93076e7e1c | ||
|
|
1c51feb3c5 | ||
|
|
c2773dbc2f | ||
|
|
4534db84c4 | ||
|
|
be8215e181 | ||
|
|
ae82bbbace | ||
|
|
2b6ea41062 | ||
|
|
d9f745fe70 | ||
|
|
9aac179367 | ||
|
|
b896bb5a78 | ||
|
|
64c2fd9888 | ||
|
|
2668a12e4e | ||
|
|
e1645966ec | ||
|
|
4f1fc1ee78 | ||
|
|
d70df3daab | ||
|
|
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 |
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
|
||||
|
||||
77
NEWS
77
NEWS
@@ -1,3 +1,77 @@
|
||||
New in version 3.3
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add burst option to server/pool directive
|
||||
* Add stratum and tai options to refclock directive
|
||||
* Add support for Nettle crypto library
|
||||
* Add workaround for missing kernel receive timestamps on Linux
|
||||
* Wait for late hardware transmit timestamps
|
||||
* Improve source selection with unreachable sources
|
||||
* Improve protection against replay attacks on symmetric mode
|
||||
* Allow PHC refclock to use socket in /var/run/chrony
|
||||
* Add shutdown command to stop chronyd
|
||||
* Simplify format of response to manual list command
|
||||
* Improve handling of unknown responses in chronyc
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Respond to NTPv1 client requests with zero mode
|
||||
* Fix -x option to not require CAP_SYS_TIME under non-root user
|
||||
* Fix chronyc to not get stuck in infinite loop after clock step
|
||||
|
||||
New in version 3.2
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Improve stability with NTP sources and reference clocks
|
||||
* Improve stability with hardware timestamping
|
||||
* Improve support for NTP interleaved modes
|
||||
* Control frequency of system clock on macOS 10.13 and later
|
||||
* Set TAI-UTC offset of system clock with leapsectz directive
|
||||
* Minimise data in client requests to improve privacy
|
||||
* Allow transmit-only hardware timestamping
|
||||
* Add support for new timestamping options introduced in Linux 4.13
|
||||
* Add root delay, root dispersion and maximum error to tracking log
|
||||
* Add mindelay and asymmetry options to server/peer/pool directive
|
||||
* Add extpps option to PHC refclock to timestamp external PPS signal
|
||||
* Add pps option to refclock directive to treat any refclock as PPS
|
||||
* Add width option to refclock directive to filter wrong pulse edges
|
||||
* Add rxfilter option to hwtimestamp directive
|
||||
* Add -x option to disable control of system clock
|
||||
* Add -l option to log to specified file instead of syslog
|
||||
* Allow multiple command-line options to be specified together
|
||||
* Allow starting without root privileges with -Q option
|
||||
* Update seccomp filter for new glibc versions
|
||||
* Dump history on exit by default with dumpdir directive
|
||||
* Use hardening compiler options by default
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Don't drop PHC samples with low-resolution system clock
|
||||
* Ignore outliers in PHC tracking, RTC tracking, manual input
|
||||
* Increase polling interval when peer is not responding
|
||||
* Exit with error message when include directive fails
|
||||
* Don't allow slash after hostname in allow/deny directive/command
|
||||
* Try to connect to all addresses in chronyc before giving up
|
||||
|
||||
New in version 3.1
|
||||
==================
|
||||
|
||||
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,8 +90,7 @@ 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
|
||||
* Enable NTP response rate limiting by default
|
||||
(1024 packets per second per IP address and 25% leak)
|
||||
* 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
|
||||
|
||||
52
README
52
README
@@ -4,7 +4,7 @@ What is chrony?
|
||||
===============
|
||||
|
||||
chrony is a versatile implementation of the Network Time Protocol (NTP).
|
||||
It can synchronize the system clock with NTP servers, reference clocks
|
||||
It can synchronise the system clock with NTP servers, reference clocks
|
||||
(e.g. GPS receiver), and manual input using wristwatch and keyboard.
|
||||
It can also operate as an NTPv4 (RFC 5905) server and peer to provide
|
||||
a time service to other computers in the network.
|
||||
@@ -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
|
||||
@@ -37,20 +37,16 @@ How do I set it up?
|
||||
===================
|
||||
|
||||
The file INSTALL gives instructions. On supported systems the
|
||||
compilation process should be automatic.
|
||||
|
||||
You will need an ANSI C compiler -- gcc is recommended.
|
||||
|
||||
The manual (in texinfo and text formats) describes how to set the
|
||||
software up for the less straightforward cases.
|
||||
compilation process should be automatic. You will need a C compiler,
|
||||
e.g. gcc or clang.
|
||||
|
||||
What documentation is there?
|
||||
============================
|
||||
|
||||
A manual is supplied in Texinfo format (chrony.texi) and
|
||||
ready-formatted plain text (chrony.txt) in the distribution.
|
||||
The distribution includes manual pages and a document containing
|
||||
Frequently Asked Questions (FAQ).
|
||||
|
||||
There is also information available on the chrony web pages, accessible
|
||||
The documentation is also available on the chrony web pages, accessible
|
||||
through the URL
|
||||
|
||||
https://chrony.tuxfamily.org/
|
||||
@@ -126,7 +122,7 @@ Andrew Bishop <amb@gedanken.demon.co.uk>
|
||||
Improvements to 'sources' and 'sourcestats' output from chronyc
|
||||
Improvements to documentation
|
||||
Investigation of required dosynctodr behaviour for various Solaris
|
||||
versions.
|
||||
versions
|
||||
|
||||
Stephan I. Boettcher <stephan@nevis1.columbia.edu>
|
||||
Entries in contrib directory
|
||||
@@ -140,27 +136,27 @@ Bryan Christianson <bryan@whatroute.net>
|
||||
Entries in contrib directory
|
||||
|
||||
Juliusz Chroboczek <jch@pps.jussieu.fr>
|
||||
Fix install rule in Makefile if chronyd file is in use.
|
||||
Patch to fix install rule in Makefile if chronyd file is in use
|
||||
|
||||
Christian Ehrhardt <christian.ehrhardt@canonical.com>
|
||||
Patch to generate a warning message when CAP_SYS_TIME is missing
|
||||
|
||||
Paul Elliott <pelliott@io.com>
|
||||
DNSchrony (in contrib directory), a tool for handling NTP servers
|
||||
with variable IP addresses.
|
||||
Entries in contrib directory
|
||||
|
||||
Mike Fleetwood <mike@rockover.demon.co.uk>
|
||||
Fixes for compiler warnings
|
||||
|
||||
Alexander Gretencord <arutha@gmx.de>
|
||||
Changes to installation directory system to make it easier for
|
||||
package builders.
|
||||
package builders
|
||||
|
||||
Andrew Griffiths <agriffit@redhat.com>
|
||||
Patch to add support for seccomp filter
|
||||
|
||||
Walter Haidinger <walter.haidinger@gmx.at>
|
||||
Providing me with login access to a Linux installation where v1.12
|
||||
wouldn't compile, so I could develop the fixes for v1.13. Also, for
|
||||
providing the disc space so I can keep an independent backup of the
|
||||
sources.
|
||||
Access to a Linux installation where v1.12 wouldn't compile
|
||||
Disc space for an independent backup of the sources
|
||||
|
||||
Juergen Hannken-Illjes <hannken@eis.cs.tu-bs.de>
|
||||
Port to NetBSD
|
||||
@@ -170,7 +166,7 @@ John Hasler <john@dhh.gt.org>
|
||||
Changes to support 64 bit machines (i.e. those where
|
||||
sizeof(unsigned long) > 4)
|
||||
Bug fix to initstepslew directive
|
||||
Fix to remove potential buffer overrun errors.
|
||||
Fix to remove potential buffer overrun errors
|
||||
Memory locking and real-time scheduler support
|
||||
Fix fault where chronyd enters an endless loop
|
||||
|
||||
@@ -198,17 +194,26 @@ Victor Moroz <vim@prv.adlum.ru>
|
||||
Patch to support Linux with HZ!=100
|
||||
|
||||
Kalle Olavi Niemitalo <tosi@stekt.oulu.fi>
|
||||
acquisitionport support
|
||||
Patch to add acquisitionport directive
|
||||
|
||||
Frank Otto <sandwichmacher@web.de>
|
||||
Handling arbitrary HZ values
|
||||
|
||||
Denny Page <dennypage@me.com>
|
||||
Advice on support for hardware timestamping
|
||||
|
||||
Chris Perl <cperl@janestreet.com>
|
||||
Patches to improve support for refclocks keeping time in TAI
|
||||
|
||||
Gautier PHILIPPON <gautier.philippon@ensimag.grenoble-inp.fr>
|
||||
Patch to add refresh command to chronyc
|
||||
|
||||
Andreas Piesk <apiesk@virbus.de>
|
||||
Patch to make chronyc use the readline library if available
|
||||
|
||||
Andreas Steinmetz <ast@domdv.de>
|
||||
Patch to make stratum of refclocks configurable
|
||||
|
||||
Timo Teras <timo.teras@iki.fi>
|
||||
Patch to reply correctly on multihomed hosts
|
||||
|
||||
@@ -225,8 +230,7 @@ Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
|
||||
Many robustness and security improvements
|
||||
|
||||
Ulrich Windl <ulrich.windl@rz.uni-regensburg.de> for the
|
||||
Providing me with information about the Linux 2.2 kernel
|
||||
functionality compared to 2.0.
|
||||
Information about the Linux 2.2 kernel functionality compared to 2.0
|
||||
|
||||
Doug Woodward <dougw@whistler.com>
|
||||
Advice on configuring for Solaris 2.8 on x86
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
7
array.c
7
array.c
@@ -66,8 +66,6 @@ ARR_DestroyInstance(ARR_Instance array)
|
||||
static void
|
||||
realloc_array(ARR_Instance array, unsigned int min_size)
|
||||
{
|
||||
size_t data_size;
|
||||
|
||||
assert(min_size <= 2 * min_size);
|
||||
if (array->allocated >= min_size && array->allocated <= 2 * min_size)
|
||||
return;
|
||||
@@ -79,10 +77,7 @@ realloc_array(ARR_Instance array, unsigned int min_size)
|
||||
array->allocated = min_size;
|
||||
}
|
||||
|
||||
data_size = (size_t)array->elem_size * array->allocated;
|
||||
assert(data_size / array->elem_size == array->allocated);
|
||||
|
||||
array->data = Realloc(array->data, data_size);
|
||||
array->data = Realloc2(array->data, array->allocated, array->elem_size);
|
||||
}
|
||||
|
||||
void *
|
||||
|
||||
20
candm.h
20
candm.h
@@ -97,7 +97,10 @@
|
||||
#define REQ_NTP_DATA 57
|
||||
#define REQ_ADD_SERVER2 58
|
||||
#define REQ_ADD_PEER2 59
|
||||
#define N_REQUEST_TYPES 60
|
||||
#define REQ_ADD_SERVER3 60
|
||||
#define REQ_ADD_PEER3 61
|
||||
#define REQ_SHUTDOWN 62
|
||||
#define N_REQUEST_TYPES 63
|
||||
|
||||
/* Structure used to exchange timespecs independent of time_t size */
|
||||
typedef struct {
|
||||
@@ -250,6 +253,7 @@ typedef struct {
|
||||
#define REQ_ADDSRC_TRUST 0x20
|
||||
#define REQ_ADDSRC_REQUIRE 0x40
|
||||
#define REQ_ADDSRC_INTERLEAVED 0x80
|
||||
#define REQ_ADDSRC_BURST 0x100
|
||||
|
||||
typedef struct {
|
||||
IPAddr ip_addr;
|
||||
@@ -267,8 +271,11 @@ typedef struct {
|
||||
Float max_delay;
|
||||
Float max_delay_ratio;
|
||||
Float max_delay_dev_ratio;
|
||||
Float min_delay;
|
||||
Float asymmetry;
|
||||
Float offset;
|
||||
uint32_t flags;
|
||||
uint32_t reserved[4];
|
||||
int32_t EOR;
|
||||
} REQ_NTP_Source;
|
||||
|
||||
@@ -362,8 +369,9 @@ typedef struct {
|
||||
domain socket.
|
||||
|
||||
Version 6 (no authentication) : changed format of client accesses by index
|
||||
(using new request/reply types), new fields and flags in NTP source request
|
||||
and report, new commands: ntpdata, refresh, serverstats
|
||||
(using new request/reply types) and manual timestamp, added new fields and
|
||||
flags to NTP source request and report, made length of manual list constant,
|
||||
added new commands: ntpdata, refresh, serverstats, shutdown
|
||||
*/
|
||||
|
||||
#define PROTO_VERSION_NUMBER 6
|
||||
@@ -461,7 +469,9 @@ 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 RPY_MANUAL_LIST2 18
|
||||
#define N_REPLY_TYPES 19
|
||||
|
||||
/* Status codes */
|
||||
#define STT_SUCCESS 0
|
||||
@@ -569,7 +579,7 @@ typedef struct {
|
||||
} RPY_Rtc;
|
||||
|
||||
typedef struct {
|
||||
uint32_t centiseconds;
|
||||
Float offset;
|
||||
Float dfreq_ppm;
|
||||
Float new_afreq_ppm;
|
||||
int32_t EOR;
|
||||
|
||||
357
client.c
357
client.c
@@ -3,7 +3,8 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2009-2016
|
||||
* Copyright (C) Lonnie Abelbeck 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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1102,16 +1101,21 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
|
||||
msg->data.ntp_source.max_delay_ratio = UTI_FloatHostToNetwork(data.params.max_delay_ratio);
|
||||
msg->data.ntp_source.max_delay_dev_ratio =
|
||||
UTI_FloatHostToNetwork(data.params.max_delay_dev_ratio);
|
||||
msg->data.ntp_source.min_delay = UTI_FloatHostToNetwork(data.params.min_delay);
|
||||
msg->data.ntp_source.asymmetry = UTI_FloatHostToNetwork(data.params.asymmetry);
|
||||
msg->data.ntp_source.offset = UTI_FloatHostToNetwork(data.params.offset);
|
||||
msg->data.ntp_source.flags = htonl(
|
||||
(data.params.online ? REQ_ADDSRC_ONLINE : 0) |
|
||||
(data.params.auto_offline ? REQ_ADDSRC_AUTOOFFLINE : 0) |
|
||||
(data.params.iburst ? REQ_ADDSRC_IBURST : 0) |
|
||||
(data.params.interleaved ? REQ_ADDSRC_INTERLEAVED : 0) |
|
||||
(data.params.burst ? REQ_ADDSRC_BURST : 0) |
|
||||
(data.params.sel_options & SRC_SELECT_PREFER ? REQ_ADDSRC_PREFER : 0) |
|
||||
(data.params.sel_options & SRC_SELECT_NOSELECT ? REQ_ADDSRC_NOSELECT : 0) |
|
||||
(data.params.sel_options & SRC_SELECT_TRUST ? REQ_ADDSRC_TRUST : 0) |
|
||||
(data.params.sel_options & SRC_SELECT_REQUIRE ? REQ_ADDSRC_REQUIRE : 0));
|
||||
memset(msg->data.ntp_source.reserved, 0, sizeof (msg->data.ntp_source.reserved));
|
||||
|
||||
result = 1;
|
||||
|
||||
break;
|
||||
@@ -1125,7 +1129,7 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
|
||||
static int
|
||||
process_cmd_add_server(CMD_Request *msg, char *line)
|
||||
{
|
||||
msg->command = htons(REQ_ADD_SERVER2);
|
||||
msg->command = htons(REQ_ADD_SERVER3);
|
||||
return process_cmd_add_server_or_peer(msg, line);
|
||||
}
|
||||
|
||||
@@ -1134,7 +1138,7 @@ process_cmd_add_server(CMD_Request *msg, char *line)
|
||||
static int
|
||||
process_cmd_add_peer(CMD_Request *msg, char *line)
|
||||
{
|
||||
msg->command = htons(REQ_ADD_PEER2);
|
||||
msg->command = htons(REQ_ADD_PEER3);
|
||||
return process_cmd_add_server_or_peer(msg, line);
|
||||
}
|
||||
|
||||
@@ -1152,11 +1156,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);
|
||||
@@ -1241,6 +1245,8 @@ 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"
|
||||
"shutdown\0Stop daemon\0"
|
||||
"\0\0"
|
||||
"Client commands:\0\0"
|
||||
"dns -n|+n\0Disable/enable resolving IP addresses to hostnames\0"
|
||||
@@ -1275,9 +1281,9 @@ command_name_generator(const char *text, int state)
|
||||
"maxdelay", "maxdelaydevratio", "maxdelayratio", "maxpoll",
|
||||
"maxupdateskew", "minpoll", "minstratum", "ntpdata", "offline", "online",
|
||||
"polltarget", "quit", "refresh", "rekey", "reselect", "reselectdist",
|
||||
"retries", "rtcdata", "serverstats", "settime", "smoothing", "smoothtime",
|
||||
"sources", "sources -v", "sourcestats", "sourcestats -v", "timeout",
|
||||
"tracking", "trimrtc", "waitsync", "writertc",
|
||||
"retries", "rtcdata", "serverstats", "settime", "shutdown", "smoothing",
|
||||
"smoothtime", "sources", "sources -v", "sourcestats", "sourcestats -v",
|
||||
"timeout", "tracking", "trimrtc", "waitsync", "writertc",
|
||||
NULL
|
||||
};
|
||||
static int list_index, len;
|
||||
@@ -1320,18 +1326,16 @@ static int proto_version = PROTO_VERSION_NUMBER;
|
||||
static int
|
||||
submit_request(CMD_Request *request, CMD_Reply *reply)
|
||||
{
|
||||
int bad_length, bad_sequence, bad_header;
|
||||
int select_status;
|
||||
int recv_status;
|
||||
int read_length;
|
||||
int expected_length;
|
||||
int command_length;
|
||||
int padding_length;
|
||||
struct timespec ts_now, ts_start;
|
||||
struct timeval tv;
|
||||
int n_attempts, new_attempt;
|
||||
double timeout;
|
||||
fd_set rdfd, wrfd, exfd;
|
||||
fd_set rdfd;
|
||||
|
||||
request->pkt_type = PKT_TYPE_CMD_REQUEST;
|
||||
request->res1 = 0;
|
||||
@@ -1343,15 +1347,15 @@ submit_request(CMD_Request *request, CMD_Reply *reply)
|
||||
new_attempt = 1;
|
||||
|
||||
do {
|
||||
if (gettimeofday(&tv, NULL))
|
||||
return 0;
|
||||
|
||||
if (new_attempt) {
|
||||
new_attempt = 0;
|
||||
|
||||
if (n_attempts > max_retries)
|
||||
return 0;
|
||||
|
||||
if (gettimeofday(&tv, NULL))
|
||||
return 0;
|
||||
|
||||
UTI_TimevalToTimespec(&tv, &ts_start);
|
||||
|
||||
UTI_GetRandomBytes(&request->sequence, sizeof (request->sequence));
|
||||
@@ -1367,22 +1371,18 @@ 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))
|
||||
return 0;
|
||||
|
||||
UTI_TimevalToTimespec(&tv, &ts_now);
|
||||
|
||||
/* Check if the clock wasn't stepped back */
|
||||
@@ -1391,22 +1391,27 @@ submit_request(CMD_Request *request, CMD_Reply *reply)
|
||||
|
||||
timeout = initial_timeout / 1000.0 * (1U << (n_attempts - 1)) -
|
||||
UTI_DiffTimespecsToDouble(&ts_now, &ts_start);
|
||||
DEBUG_LOG("Timeout %f seconds", timeout);
|
||||
|
||||
/* Avoid calling select() with an invalid timeout */
|
||||
if (timeout <= 0.0) {
|
||||
new_attempt = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
UTI_DoubleToTimeval(timeout, &tv);
|
||||
DEBUG_LOG(LOGF_Client, "Timeout %f seconds", timeout);
|
||||
|
||||
FD_ZERO(&rdfd);
|
||||
FD_ZERO(&wrfd);
|
||||
FD_ZERO(&exfd);
|
||||
|
||||
FD_SET(sock_fd, &rdfd);
|
||||
|
||||
if (quit)
|
||||
return 0;
|
||||
|
||||
select_status = select(sock_fd + 1, &rdfd, &wrfd, &exfd, &tv);
|
||||
select_status = select(sock_fd + 1, &rdfd, NULL, NULL, &tv);
|
||||
|
||||
if (select_status < 0) {
|
||||
DEBUG_LOG(LOGF_Client, "select failed : %s", strerror(errno));
|
||||
DEBUG_LOG("select failed : %s", strerror(errno));
|
||||
return 0;
|
||||
} else if (select_status == 0) {
|
||||
/* Timeout must have elapsed, try a resend? */
|
||||
new_attempt = 1;
|
||||
@@ -1416,40 +1421,24 @@ 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)) {
|
||||
expected_length = PKL_ReplyLength(reply);
|
||||
} else {
|
||||
expected_length = 0;
|
||||
}
|
||||
|
||||
bad_length = (read_length < expected_length ||
|
||||
expected_length < offsetof(CMD_Reply, data));
|
||||
|
||||
if (!bad_length) {
|
||||
bad_sequence = reply->sequence != request->sequence;
|
||||
} else {
|
||||
bad_sequence = 0;
|
||||
}
|
||||
|
||||
if (bad_length || bad_sequence) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bad_header = ((reply->version != proto_version &&
|
||||
!(reply->version >= PROTO_VERSION_MISMATCH_COMPAT_CLIENT &&
|
||||
ntohs(reply->status) == STT_BADPKTVERSION)) ||
|
||||
(reply->pkt_type != PKT_TYPE_CMD_REPLY) ||
|
||||
(reply->res1 != 0) ||
|
||||
(reply->res2 != 0) ||
|
||||
(reply->command != request->command));
|
||||
|
||||
if (bad_header) {
|
||||
/* Check if the header is valid */
|
||||
if (read_length < offsetof(CMD_Reply, data) ||
|
||||
(reply->version != proto_version &&
|
||||
!(reply->version >= PROTO_VERSION_MISMATCH_COMPAT_CLIENT &&
|
||||
ntohs(reply->status) == STT_BADPKTVERSION)) ||
|
||||
reply->pkt_type != PKT_TYPE_CMD_REPLY ||
|
||||
reply->res1 != 0 ||
|
||||
reply->res2 != 0 ||
|
||||
reply->command != request->command ||
|
||||
reply->sequence != request->sequence) {
|
||||
DEBUG_LOG("Invalid reply");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1468,8 +1457,17 @@ submit_request(CMD_Request *request, CMD_Reply *reply)
|
||||
#error unknown compatibility with PROTO_VERSION - 1
|
||||
#endif
|
||||
|
||||
/* Check that the packet contains all data it is supposed to have.
|
||||
Unknown responses will always pass this test as their expected
|
||||
length is zero. */
|
||||
if (read_length < PKL_ReplyLength(reply)) {
|
||||
DEBUG_LOG("Reply too short");
|
||||
new_attempt = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Good packet received, print out results */
|
||||
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;
|
||||
}
|
||||
@@ -1574,6 +1572,9 @@ request_reply(CMD_Request *request, CMD_Reply *reply, int requested_reply, int v
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure an unknown response was not requested */
|
||||
assert(PKL_ReplyLength(reply));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -2059,7 +2060,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 +2216,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,
|
||||
@@ -2262,7 +2264,7 @@ process_cmd_ntpdata(char *line)
|
||||
for (i = 0; i < n_sources; i++) {
|
||||
if (specified_addr) {
|
||||
if (DNS_Name2IPAddress(line, &remote_addr, 1) != DNS_Success) {
|
||||
LOG(LOGS_ERR, LOGF_Client, "Could not get address for hostname");
|
||||
LOG(LOGS_ERR, "Could not get address for hostname");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
@@ -2301,7 +2303,7 @@ process_cmd_ntpdata(char *line)
|
||||
"Precision : %d (%.9f seconds)\n"
|
||||
"Root delay : %.6f seconds\n"
|
||||
"Root dispersion : %.6f seconds\n"
|
||||
"Reference ID : %R\n"
|
||||
"Reference ID : %R (%s)\n"
|
||||
"Reference time : %T\n"
|
||||
"Offset : %+.9f seconds\n"
|
||||
"Peer delay : %.9f seconds\n"
|
||||
@@ -2325,7 +2327,10 @@ process_cmd_ntpdata(char *line)
|
||||
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), &ref_time,
|
||||
(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),
|
||||
@@ -2416,7 +2421,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;
|
||||
}
|
||||
|
||||
@@ -2533,7 +2538,7 @@ process_cmd_manual_list(const char *line)
|
||||
struct timespec when;
|
||||
|
||||
request.command = htons(REQ_MANUAL_LIST);
|
||||
if (!request_reply(&request, &reply, RPY_MANUAL_LIST, 0))
|
||||
if (!request_reply(&request, &reply, RPY_MANUAL_LIST2, 0))
|
||||
return 0;
|
||||
|
||||
n_samples = ntohl(reply.data.manual_list.n_samples);
|
||||
@@ -2541,7 +2546,7 @@ process_cmd_manual_list(const char *line)
|
||||
|
||||
print_header("# Date Time(UTC) Slewed Original Residual");
|
||||
|
||||
for (i = 0; i < n_samples; i++) {
|
||||
for (i = 0; i < n_samples && i < MAX_MANUAL_LIST_SAMPLES; i++) {
|
||||
sample = &reply.data.manual_list.samples[i];
|
||||
UTI_TimespecNetworkToHost(&sample->when, &when);
|
||||
|
||||
@@ -2564,7 +2569,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;
|
||||
}
|
||||
|
||||
@@ -2582,7 +2587,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;
|
||||
|
||||
@@ -2596,9 +2600,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",
|
||||
@@ -2627,7 +2630,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);
|
||||
@@ -2704,6 +2707,14 @@ process_cmd_refresh(CMD_Request *msg, char *line)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
process_cmd_shutdown(CMD_Request *msg, char *line)
|
||||
{
|
||||
msg->command = htons(REQ_SHUTDOWN);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
process_cmd_waitsync(char *line)
|
||||
{
|
||||
@@ -2720,7 +2731,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)
|
||||
@@ -2775,7 +2787,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;
|
||||
@@ -2790,7 +2802,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;
|
||||
@@ -2805,8 +2817,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;
|
||||
@@ -2828,11 +2840,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;
|
||||
}
|
||||
|
||||
@@ -2997,6 +3010,8 @@ process_line(char *line)
|
||||
} else if (!strcmp(command, "settime")) {
|
||||
do_normal_submit = 0;
|
||||
ret = process_cmd_settime(line);
|
||||
} else if (!strcmp(command, "shutdown")) {
|
||||
process_cmd_shutdown(&tx_message, line);
|
||||
} else if (!strcmp(command, "smoothing")) {
|
||||
do_normal_submit = 0;
|
||||
ret = process_cmd_smoothing(line);
|
||||
@@ -3024,11 +3039,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;
|
||||
}
|
||||
|
||||
@@ -3045,7 +3060,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;
|
||||
@@ -3091,7 +3106,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",
|
||||
@@ -3100,54 +3115,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3155,7 +3196,7 @@ main(int argc, char **argv)
|
||||
on_terminal = 1;
|
||||
}
|
||||
|
||||
if (on_terminal && (argc == 0)) {
|
||||
if (on_terminal && optind == argc) {
|
||||
display_gpl();
|
||||
}
|
||||
|
||||
@@ -3170,10 +3211,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();
|
||||
|
||||
55
clientlog.c
55
clientlog.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2009, 2015-2016
|
||||
* Copyright (C) Miroslav Lichvar 2009, 2015-2017
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -119,7 +119,7 @@ static int cmd_token_shift;
|
||||
prevent an attacker sending requests with spoofed source address
|
||||
from blocking responses to the address completely. */
|
||||
|
||||
#define MIN_LEAK_RATE 0
|
||||
#define MIN_LEAK_RATE 1
|
||||
#define MAX_LEAK_RATE 4
|
||||
|
||||
static int ntp_leak_rate;
|
||||
@@ -128,6 +128,9 @@ static int cmd_leak_rate;
|
||||
/* Flag indicating whether the last response was dropped */
|
||||
#define FLAG_NTP_DROPPED 0x1
|
||||
|
||||
/* NTP limit interval in log2 */
|
||||
static int ntp_limit_interval;
|
||||
|
||||
/* Flag indicating whether facility is turned on or not */
|
||||
static int active;
|
||||
|
||||
@@ -294,7 +297,7 @@ set_bucket_params(int interval, int burst, uint16_t *max_tokens,
|
||||
*tokens_per_packet = 1U << (TS_FRAC + interval - *token_shift);
|
||||
*max_tokens = *tokens_per_packet * burst;
|
||||
|
||||
DEBUG_LOG(LOGF_ClientLog, "Tokens max %d packet %d shift %d",
|
||||
DEBUG_LOG("Tokens max %d packet %d shift %d",
|
||||
*max_tokens, *tokens_per_packet, *token_shift);
|
||||
}
|
||||
|
||||
@@ -305,19 +308,31 @@ CLG_Initialise(void)
|
||||
{
|
||||
int interval, burst, leak_rate;
|
||||
|
||||
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);
|
||||
max_ntp_tokens = max_cmd_tokens = 0;
|
||||
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;
|
||||
|
||||
CNF_GetCommandRateLimit(&interval, &burst, &leak_rate);
|
||||
set_bucket_params(interval, burst, &max_cmd_tokens, &cmd_tokens_per_packet,
|
||||
&cmd_token_shift);
|
||||
cmd_leak_rate = CLAMP(MIN_LEAK_RATE, leak_rate, MAX_LEAK_RATE);
|
||||
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)) {
|
||||
set_bucket_params(interval, burst, &max_cmd_tokens, &cmd_tokens_per_packet,
|
||||
&cmd_token_shift);
|
||||
cmd_leak_rate = CLAMP(MIN_LEAK_RATE, leak_rate, MAX_LEAK_RATE);
|
||||
}
|
||||
|
||||
active = !CNF_GetNoClientLog();
|
||||
if (!active)
|
||||
if (!active) {
|
||||
if (ntp_leak_rate || cmd_leak_rate)
|
||||
LOG_FATAL("ratelimit cannot be used with noclientlog");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Calculate the maximum number of slots that can be allocated in the
|
||||
configured memory limit. Take into account expanding of the hash
|
||||
@@ -460,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);
|
||||
|
||||
@@ -484,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);
|
||||
@@ -520,7 +535,7 @@ CLG_LimitNTPResponseRate(int index)
|
||||
Record *record;
|
||||
int drop;
|
||||
|
||||
if (!ntp_leak_rate)
|
||||
if (!ntp_tokens_per_packet)
|
||||
return 0;
|
||||
|
||||
record = ARR_GetElement(records, index);
|
||||
@@ -561,7 +576,7 @@ CLG_LimitCommandResponseRate(int index)
|
||||
{
|
||||
Record *record;
|
||||
|
||||
if (!cmd_leak_rate)
|
||||
if (!cmd_tokens_per_packet)
|
||||
return 0;
|
||||
|
||||
record = ARR_GetElement(records, index);
|
||||
@@ -596,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. */
|
||||
|
||||
|
||||
88
cmdmon.c
88
cmdmon.c
@@ -136,6 +136,9 @@ static const char permissions[] = {
|
||||
PERMIT_AUTH, /* NTP_DATA */
|
||||
PERMIT_AUTH, /* ADD_SERVER2 */
|
||||
PERMIT_AUTH, /* ADD_PEER2 */
|
||||
PERMIT_AUTH, /* ADD_SERVER3 */
|
||||
PERMIT_AUTH, /* ADD_PEER3 */
|
||||
PERMIT_AUTH, /* SHUTDOWN */
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
@@ -161,7 +164,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 +175,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 +191,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 +233,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 +241,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;
|
||||
@@ -276,7 +279,6 @@ do_size_checks(void)
|
||||
for (i = 1; i < N_REPLY_TYPES; i++) {
|
||||
reply.reply = htons(i);
|
||||
reply.status = STT_SUCCESS;
|
||||
reply.data.manual_list.n_samples = htonl(MAX_MANUAL_LIST_SAMPLES);
|
||||
reply_length = PKL_ReplyLength(&reply);
|
||||
if ((reply_length && reply_length < offsetof(CMD_Reply, data)) ||
|
||||
reply_length > sizeof (CMD_Reply))
|
||||
@@ -315,7 +317,7 @@ CAM_Initialise(int family)
|
||||
&& sock_fd6 < 0
|
||||
#endif
|
||||
) {
|
||||
LOG_FATAL(LOGF_CmdMon, "Could not open any command socket");
|
||||
LOG_FATAL("Could not open any command socket");
|
||||
}
|
||||
|
||||
access_auth_table = ADF_CreateTable();
|
||||
@@ -396,12 +398,12 @@ transmit_reply(CMD_Reply *msg, union sockaddr_all *where_to)
|
||||
&where_to->sa, addrlen);
|
||||
|
||||
if (status < 0) {
|
||||
DEBUG_LOG(LOGF_CmdMon, "Could not send to %s fd %d : %s",
|
||||
DEBUG_LOG("Could not send to %s fd %d : %s",
|
||||
UTI_SockaddrToString(&where_to->sa), sock_fd, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_LOG(LOGF_CmdMon, "Sent %d bytes to %s fd %d", status,
|
||||
DEBUG_LOG("Sent %d bytes to %s fd %d", status,
|
||||
UTI_SockaddrToString(&where_to->sa), sock_fd);
|
||||
}
|
||||
|
||||
@@ -568,14 +570,13 @@ static void
|
||||
handle_settime(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
struct timespec ts;
|
||||
long offset_cs;
|
||||
double dfreq_ppm, new_afreq_ppm;
|
||||
double offset, dfreq_ppm, new_afreq_ppm;
|
||||
UTI_TimespecNetworkToHost(&rx_message->data.settime.ts, &ts);
|
||||
if (!MNL_IsEnabled()) {
|
||||
tx_message->status = htons(STT_NOTENABLED);
|
||||
} else if (MNL_AcceptTimestamp(&ts, &offset_cs, &dfreq_ppm, &new_afreq_ppm)) {
|
||||
tx_message->reply = htons(RPY_MANUAL_TIMESTAMP);
|
||||
tx_message->data.manual_timestamp.centiseconds = htonl((int32_t)offset_cs);
|
||||
} else if (MNL_AcceptTimestamp(&ts, &offset, &dfreq_ppm, &new_afreq_ppm)) {
|
||||
tx_message->reply = htons(RPY_MANUAL_TIMESTAMP2);
|
||||
tx_message->data.manual_timestamp.offset = UTI_FloatHostToNetwork(offset);
|
||||
tx_message->data.manual_timestamp.dfreq_ppm = UTI_FloatHostToNetwork(dfreq_ppm);
|
||||
tx_message->data.manual_timestamp.new_afreq_ppm = UTI_FloatHostToNetwork(new_afreq_ppm);
|
||||
} else {
|
||||
@@ -792,12 +793,15 @@ handle_add_source(NTP_Source_Type type, CMD_Request *rx_message, CMD_Reply *tx_m
|
||||
UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay_ratio);
|
||||
params.max_delay_dev_ratio =
|
||||
UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay_dev_ratio);
|
||||
params.min_delay = UTI_FloatNetworkToHost(rx_message->data.ntp_source.min_delay);
|
||||
params.asymmetry = UTI_FloatNetworkToHost(rx_message->data.ntp_source.asymmetry);
|
||||
params.offset = UTI_FloatNetworkToHost(rx_message->data.ntp_source.offset);
|
||||
|
||||
params.online = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_ONLINE ? 1 : 0;
|
||||
params.auto_offline = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_AUTOOFFLINE ? 1 : 0;
|
||||
params.iburst = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_IBURST ? 1 : 0;
|
||||
params.interleaved = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_INTERLEAVED ? 1 : 0;
|
||||
params.burst = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_BURST ? 1 : 0;
|
||||
params.sel_options =
|
||||
(ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_PREFER ? SRC_SELECT_PREFER : 0) |
|
||||
(ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_NOSELECT ? SRC_SELECT_NOSELECT : 0) |
|
||||
@@ -874,7 +878,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 +891,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);
|
||||
}
|
||||
|
||||
@@ -1065,9 +1069,6 @@ handle_client_accesses_by_index(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
tx_message->reply = htons(RPY_CLIENT_ACCESSES_BY_INDEX2);
|
||||
tx_message->data.client_accesses_by_index.n_indices = htonl(n_indices);
|
||||
|
||||
memset(tx_message->data.client_accesses_by_index.clients, 0,
|
||||
sizeof (tx_message->data.client_accesses_by_index.clients));
|
||||
|
||||
for (i = req_first_index, j = 0; i < (uint32_t)n_indices && j < req_n_clients; i++) {
|
||||
if (!CLG_GetClientAccessReportByIndex(i, &report, &now))
|
||||
continue;
|
||||
@@ -1100,10 +1101,11 @@ handle_manual_list(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
RPY_ManualListSample *sample;
|
||||
RPT_ManualSamplesReport report[MAX_MANUAL_LIST_SAMPLES];
|
||||
|
||||
tx_message->reply = htons(RPY_MANUAL_LIST);
|
||||
tx_message->reply = htons(RPY_MANUAL_LIST2);
|
||||
|
||||
MNL_ReportSamples(report, MAX_MANUAL_LIST_SAMPLES, &n_samples);
|
||||
tx_message->data.manual_list.n_samples = htonl(n_samples);
|
||||
|
||||
for (i=0; i<n_samples; i++) {
|
||||
sample = &tx_message->data.manual_list.samples[i];
|
||||
UTI_TimespecHostToNetwork(&report[i].when, &sample->when);
|
||||
@@ -1235,6 +1237,15 @@ handle_ntp_data(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
memset(tx_message->data.ntp_data.reserved, 0xff, sizeof (tx_message->data.ntp_data.reserved));
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_shutdown(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
LOG(LOGS_INFO, "Received shutdown command");
|
||||
SCH_QuitProgram();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Read a packet and process it */
|
||||
|
||||
@@ -1258,14 +1269,14 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
&where_from.sa, &from_length);
|
||||
|
||||
if (status < 0) {
|
||||
LOG(LOGS_WARN, LOGF_CmdMon, "Error [%s] reading from control socket %d",
|
||||
LOG(LOGS_WARN, "Error [%s] reading from control socket %d",
|
||||
strerror(errno), sock_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (from_length > sizeof (where_from) ||
|
||||
from_length <= sizeof (where_from.sa.sa_family)) {
|
||||
DEBUG_LOG(LOGF_CmdMon, "Read command packet without source address");
|
||||
DEBUG_LOG("Read command packet without source address");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1300,7 +1311,7 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
assert(0);
|
||||
}
|
||||
|
||||
DEBUG_LOG(LOGF_CmdMon, "Received %d bytes from %s fd %d",
|
||||
DEBUG_LOG("Received %d bytes from %s fd %d",
|
||||
status, UTI_SockaddrToString(&where_from.sa), sock_fd);
|
||||
|
||||
if (!(localhost || ADF_IsAllowed(access_auth_table, &remote_ip))) {
|
||||
@@ -1319,29 +1330,24 @@ 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;
|
||||
}
|
||||
|
||||
expected_length = PKL_CommandLength(&rx_message);
|
||||
rx_command = ntohs(rx_message.command);
|
||||
|
||||
memset(&tx_message, 0, sizeof (tx_message));
|
||||
|
||||
tx_message.version = PROTO_VERSION_NUMBER;
|
||||
tx_message.pkt_type = PKT_TYPE_CMD_REPLY;
|
||||
tx_message.res1 = 0;
|
||||
tx_message.res2 = 0;
|
||||
tx_message.command = rx_message.command;
|
||||
tx_message.reply = htons(RPY_NULL);
|
||||
tx_message.status = htons(STT_SUCCESS);
|
||||
tx_message.pad1 = 0;
|
||||
tx_message.pad2 = 0;
|
||||
tx_message.pad3 = 0;
|
||||
tx_message.sequence = rx_message.sequence;
|
||||
tx_message.pad4 = 0;
|
||||
tx_message.pad5 = 0;
|
||||
|
||||
if (rx_message.version != PROTO_VERSION_NUMBER) {
|
||||
DEBUG_LOG(LOGF_CmdMon, "Command packet has invalid version (%d != %d)",
|
||||
DEBUG_LOG("Command packet has invalid version (%d != %d)",
|
||||
rx_message.version, PROTO_VERSION_NUMBER);
|
||||
|
||||
if (rx_message.version >= PROTO_VERSION_MISMATCH_COMPAT_SERVER) {
|
||||
@@ -1353,7 +1359,7 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
|
||||
if (rx_command >= N_REQUEST_TYPES ||
|
||||
expected_length < (int)offsetof(CMD_Request, data)) {
|
||||
DEBUG_LOG(LOGF_CmdMon, "Command packet has invalid command %d", rx_command);
|
||||
DEBUG_LOG("Command packet has invalid command %d", rx_command);
|
||||
|
||||
tx_message.status = htons(STT_INVALID);
|
||||
transmit_reply(&tx_message, &where_from);
|
||||
@@ -1361,7 +1367,7 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
}
|
||||
|
||||
if (read_length < expected_length) {
|
||||
DEBUG_LOG(LOGF_CmdMon, "Command packet is too short (%d < %d)", read_length,
|
||||
DEBUG_LOG("Command packet is too short (%d < %d)", read_length,
|
||||
expected_length);
|
||||
|
||||
tx_message.status = htons(STT_BADPKTLENGTH);
|
||||
@@ -1376,7 +1382,7 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
/* Don't reply to all requests from hosts other than localhost if the rate
|
||||
is excessive */
|
||||
if (!localhost && log_index >= 0 && CLG_LimitCommandResponseRate(log_index)) {
|
||||
DEBUG_LOG(LOGF_CmdMon, "Command packet discarded to limit response rate");
|
||||
DEBUG_LOG("Command packet discarded to limit response rate");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1526,11 +1532,11 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
handle_cmdaccheck(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_ADD_SERVER2:
|
||||
case REQ_ADD_SERVER3:
|
||||
handle_add_source(NTP_SERVER, &rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_ADD_PEER2:
|
||||
case REQ_ADD_PEER3:
|
||||
handle_add_source(NTP_PEER, &rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
@@ -1626,8 +1632,12 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
handle_ntp_data(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_SHUTDOWN:
|
||||
handle_shutdown(&rx_message, &tx_message);
|
||||
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;
|
||||
}
|
||||
|
||||
11
cmdparse.c
11
cmdparse.c
@@ -51,6 +51,7 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
|
||||
src->params.online = 1;
|
||||
src->params.auto_offline = 0;
|
||||
src->params.presend_minpoll = SRC_DEFAULT_PRESEND_MINPOLL;
|
||||
src->params.burst = 0;
|
||||
src->params.iburst = 0;
|
||||
src->params.min_stratum = SRC_DEFAULT_MINSTRATUM;
|
||||
src->params.poll_target = SRC_DEFAULT_POLLTARGET;
|
||||
@@ -64,6 +65,8 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
|
||||
src->params.max_delay = SRC_DEFAULT_MAXDELAY;
|
||||
src->params.max_delay_ratio = SRC_DEFAULT_MAXDELAYRATIO;
|
||||
src->params.max_delay_dev_ratio = SRC_DEFAULT_MAXDELAYDEVRATIO;
|
||||
src->params.min_delay = 0.0;
|
||||
src->params.asymmetry = SRC_DEFAULT_ASYMMETRY;
|
||||
src->params.offset = 0.0;
|
||||
|
||||
hostname = line;
|
||||
@@ -82,6 +85,8 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
|
||||
|
||||
if (!strcasecmp(cmd, "auto_offline")) {
|
||||
src->params.auto_offline = 1;
|
||||
} else if (!strcasecmp(cmd, "burst")) {
|
||||
src->params.burst = 1;
|
||||
} else if (!strcasecmp(cmd, "iburst")) {
|
||||
src->params.iburst = 1;
|
||||
} else if (!strcasecmp(cmd, "offline")) {
|
||||
@@ -98,6 +103,9 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
|
||||
if (sscanf(line, "%"SCNu32"%n", &src->params.authkey, &n) != 1 ||
|
||||
src->params.authkey == INACTIVE_AUTHKEY)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "asymmetry")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.asymmetry, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "maxdelay")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.max_delay, &n) != 1)
|
||||
return 0;
|
||||
@@ -116,6 +124,9 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
|
||||
} else if (!strcasecmp(cmd, "maxsources")) {
|
||||
if (sscanf(line, "%d%n", &src->params.max_sources, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "mindelay")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.min_delay, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "minpoll")) {
|
||||
if (sscanf(line, "%d%n", &src->params.minpoll, &n) != 1)
|
||||
return 0;
|
||||
|
||||
204
conf.c
204
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
|
||||
@@ -66,7 +66,8 @@ static void parse_log(char *);
|
||||
static void parse_mailonchange(char *);
|
||||
static void parse_makestep(char *);
|
||||
static void parse_maxchange(char *);
|
||||
static void parse_ratelimit(char *line, int *interval, int *burst, int *leak);
|
||||
static void parse_ratelimit(char *line, int *enabled, int *interval,
|
||||
int *burst, int *leak);
|
||||
static void parse_refclock(char *);
|
||||
static void parse_smoothtime(char *);
|
||||
static void parse_source(char *line, NTP_Source_Type type, int pool);
|
||||
@@ -78,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;
|
||||
@@ -96,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;
|
||||
@@ -190,12 +191,14 @@ static char *ntp_signd_socket = NULL;
|
||||
static char *pidfile;
|
||||
|
||||
/* Rate limiting parameters */
|
||||
static int ntp_ratelimit_interval = -10;
|
||||
static int ntp_ratelimit_burst = 16;
|
||||
static int ntp_ratelimit_enabled = 0;
|
||||
static int ntp_ratelimit_interval = 3;
|
||||
static int ntp_ratelimit_burst = 8;
|
||||
static int ntp_ratelimit_leak = 2;
|
||||
static int cmd_ratelimit_interval = -10;
|
||||
static int cmd_ratelimit_burst = 16;
|
||||
static int cmd_ratelimit_leak = 0;
|
||||
static int cmd_ratelimit_enabled = 0;
|
||||
static int cmd_ratelimit_interval = -4;
|
||||
static int cmd_ratelimit_burst = 8;
|
||||
static int cmd_ratelimit_leak = 2;
|
||||
|
||||
/* Smoothing constants */
|
||||
static double smooth_max_freq = 0.0; /* in ppm */
|
||||
@@ -220,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 {
|
||||
@@ -267,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 : "");
|
||||
}
|
||||
@@ -277,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 : "");
|
||||
}
|
||||
@@ -310,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 : "");
|
||||
@@ -320,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));
|
||||
@@ -336,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);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -351,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++)
|
||||
@@ -394,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);
|
||||
@@ -452,7 +462,8 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
} else if (!strcasecmp(command, "cmdport")) {
|
||||
parse_int(p, &cmd_port);
|
||||
} else if (!strcasecmp(command, "cmdratelimit")) {
|
||||
parse_ratelimit(p, &cmd_ratelimit_interval, &cmd_ratelimit_burst, &cmd_ratelimit_leak);
|
||||
parse_ratelimit(p, &cmd_ratelimit_enabled, &cmd_ratelimit_interval,
|
||||
&cmd_ratelimit_burst, &cmd_ratelimit_leak);
|
||||
} else if (!strcasecmp(command, "combinelimit")) {
|
||||
parse_double(p, &combine_limit);
|
||||
} else if (!strcasecmp(command, "corrtimeratio")) {
|
||||
@@ -464,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")) {
|
||||
@@ -532,7 +543,8 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
} else if (!strcasecmp(command, "port")) {
|
||||
parse_int(p, &ntp_port);
|
||||
} else if (!strcasecmp(command, "ratelimit")) {
|
||||
parse_ratelimit(p, &ntp_ratelimit_interval, &ntp_ratelimit_burst, &ntp_ratelimit_leak);
|
||||
parse_ratelimit(p, &ntp_ratelimit_enabled, &ntp_ratelimit_interval,
|
||||
&ntp_ratelimit_burst, &ntp_ratelimit_leak);
|
||||
} else if (!strcasecmp(command, "refclock")) {
|
||||
parse_refclock(p);
|
||||
} else if (!strcasecmp(command, "reselectdist")) {
|
||||
@@ -563,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");
|
||||
}
|
||||
@@ -637,11 +649,13 @@ parse_source(char *line, NTP_Source_Type type, int pool)
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
parse_ratelimit(char *line, int *interval, int *burst, int *leak)
|
||||
parse_ratelimit(char *line, int *enabled, int *interval, int *burst, int *leak)
|
||||
{
|
||||
int n, val;
|
||||
char *opt;
|
||||
|
||||
*enabled = 1;
|
||||
|
||||
while (*line) {
|
||||
opt = line;
|
||||
line = CPS_SplitWord(line);
|
||||
@@ -667,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, stratum, tai;
|
||||
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;
|
||||
@@ -677,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;
|
||||
@@ -685,9 +700,12 @@ 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;
|
||||
stratum = 0;
|
||||
tai = 0;
|
||||
|
||||
if (!*line) {
|
||||
command_parse_error();
|
||||
@@ -749,12 +767,25 @@ 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, "stratum")) {
|
||||
if (sscanf(line, "%d%n", &stratum, &n) != 1 ||
|
||||
stratum >= NTP_MAX_STRATUM || stratum < 0)
|
||||
break;
|
||||
} else if (!strcasecmp(cmd, "tai")) {
|
||||
n = 0;
|
||||
tai = 1;
|
||||
} else if (!strcasecmp(cmd, "width")) {
|
||||
if (sscanf(line, "%lf%n", &pulse_width, &n) != 1)
|
||||
break;
|
||||
} else if (!strcasecmp(cmd, "noselect")) {
|
||||
n = 0;
|
||||
sel_options |= SRC_SELECT_NOSELECT;
|
||||
@@ -784,14 +815,18 @@ 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;
|
||||
refclock->sel_options = sel_options;
|
||||
refclock->stratum = stratum;
|
||||
refclock->tai = tai;
|
||||
refclock->offset = offset;
|
||||
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;
|
||||
@@ -807,7 +842,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;
|
||||
@@ -867,7 +905,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1044,7 +1082,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;
|
||||
@@ -1159,7 +1197,7 @@ parse_broadcast(char *line)
|
||||
}
|
||||
} else {
|
||||
/* default port */
|
||||
port = 123;
|
||||
port = NTP_PORT;
|
||||
}
|
||||
|
||||
destination = (NTP_Broadcast_Destination *)ARR_GetNewElement(broadcasts);
|
||||
@@ -1238,8 +1276,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_ANY;
|
||||
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();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1249,11 +1342,19 @@ parse_include(char *line)
|
||||
{
|
||||
glob_t gl;
|
||||
size_t i;
|
||||
int r;
|
||||
|
||||
check_number_of_args(line, 1);
|
||||
|
||||
if (glob(line, 0, NULL, &gl)) {
|
||||
DEBUG_LOG(LOGF_Configure, "glob of %s failed", line);
|
||||
if ((r = glob(line,
|
||||
#ifdef GLOB_NOMAGIC
|
||||
GLOB_NOMAGIC |
|
||||
#endif
|
||||
GLOB_ERR, NULL, &gl)) != 0) {
|
||||
if (r != GLOB_NOMATCH)
|
||||
LOG_FATAL("Could not search for files matching %s", line);
|
||||
|
||||
DEBUG_LOG("glob of %s failed", line);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1279,7 +1380,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';
|
||||
}
|
||||
|
||||
@@ -1418,8 +1519,9 @@ CNF_GetDumpDir(void)
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CNF_GetLogMeasurements(void)
|
||||
CNF_GetLogMeasurements(int *raw)
|
||||
{
|
||||
*raw = raw_measurements;
|
||||
return do_log_measurements;
|
||||
}
|
||||
|
||||
@@ -1497,14 +1599,6 @@ CNF_GetRtcDevice(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CNF_GetDumpOnExit(void)
|
||||
{
|
||||
return do_dump_on_exit;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
double
|
||||
CNF_GetMaxUpdateSkew(void)
|
||||
{
|
||||
@@ -1685,7 +1779,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1693,7 +1787,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1823,20 +1917,22 @@ CNF_GetLockMemory(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void CNF_GetNTPRateLimit(int *interval, int *burst, int *leak)
|
||||
int CNF_GetNTPRateLimit(int *interval, int *burst, int *leak)
|
||||
{
|
||||
*interval = ntp_ratelimit_interval;
|
||||
*burst = ntp_ratelimit_burst;
|
||||
*leak = ntp_ratelimit_leak;
|
||||
return ntp_ratelimit_enabled;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void CNF_GetCommandRateLimit(int *interval, int *burst, int *leak)
|
||||
int CNF_GetCommandRateLimit(int *interval, int *burst, int *leak)
|
||||
{
|
||||
*interval = cmd_ratelimit_interval;
|
||||
*burst = cmd_ratelimit_burst;
|
||||
*leak = cmd_ratelimit_leak;
|
||||
return cmd_ratelimit_enabled;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1921,8 +2017,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;
|
||||
}
|
||||
|
||||
29
conf.h
29
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);
|
||||
@@ -102,8 +100,8 @@ extern void CNF_SetupAccessRestrictions(void);
|
||||
extern int CNF_GetSchedPriority(void);
|
||||
extern int CNF_GetLockMemory(void);
|
||||
|
||||
extern void CNF_GetNTPRateLimit(int *interval, int *burst, int *leak);
|
||||
extern void CNF_GetCommandRateLimit(int *interval, int *burst, int *leak);
|
||||
extern int CNF_GetNTPRateLimit(int *interval, int *burst, int *leak);
|
||||
extern int CNF_GetCommandRateLimit(int *interval, int *burst, int *leak);
|
||||
extern void CNF_GetSmooth(double *max_freq, double *max_wander, int *leap_only);
|
||||
extern void CNF_GetTempComp(char **file, double *interval, char **point_file, double *T0, double *k0, double *k1, double *k2);
|
||||
|
||||
@@ -120,6 +118,23 @@ extern char *CNF_GetHwclockFile(void);
|
||||
extern int CNF_GetInitSources(void);
|
||||
extern double CNF_GetInitStepThreshold(void);
|
||||
|
||||
extern ARR_Instance CNF_GetHwTsInterfaces(void);
|
||||
typedef enum {
|
||||
CNF_HWTS_RXFILTER_ANY,
|
||||
CNF_HWTS_RXFILTER_NONE,
|
||||
CNF_HWTS_RXFILTER_NTP,
|
||||
CNF_HWTS_RXFILTER_ALL,
|
||||
} CNF_HwTs_RxFilter;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
int minpoll;
|
||||
int nocrossts;
|
||||
CNF_HwTs_RxFilter rxfilter;
|
||||
double precision;
|
||||
double tx_comp;
|
||||
double rx_comp;
|
||||
} CNF_HwTsInterface;
|
||||
|
||||
extern int CNF_GetHwTsInterface(unsigned int index, CNF_HwTsInterface **iface);
|
||||
|
||||
#endif /* GOT_CONF_H */
|
||||
|
||||
93
configure
vendored
93
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
|
||||
#
|
||||
# =======================================================================
|
||||
|
||||
@@ -84,6 +85,7 @@ For better control, use the options below.
|
||||
--with-readline-library=DIR Specify where readline lib directory is
|
||||
--with-ncurses-library=DIR Specify where ncurses lib directory is
|
||||
--disable-sechash Disable support for hashes other than MD5
|
||||
--without-nettle Don't use nettle even if it is available
|
||||
--without-nss Don't use NSS even if it is available
|
||||
--without-tomcrypt Don't use libtomcrypt even if it is available
|
||||
--disable-cmdmon Disable command and monitoring support
|
||||
@@ -197,6 +199,7 @@ feat_readline=1
|
||||
try_readline=1
|
||||
try_editline=1
|
||||
feat_sechash=1
|
||||
try_nettle=1
|
||||
try_nss=1
|
||||
try_tomcrypt=1
|
||||
feat_rtc=1
|
||||
@@ -359,6 +362,9 @@ do
|
||||
--disable-sechash )
|
||||
feat_sechash=0
|
||||
;;
|
||||
--without-nettle )
|
||||
try_nettle=0
|
||||
;;
|
||||
--without-nss )
|
||||
try_nss=0
|
||||
;;
|
||||
@@ -427,6 +433,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)
|
||||
@@ -489,14 +504,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"
|
||||
@@ -506,9 +523,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
|
||||
|
||||
@@ -522,7 +555,11 @@ then
|
||||
split_seconds=$ntp_era_split
|
||||
split_days=0
|
||||
else
|
||||
split_seconds=`date '+%s'`
|
||||
if [ "x$SOURCE_DATE_EPOCH" != "x" ]; then
|
||||
split_seconds=$SOURCE_DATE_EPOCH
|
||||
else
|
||||
split_seconds=`date '+%s'`
|
||||
fi
|
||||
if [ "x$split_seconds" = "x" ]; then
|
||||
echo "error: could not get current time, --with-ntp-era option is needed"
|
||||
exit 1
|
||||
@@ -630,6 +667,11 @@ if test_code 'arc4random_buf()' 'stdlib.h' '' '' 'arc4random_buf(NULL, 0);'; the
|
||||
add_def HAVE_ARC4RANDOM
|
||||
fi
|
||||
|
||||
if test_code 'getrandom()' 'stdlib.h sys/random.h' '' '' \
|
||||
'return getrandom(NULL, 256, 0);'; then
|
||||
add_def HAVE_GETRANDOM
|
||||
fi
|
||||
|
||||
RECVMMSG_CODE='
|
||||
struct mmsghdr hdr;
|
||||
return !recvmmsg(0, &hdr, 1, MSG_DONTWAIT, 0);'
|
||||
@@ -657,6 +699,18 @@ 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 +
|
||||
SCM_TIMESTAMPING_PKTINFO +
|
||||
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=""
|
||||
@@ -708,7 +762,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
|
||||
|
||||
@@ -731,8 +785,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
|
||||
|
||||
@@ -806,7 +862,22 @@ fi
|
||||
HASH_OBJ="hash_intmd5.o"
|
||||
HASH_LINK=""
|
||||
|
||||
if [ $feat_sechash = "1" ] && [ $try_nss = "1" ]; then
|
||||
if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_nettle = "1" ]; then
|
||||
test_cflags="`pkg_config --cflags nettle`"
|
||||
test_link="`pkg_config --libs nettle`"
|
||||
if test_code 'nettle' 'nettle/nettle-meta.h nettle/sha2.h' \
|
||||
"$test_cflags" "$test_link" \
|
||||
'return nettle_hashes[0]->context_size;'
|
||||
then
|
||||
HASH_OBJ="hash_nettle.o"
|
||||
HASH_LINK="$test_link"
|
||||
LIBS="$LIBS $HASH_LINK"
|
||||
MYCPPFLAGS="$MYCPPFLAGS $test_cflags"
|
||||
add_def FEAT_SECHASH
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_nss = "1" ]; then
|
||||
test_cflags="`pkg_config --cflags nss`"
|
||||
test_link="`pkg_config --libs-only-L nss` -lfreebl3"
|
||||
if test_code 'NSS' 'nss.h hasht.h nsslowhash.h' \
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// 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) Bryan Christianson 2017
|
||||
// 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
|
||||
@@ -64,29 +66,40 @@ server, or its IP address. The *server* directive supports the following
|
||||
options:
|
||||
+
|
||||
*minpoll* _poll_:::
|
||||
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).
|
||||
This option specifies the minimum interval between requests sent to the server
|
||||
as a power of 2 in seconds. For example, *minpoll 5* would mean that the
|
||||
polling interval should not 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).
|
||||
This option specifies the maximum interval between requests sent to the server
|
||||
as a power of 2 in seconds. For example, *maxpoll 9* indicates that the polling
|
||||
interval should stay at or below 9 (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
|
||||
the clock after *chronyd* is started.
|
||||
*key* _id_:::
|
||||
With this option, the interval between the first four requests sent to the
|
||||
server will be 2 seconds instead of the interval specified by the *minpoll*
|
||||
option, which allows *chronyd* to make the first update of the clock shortly
|
||||
after start.
|
||||
*burst*:::
|
||||
With this option, *chronyd* will shorten the interval between up to four
|
||||
requests to 2 seconds when it cannot get a good measurement from the server.
|
||||
The number of requests in the burst is limited by the current polling interval
|
||||
to keep the average interval at or above the minimum interval, i.e. the current
|
||||
interval needs to be at least two times longer than the minimum interval in
|
||||
order to allow a burst with two requests.
|
||||
*key* _ID_:::
|
||||
The NTP protocol supports the inclusion of checksums in the packets, to prevent
|
||||
computers having their system time upset by rogue packets being sent to them.
|
||||
The checksums are generated as a function of a password, using the
|
||||
cryptographic hash function set in the key file, which is specified by the
|
||||
<<keyfile,*keyfile*>> directive.
|
||||
+
|
||||
If the key option is present, *chronyd* will attempt to use authenticated
|
||||
packets when communicating with this server. The key number used will be the
|
||||
single argument to the key option (an unsigned integer in the range 1 through
|
||||
2^32-1). The server must have the same password for this key number configured,
|
||||
The *key* option specifies which key (with an ID in the range 1 through 2^32-1)
|
||||
should *chronyd* use to authenticate requests sent to the server and verify its
|
||||
responses. The server must have the same key for this number configured,
|
||||
otherwise no relationship between the computers will be possible.
|
||||
*maxdelay* _delay_:::
|
||||
*chronyd* uses the network round-trip delay to the server to determine how
|
||||
@@ -105,18 +118,30 @@ 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
|
||||
This option is similar to the *maxdelay* option above. *chronyd* keeps a record
|
||||
of the minimum round-trip delay amongst the previous measurements that it has
|
||||
buffered. If a measurement has a round trip delay that is greater than the
|
||||
maxdelayratio times the minimum delay, it will be rejected. This option works
|
||||
only in the *server* directive when not in the interleaved mode.
|
||||
maxdelayratio times the minimum delay, it will be rejected.
|
||||
*maxdelaydevratio* _ratio_:::
|
||||
If a measurement has a ratio of the increase in the round-trip delay from the
|
||||
minimum delay amongst the previous measurements to the standard deviation of
|
||||
the previous measurements that is greater than the specified ratio, it will be
|
||||
rejected. The default is 10.0.
|
||||
*mindelay* _delay_:::
|
||||
This option specifies a fixed minimum round-trip delay to be used instead of
|
||||
the minimum amongst the previous measurements. This can be useful in networks
|
||||
with static configuration to improve the stability of corrections for
|
||||
asymmetric jitter, weighting of the measurements, and the *maxdelayratio* and
|
||||
*maxdelaydevratio* tests. The value should be set accurately in order to have a
|
||||
positive effect on the synchronisation.
|
||||
*asymmetry* _ratio_:::
|
||||
This option specifies the asymmetry of the network jitter on the path to the
|
||||
source, which is used to correct the measured offset according to the delay.
|
||||
The asymmetry can be between -0.5 and +0.5. A negative value means the delay of
|
||||
packets sent to the source is more variable than the delay of packets sent from
|
||||
the source back. By default, *chronyd* estimates the asymmetry automatically.
|
||||
*offset* _offset_:::
|
||||
This option specifies a correction (in seconds) which will be applied to
|
||||
offsets measured with this source. It's particularly useful to compensate for a
|
||||
@@ -136,14 +161,15 @@ option can be specified. *chronyd* will not try to poll the server until it is
|
||||
enabled to do so (by using the <<chronyc.adoc#online,*online*>> command in
|
||||
*chronyc*).
|
||||
*auto_offline*:::
|
||||
If this option is set, the server will be assumed to have gone offline when 2
|
||||
With this option, the server will be assumed to have gone offline when two
|
||||
requests have been sent to it without receiving a response. This option avoids
|
||||
the need to run the <<chronyc.adoc#offline,*offline*>> command from *chronyc*
|
||||
when disconnecting the network link. (It will still be necessary to use the
|
||||
<<chronyc.adoc#online,*online*>> command when the link has been established, to
|
||||
enable measurements to start.)
|
||||
when disconnecting the network link, if it is safe to assume that the requests
|
||||
and responses will not be dropped in the network, e.g. in a trusted local
|
||||
network. (It will still be necessary to use the <<chronyc.adoc#online,*online*>>
|
||||
command when the link has been established, to enable measurements to start.)
|
||||
*prefer*:::
|
||||
Prefer this source over sources without prefer option.
|
||||
Prefer this source over sources without the *prefer* option.
|
||||
*noselect*:::
|
||||
Never select this source. This is particularly useful for monitoring.
|
||||
*trust*:::
|
||||
@@ -160,9 +186,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,
|
||||
@@ -172,9 +197,11 @@ 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).
|
||||
+
|
||||
The *xleave* option can be combined with the *presend* option in order to
|
||||
shorten the interval in which the server has to keep the state to be able to
|
||||
respond in the interleaved mode.
|
||||
*polltarget* _target_:::
|
||||
Target number of measurements to use for the regression algorithm which
|
||||
*chronyd* will try to maintain by adjusting the polling interval between
|
||||
@@ -337,47 +364,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
|
||||
@@ -397,17 +433,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
|
||||
@@ -440,6 +503,17 @@ This option specifies in number of pulses how old can be samples from the
|
||||
refclock specified by the *lock* option to be paired with the pulses.
|
||||
Increasing this value is useful when the samples are produced at a lower rate
|
||||
than the pulses. The default is 2.
|
||||
*width* _width_:::
|
||||
This option specifies the width of the pulses (in seconds). It is used to
|
||||
filter PPS samples when the driver provides samples for both rising and falling
|
||||
edges. Note that it reduces the maximum allowed error of the time source which
|
||||
completes the PPS samples. If the duty cycle is configurable, 50% should be
|
||||
preferred in order to maximise the allowed error.
|
||||
*pps*:::
|
||||
This options forces *chronyd* to treat any refclock (e.g. SHM or PHC) as a PPS
|
||||
refclock. This can be useful when the refclock provides time with a variable
|
||||
offset of a whole number of seconds (e.g. it uses TAI instead of UTC). Another
|
||||
time source is needed to complete samples from the refclock.
|
||||
*offset* _offset_:::
|
||||
This option can be used to compensate for a constant error. The specified
|
||||
offset (in seconds) is applied to all samples produced by the reference clock.
|
||||
@@ -450,10 +524,12 @@ is included in the maximum assumed error which is used in the source selection
|
||||
algorithm. Increasing the delay is useful to avoid having no majority in the
|
||||
source selection or to make it prefer other sources. The default is 1e-9 (1
|
||||
nanosecond).
|
||||
*stratum* _stratum_:::
|
||||
This option sets the NTP stratum of the refclock. This can be useful when the
|
||||
refclock provides time with a stratum other than 0. The default is 0.
|
||||
*precision* _precision_:::
|
||||
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.
|
||||
@@ -481,6 +557,12 @@ but not very precise, reference clock to be safely combined with
|
||||
unauthenticated NTP sources in order to improve the accuracy of the clock. They
|
||||
can be selected and used for synchronisation only if they agree with the
|
||||
trusted and required source.
|
||||
*tai*:::
|
||||
This option indicates that the reference clock keeps time in TAI instead of UTC
|
||||
and that *chronyd* should correct its offset by the current TAI-UTC offset. The
|
||||
<<leapsectz,*leapsectz*>> directive must be used with this option and the
|
||||
database must be kept up to date in order for this correction to work as
|
||||
expected. This option does not make sense with PPS refclocks.
|
||||
*minsamples* _samples_:::
|
||||
Set the minimum number of samples kept for this source. This overrides the
|
||||
<<minsamples,*minsamples*>> directive.
|
||||
@@ -534,19 +616,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:
|
||||
+
|
||||
@@ -558,11 +639,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
|
||||
@@ -644,8 +720,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
|
||||
@@ -728,8 +805,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
|
||||
@@ -784,15 +861,28 @@ 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*.
|
||||
+
|
||||
The specified timezone is not used as an exclusive source of information about
|
||||
leap seconds. If a majority of time sources announce on the last day of June or
|
||||
December that a leap second should be inserted or deleted, it will be accepted
|
||||
even if it is not included in the timezone.
|
||||
+
|
||||
An example of the directive is:
|
||||
+
|
||||
@@ -864,7 +954,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.
|
||||
@@ -899,14 +989,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]]
|
||||
@@ -994,7 +1088,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
|
||||
@@ -1005,7 +1099,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_
|
||||
@@ -1046,6 +1141,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.
|
||||
@@ -1221,8 +1320,8 @@ source port used in NTP client requests can be set by the
|
||||
<<acquisitionport,*acquisitionport*>> directive.
|
||||
|
||||
[[ratelimit]]*ratelimit* [_option_]...::
|
||||
This directive configures response rate limiting for NTP packets. Its purpose
|
||||
is to reduce network traffic with misconfigured or broken NTP clients that are
|
||||
This directive enables response rate limiting for NTP packets. Its purpose is
|
||||
to reduce network traffic with misconfigured or broken NTP clients that are
|
||||
polling the server too frequently. The limits are applied to individual IP
|
||||
addresses. If multiple clients share one IP address (e.g. multiple hosts behind
|
||||
NAT), the sum of their traffic will be limited. If a client that increases its
|
||||
@@ -1237,16 +1336,16 @@ 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 -10 (1/1024 of a second, or 1024
|
||||
packets per second). The minimum value 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).
|
||||
power of 2 in seconds. The default value is 3 (8 seconds). The minimum value
|
||||
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
|
||||
useful for clients that make rapid measurements on start (e.g. *chronyd* with
|
||||
the *iburst* option). The default value is 16. The minimum value is 1 and the
|
||||
the *iburst* option). The default value is 8. The minimum value is 1 and the
|
||||
maximum value is 255.
|
||||
*leak*:::
|
||||
This option sets the rate at which responses are randomly allowed even if the
|
||||
@@ -1254,23 +1353,19 @@ 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 2 by default, i.e. on average at
|
||||
least every fourth request has a response. The minimum value is 0, which
|
||||
disables the rate limiting, and the maximum value is 4 (one response per 16
|
||||
requests).
|
||||
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 1 burst 8
|
||||
ratelimit interval 1 burst 16
|
||||
----
|
||||
+
|
||||
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 8
|
||||
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).
|
||||
+
|
||||
Rate limiting can be disabled by setting the *leak* option to 0, or by the
|
||||
<<noclientlog,*noclientlog*>> directive.
|
||||
|
||||
[[smoothtime]]*smoothtime* _max-freq_ _max-wander_ [*leaponly*]::
|
||||
The *smoothtime* directive can be used to enable smoothing of the time that
|
||||
@@ -1397,18 +1492,16 @@ This would make *chronyd* use UDP 257 as its command port. (*chronyc* would
|
||||
need to be run with the *-p 257* switch to inter-operate correctly.)
|
||||
|
||||
[[cmdratelimit]]*cmdratelimit* [_option_]...::
|
||||
This directive is identical to the <<ratelimit,*ratelimit*>> directive, except
|
||||
it configures rate limiting for command packets and responses to localhost are
|
||||
never limited. It is disabled by default (the default *leak* is 0).
|
||||
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 -4 (16 packets per
|
||||
second).
|
||||
+
|
||||
An example of the use of the directive is:
|
||||
+
|
||||
----
|
||||
cmdratelimit interval -2 burst 128 leak 2
|
||||
cmdratelimit interval 2
|
||||
----
|
||||
+
|
||||
This would reduce response rate for addresses that send more than 4 requests
|
||||
per second, or bursts of more than 128 packets, by up to 75%.
|
||||
|
||||
=== Real-time clock (RTC)
|
||||
|
||||
@@ -1511,10 +1604,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 \
|
||||
@@ -1550,12 +1645,18 @@ from the example line above):
|
||||
. The root dispersion (_EPSILON_ in RFC 5905). [7.446e-03]
|
||||
. Reference ID of the server's source as a hexadecimal number. [CB00717B]
|
||||
. NTP mode of the received packet (_1_=active peer, _2_=passive peer,
|
||||
_3_=server, _B_=basic, _I_=interleaved). [4B]
|
||||
_4_=server, _B_=basic, _I_=interleaved). [4B]
|
||||
. Source of the local transmit timestamp
|
||||
(_D_=daemon, _K_=kernel, _H_=hardware). [D]
|
||||
. Source of the local receive timestamp
|
||||
(_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
|
||||
@@ -1598,11 +1699,11 @@ from the example line above):
|
||||
to be discarded. The number of runs for the data that is being retained is
|
||||
tabulated. Values of approximately half the number of samples are expected.
|
||||
[8]
|
||||
. The estimated asymmetry of network jitter on the path to the source which was
|
||||
used to correct the measured offsets. The asymmetry can be between -0.5 and
|
||||
0.5. A negative value means the delay of packets sent to the source is
|
||||
more variable than the delay of packets sent from the source back. [0.00,
|
||||
i.e. no correction for asymmetry]
|
||||
. The estimated or configured asymmetry of network jitter on the path to the
|
||||
source which was used to correct the measured offsets. The asymmetry can be
|
||||
between -0.5 and +0.5. A negative value means the delay of packets sent to
|
||||
the source is more variable than the delay of packets sent from the source
|
||||
back. [0.00, i.e. no correction for asymmetry]
|
||||
+
|
||||
*tracking*:::
|
||||
This option logs changes to the estimate of the system's gain or loss rate, and
|
||||
@@ -1611,33 +1712,42 @@ actually appears as a single line in the file) from the log file is shown
|
||||
below.
|
||||
+
|
||||
----
|
||||
2015-02-23 05:40:50 203.0.113.15 3 340.529 1.606 1.046e-03 N \
|
||||
4 6.849e-03 -4.670e-04
|
||||
2017-08-22 13:22:36 203.0.113.15 2 -3.541 0.075 -8.621e-06 N \
|
||||
2 2.940e-03 -2.084e-04 1.534e-02 3.472e-04 8.304e-03
|
||||
----
|
||||
+
|
||||
The columns are as follows (the quantities in square brackets are the
|
||||
values from the example line above) :
|
||||
+
|
||||
. Date [2015-02-03]
|
||||
. Date [2017-08-22]
|
||||
. Hour:Minute:Second. Note that the date-time pair is expressed in UTC, not the
|
||||
local time zone. [05:40:50]
|
||||
local time zone. [13:22:36]
|
||||
. The IP address of the server or peer to which the local system is synchronised.
|
||||
[203.0.113.15]
|
||||
. The stratum of the local system. [3]
|
||||
. The stratum of the local system. [2]
|
||||
. The local system frequency (in ppm, positive means the local system runs fast
|
||||
of UTC). [340.529]
|
||||
. The error bounds on the frequency (in ppm). [1.606]
|
||||
. The estimated local offset at the epoch (which is rapidly corrected by
|
||||
slewing the local clock. (In seconds, positive indicates the local system
|
||||
is fast of UTC). [1.046e-3]
|
||||
of UTC). [-3.541]
|
||||
. The error bounds on the frequency (in ppm). [0.075]
|
||||
. The estimated local offset at the epoch, which is normally corrected by
|
||||
slewing the local clock (in seconds, positive indicates the clock is fast of
|
||||
UTC). [-8.621e-06]
|
||||
. Leap status (_N_ means normal, _+_ means that the last minute of this month
|
||||
has 61 seconds, _-_ means that the last minute of the month has 59 seconds,
|
||||
_?_ means the clock is not currently synchronised.) [N]
|
||||
. The number of combined sources. [4]
|
||||
. The number of combined sources. [2]
|
||||
. The estimated standard deviation of the combined offset (in seconds).
|
||||
[6.849e-03]
|
||||
[2.940e-03]
|
||||
. The remaining offset correction from the previous update (in seconds,
|
||||
positive means the system clock is slow of UTC). [-4.670e-04]
|
||||
positive means the system clock is slow of UTC). [-2.084e-04]
|
||||
. The total of the network path delays to the reference clock to which
|
||||
the local clock is ultimately synchronised (in seconds). [1.534e-02]
|
||||
. The total dispersion accumulated through all the servers back to the
|
||||
reference clock to which the local clock is ultimately synchronised
|
||||
(in seconds). [3.472e-04]
|
||||
. The maximum estimated error of the system clock in the interval since the
|
||||
previous update (in seconds). It includes the offset, remaining offset
|
||||
correction, root delay, and dispersion from the previous update with the
|
||||
dispersion which accumulated in the interval. [8.304e-03]
|
||||
+
|
||||
*rtc*:::
|
||||
This option logs information about the system's real-time clock. An example
|
||||
@@ -1782,7 +1892,7 @@ 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
|
||||
@@ -1798,25 +1908,69 @@ be enabled by the *xleave* option in the <<server,*server*>> or the
|
||||
This directive is supported on Linux 3.19 and newer. The NIC must support HW
|
||||
timestamping, which can be verified with the *ethtool -T* command. The list of
|
||||
capabilities should include _SOF_TIMESTAMPING_RAW_HARDWARE_,
|
||||
_SOF_TIMESTAMPING_TX_HARDWARE_, _SOF_TIMESTAMPING_RX_HARDWARE_, and the filter
|
||||
modes should have _HWTSTAMP_FILTER_ALL_. When *chronyd* is running, no other
|
||||
process should be working with the clock on the NIC. If no *hwtimestamp*
|
||||
directive is specified, *chronyd* will try to use software (kernel)
|
||||
timestamping. With both hardware and software timestamping there are
|
||||
some limitations on which packets can be actually timestamped, e.g. transmit
|
||||
timestamping does not currently work with IPv6 packets using IP options and
|
||||
hardware receive timestamping does not work with packets from bridged
|
||||
interfaces. The timestamping used in measurements is indicated in the
|
||||
_measurements.log_ file if enabled by the <<log,*log measurements*>> directive,
|
||||
and the <<chronyc.adoc#ntpdata,*ntpdata*>> report in *chronyc*.
|
||||
_SOF_TIMESTAMPING_TX_HARDWARE_, and _SOF_TIMESTAMPING_RX_HARDWARE_. Receive
|
||||
filter _HWTSTAMP_FILTER_ALL_, or _HWTSTAMP_FILTER_NTP_ALL_, is necessary for
|
||||
timestamping of received packets. Timestamping of packets received from bridged
|
||||
and bonded interfaces is supported on Linux 4.13 and newer. When *chronyd* is
|
||||
running, no other process (e.g. a PTP daemon) should be working with the NIC
|
||||
clock.
|
||||
+
|
||||
If the kernel supports software timestamping, it will be enabled for all
|
||||
interfaces. The source of timestamps (i.e. hardware, kernel, or daemon) is
|
||||
indicated in the _measurements.log_ file if enabled by the <<log,*log
|
||||
measurements*>> directive, and the <<chronyc.adoc#ntpdata,*ntpdata*>> report in
|
||||
*chronyc*.
|
||||
+
|
||||
If the specified interface is _*_, *chronyd* will try to enable HW timestamping
|
||||
on all available interfaces.
|
||||
+
|
||||
An example of the directive is:
|
||||
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. The _filter_ can be one of
|
||||
the following:
|
||||
_all_::::
|
||||
Enables timestamping of all received packets.
|
||||
_ntp_::::
|
||||
Enables timestamping of received NTP packets.
|
||||
_none_::::
|
||||
Disables timestamping of received packets.
|
||||
:::
|
||||
The most specific filter for timestamping NTP packets which is supported by the
|
||||
NIC is selected by default. Some NICs can timestamp only PTP packets, which
|
||||
limits the selection to the _none_ filter. Forcing timestamping of all packets
|
||||
with the _all_ filter when the NIC supports both _all_ and _ntp_ filters can be
|
||||
useful when packets are received from or on a non-standard UDP port (e.g.
|
||||
specified by the *port* directive).
|
||||
::
|
||||
+
|
||||
Examples of the directive are:
|
||||
+
|
||||
----
|
||||
hwtimestamp eth0
|
||||
hwtimestamp eth1 txcomp 300e-9 rxcomp 645e-9
|
||||
hwtimestamp *
|
||||
----
|
||||
|
||||
[[include]]*include* _pattern_::
|
||||
@@ -1853,12 +2007,18 @@ format of the file is shown below:
|
||||
+
|
||||
Each line consists of an ID, name of an authentication hash function (optional),
|
||||
and a password. The ID can be any unsigned integer in the range 1 through
|
||||
2^32-1. The default hash function is *MD5*. Depending on how *chronyd*
|
||||
was compiled, other supported functions might be *SHA1*, *SHA256*, *SHA384*,
|
||||
*SHA512*, *RMD128*, *RMD160*, *RMD256*, *RMD320*, *TIGER*, and *WHIRLPOOL*. The
|
||||
password can be specified as a string of characters not containing white space
|
||||
with an optional *ASCII:* prefix, or as a hexadecimal number with the *HEX:*
|
||||
prefix. The maximum length of the line is 2047 characters.
|
||||
2^32-1. The default hash function is *MD5*, which is always supported.
|
||||
+
|
||||
If *chronyd* was built with enabled support for hashing using a crypto library
|
||||
(nettle, nss, or libtomcrypt), the following functions are available: *MD5*,
|
||||
*SHA1*, *SHA256*, *SHA384*, *SHA512*. Depending on which library and version is
|
||||
*chronyd* using, some or all of the following functions may also be available:
|
||||
*SHA3-224*, *SHA3-256*, *SHA3-384*, *SHA3-512*, *RMD128*, *RMD160*, *RMD256*,
|
||||
*RMD320*, *TIGER*, *WHIRLPOOL*.
|
||||
+
|
||||
The password can be specified as a string of characters not containing white
|
||||
space with an optional *ASCII:* prefix, or as a hexadecimal number with the
|
||||
*HEX:* prefix. The maximum length of the line is 2047 characters.
|
||||
+
|
||||
The password is used with the hash function to generate and verify a message
|
||||
authentication code (MAC) in NTP packets. It is recommended to use SHA1, or
|
||||
@@ -2136,8 +2296,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
|
||||
@@ -2190,7 +2349,6 @@ log statistics measurements tracking
|
||||
driftfile @CHRONYVARDIR@/drift
|
||||
makestep 1.0 3
|
||||
maxupdateskew 100.0
|
||||
dumponexit
|
||||
dumpdir @CHRONYVARDIR@
|
||||
rtcfile @CHRONYVARDIR@/rtc
|
||||
----
|
||||
@@ -2225,27 +2383,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. The rate limiting interval can be increased to save more
|
||||
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 1
|
||||
clientloglimit 100000000
|
||||
leapsectz right/UTC
|
||||
driftfile @CHRONYVARDIR@/drift
|
||||
dumpdir @CHRONYRUNDIR@
|
||||
dumponexit
|
||||
----
|
||||
|
||||
== SEE ALSO
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -218,7 +216,7 @@ An absolute bound on the computer's clock accuracy (assuming the stratum-1
|
||||
computer is correct) is given by:
|
||||
+
|
||||
----
|
||||
clock_error <= root_dispersion + (0.5 * |root_delay|)
|
||||
clock_error <= |system_time_offset| + root_dispersion + (0.5 * root_delay)
|
||||
----
|
||||
*Update interval*:::
|
||||
This is the interval between the last two clock updates.
|
||||
@@ -458,7 +456,7 @@ 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
|
||||
@@ -1120,17 +1118,19 @@ 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.
|
||||
|
||||
[[rekey]]*shutdown*::
|
||||
The *shutdown* command causes *chronyd* to exit. This is equivalent to sending
|
||||
the process the SIGTERM signal.
|
||||
|
||||
=== Client commands
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of chrony
|
||||
//
|
||||
// Copyright (C) Richard P. Curnow 1997-2003
|
||||
// Copyright (C) Miroslav Lichvar 2009-2016
|
||||
// Copyright (C) Miroslav Lichvar 2009-2017
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -62,17 +62,22 @@ When run in this mode, the program will not detach itself from the terminal.
|
||||
|
||||
*-d*::
|
||||
When run in this mode, the program will not detach itself from the terminal,
|
||||
and all messages will be sent to the terminal instead of to syslog. When
|
||||
and all messages will be written to the terminal instead of syslog. When
|
||||
*chronyd* was compiled with debugging support, this option can be used twice to
|
||||
print also debugging messages.
|
||||
|
||||
*-l* _file_::
|
||||
This option specifies a file which should be used for logging instead of syslog
|
||||
or terminal.
|
||||
|
||||
*-q*::
|
||||
When run in this mode, *chronyd* will set the system clock once and exit. It
|
||||
will not detach from the terminal.
|
||||
|
||||
*-Q*::
|
||||
This option is similar to *-q*, but it will only print the offset without any
|
||||
corrections of the clock.
|
||||
This option is similar to the *-q* option, except it only prints the offset
|
||||
without making any corrections of the clock and it allows *chronyd* to be
|
||||
started without root privileges.
|
||||
|
||||
*-r*::
|
||||
This option will try to reload and then delete files containing sample
|
||||
@@ -82,8 +87,8 @@ histories are created by using the <<chronyc.adoc#dump,*dump*>> command in
|
||||
directive in the configuration file. This option is useful if you want to stop
|
||||
and restart *chronyd* briefly for any reason, e.g. to install a new version.
|
||||
However, it should be used only on systems where the kernel can maintain clock
|
||||
compensation whilst not under *chronyd*'s control (i.e. Linux, FreeBSD, NetBSD
|
||||
and Solaris).
|
||||
compensation whilst not under *chronyd*'s control (i.e. Linux, FreeBSD, NetBSD,
|
||||
Solaris, and macOS 10.13 or later).
|
||||
|
||||
*-R*::
|
||||
When this option is used, the <<chrony.conf.adoc#initstepslew,*initstepslew*>>
|
||||
@@ -130,7 +135,7 @@ range of privileged system calls on behalf of the parent.
|
||||
*-F* _level_::
|
||||
This option configures a system call filter when *chronyd* is compiled with
|
||||
support for the Linux secure computing (seccomp) facility. In level 1 the
|
||||
process is killed when a forbidden system call is made, in level -1 the SYSSIG
|
||||
process is killed when a forbidden system call is made, in level -1 the SIGSYS
|
||||
signal is thrown instead and in level 0 the filter is disabled (default 0).
|
||||
+
|
||||
It's recommended to enable the filter only when it's known to work on the
|
||||
@@ -151,6 +156,15 @@ 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 try to
|
||||
make any adjustments of the clock. It will assume the clock is free running and
|
||||
still track its offset and frequency relative to the estimated true time. This
|
||||
option allows *chronyd* to run without the capability to adjust or set the
|
||||
system clock (e.g. in some containers) in order to operate as an NTP server. It
|
||||
is not recommended to run *chronyd* (with or without *-x*) when another process
|
||||
is controlling the system clock.
|
||||
|
||||
*-v*::
|
||||
With this option *chronyd* will print version number to the terminal and exit.
|
||||
|
||||
|
||||
61
doc/faq.adoc
61
doc/faq.adoc
@@ -50,7 +50,7 @@ directive can be used for names that resolve to multiple addresses. For good
|
||||
reliability the client should have at least three servers. The `iburst` option
|
||||
speeds up the initial synchronisation.
|
||||
|
||||
To stabilize the initial synchronisation on the next start, the estimated drift
|
||||
To stabilise the initial synchronisation on the next start, the estimated drift
|
||||
of the system clock is saved to a file specified by the `driftfile` directive.
|
||||
|
||||
If the system clock can be far from the true time after boot for any reason,
|
||||
@@ -59,7 +59,7 @@ slewing, which would take a very long time. The `makestep` directive does
|
||||
that.
|
||||
|
||||
In order to keep the real-time clock (RTC) close to the true time, so the
|
||||
system time is reasonably close to the true time when it's initialized on the
|
||||
system time is reasonably close to the true time when it's initialised on the
|
||||
next boot from the RTC, the `rtcsync` directive enables a mode in which the
|
||||
system time is periodically copied to the RTC. It is supported on Linux and
|
||||
macOS.
|
||||
@@ -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?
|
||||
|
||||
@@ -326,14 +347,14 @@ Only by the source code. See _cmdmon.c_ (`chronyd` side) and _client.c_
|
||||
=== What is the real-time clock (RTC)?
|
||||
|
||||
This is the clock which keeps the time even when your computer is turned off.
|
||||
It is used to initialize the system clock on boot. It normally doesn't drift
|
||||
It is used to initialise the system clock on boot. It normally doesn't drift
|
||||
more than few seconds per day.
|
||||
|
||||
There are two approaches how `chronyd` can work with it. One is to use the
|
||||
`rtcsync` directive, which tells `chronyd` to enable a kernel mode which sets
|
||||
the RTC from the system clock every 11 minutes. `chronyd` itself won't touch
|
||||
the RTC. If the computer is not turned off for a long time, the RTC should
|
||||
still be close to the true time when the system clock will be initialized from
|
||||
still be close to the true time when the system clock will be initialised from
|
||||
it on the next boot.
|
||||
|
||||
The other option is to use the `rtcfile` directive, which tells `chronyd` to
|
||||
@@ -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
|
||||
|
||||
@@ -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,22 +5,32 @@ 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.
|
||||
#keyfile /etc/chrony.keys
|
||||
|
||||
# Get TAI-UTC offset and leap seconds from the system tz database.
|
||||
#leapsectz right/UTC
|
||||
|
||||
# Specify directory for log files.
|
||||
logdir /var/log/chrony
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -109,6 +97,12 @@ driftfile /var/lib/chrony/drift
|
||||
|
||||
! pidfile /var/run/chronyd.pid
|
||||
|
||||
# If the system timezone database is kept up to date and includes the
|
||||
# right/UTC timezone, chronyd can use it to determine the current
|
||||
# TAI-UTC offset and when will the next leap second occur.
|
||||
|
||||
! leapsectz right/UTC
|
||||
|
||||
#######################################################################
|
||||
### INITIAL CLOCK CORRECTION
|
||||
# This option is useful to quickly correct the clock on start if it's
|
||||
@@ -181,13 +175,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 +189,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 +236,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 +277,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,17 +1,37 @@
|
||||
#!/bin/sh
|
||||
# This is a NetworkManager dispatcher script for chronyd to set its NTP sources
|
||||
# online/offline when a default route is configured/removed on the system.
|
||||
# online or offline when a network interface is configured or removed
|
||||
|
||||
export LC_ALL=C
|
||||
|
||||
if [ "$2" = "up" ]; then
|
||||
/sbin/ip route list dev "$1" | grep -q '^default' &&
|
||||
/usr/bin/chronyc online > /dev/null 2>&1
|
||||
[ "$2" != "up" ] && [ "$2" != "down" ] && exit 0
|
||||
|
||||
# Check if there is a default route
|
||||
|
||||
if /sbin/ip route list 2> /dev/null | grep -q '^default'; then
|
||||
chronyc online > /dev/null 2>&1
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$2" = "down" ]; then
|
||||
/sbin/ip route list | grep -q '^default' ||
|
||||
/usr/bin/chronyc offline > /dev/null 2>&1
|
||||
fi
|
||||
sources=$(chronyc -c -n sources 2> /dev/null)
|
||||
|
||||
[ $? -ne 0 ] && exit 0
|
||||
|
||||
# Check each configured source if it has a route
|
||||
|
||||
echo "$sources" | while IFS=, read mode state address rest; do
|
||||
[ "$mode" != '^' ] && [ "$mode" != '=' ] && continue
|
||||
|
||||
/sbin/ip route get "$address" > /dev/null 2>&1 && command="online" || command="offline"
|
||||
|
||||
# Set priority of sources so that the selected source is set as
|
||||
# last if offline to avoid unnecessary reselection
|
||||
[ "$state" != '*' ] && priority=1 || priority=2
|
||||
|
||||
echo "$priority $command $address"
|
||||
|
||||
done | sort | while read priority command address; do
|
||||
echo "$command $address"
|
||||
done | chronyc > /dev/null 2>&1
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -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
|
||||
|
||||
120
hash_nettle.c
Normal file
120
hash_nettle.c
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2018
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Routines implementing crypto hashing using the nettle library.
|
||||
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include <nettle/nettle-meta.h>
|
||||
|
||||
#include "hash.h"
|
||||
#include "memory.h"
|
||||
|
||||
struct hash {
|
||||
const char *name;
|
||||
const char *int_name;
|
||||
const struct nettle_hash *nettle_hash;
|
||||
void *context;
|
||||
};
|
||||
|
||||
static struct hash hashes[] = {
|
||||
{ "MD5", "md5", NULL, NULL },
|
||||
{ "RMD160", "ripemd160", NULL, NULL },
|
||||
{ "SHA1", "sha1", NULL, NULL },
|
||||
{ "SHA256", "sha256", NULL, NULL },
|
||||
{ "SHA384", "sha384", NULL, NULL },
|
||||
{ "SHA512", "sha512", NULL, NULL },
|
||||
{ "SHA3-224", "sha3_224", NULL, NULL },
|
||||
{ "SHA3-256", "sha3_256", NULL, NULL },
|
||||
{ "SHA3-384", "sha3_384", NULL, NULL },
|
||||
{ "SHA3-512", "sha3_512", NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
int
|
||||
HSH_GetHashId(const char *name)
|
||||
{
|
||||
int id, nid;
|
||||
|
||||
for (id = 0; hashes[id].name; id++) {
|
||||
if (!strcmp(name, hashes[id].name))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!hashes[id].name)
|
||||
return -1;
|
||||
|
||||
if (hashes[id].context)
|
||||
return id;
|
||||
|
||||
for (nid = 0; nettle_hashes[nid]; nid++) {
|
||||
if (!strcmp(hashes[id].int_name, nettle_hashes[nid]->name))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!nettle_hashes[nid] || !nettle_hashes[nid]->context_size || !nettle_hashes[nid]->init)
|
||||
return -1;
|
||||
|
||||
hashes[id].nettle_hash = nettle_hashes[nid];
|
||||
hashes[id].context = Malloc(hashes[id].nettle_hash->context_size);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
|
||||
const unsigned char *in2, unsigned int in2_len,
|
||||
unsigned char *out, unsigned int out_len)
|
||||
{
|
||||
const struct nettle_hash *hash;
|
||||
void *context;
|
||||
|
||||
hash = hashes[id].nettle_hash;
|
||||
context = hashes[id].context;
|
||||
|
||||
if (out_len > hash->digest_size)
|
||||
out_len = hash->digest_size;
|
||||
|
||||
hash->init(context);
|
||||
hash->update(context, in1_len, in1);
|
||||
if (in2)
|
||||
hash->update(context, in2_len, in2);
|
||||
hash->digest(context, out_len, out);
|
||||
|
||||
return out_len;
|
||||
}
|
||||
|
||||
void
|
||||
HSH_Finalise(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; hashes[i].name; i++) {
|
||||
if (hashes[i].context)
|
||||
Free(hashes[i].context);
|
||||
}
|
||||
}
|
||||
@@ -62,6 +62,12 @@ static const struct hash hashes[] = {
|
||||
#ifdef LTC_SHA512
|
||||
{ "SHA512", "sha512", &sha512_desc },
|
||||
#endif
|
||||
#ifdef LTC_SHA3
|
||||
{ "SHA3-224", "sha3-224", &sha3_224_desc },
|
||||
{ "SHA3-256", "sha3-256", &sha3_256_desc },
|
||||
{ "SHA3-384", "sha3-384", &sha3_384_desc },
|
||||
{ "SHA3-512", "sha3-512", &sha3_512_desc },
|
||||
#endif
|
||||
#ifdef LTC_TIGER
|
||||
{ "TIGER", "tiger", &tiger_desc },
|
||||
#endif
|
||||
|
||||
49
hwclock.c
49
hwclock.c
@@ -2,7 +2,7 @@
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2016
|
||||
* Copyright (C) Miroslav Lichvar 2016-2017
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -39,8 +39,8 @@
|
||||
/* Maximum number of samples per clock */
|
||||
#define MAX_SAMPLES 16
|
||||
|
||||
/* Minimum interval between samples (in seconds) */
|
||||
#define MIN_SAMPLE_SEPARATION 1.0
|
||||
/* Maximum acceptable frequency offset of the clock */
|
||||
#define MAX_FREQ_OFFSET (2.0 / 3.0)
|
||||
|
||||
struct HCL_Instance_Record {
|
||||
/* HW and local reference timestamp */
|
||||
@@ -55,6 +55,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 +89,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 +98,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 +119,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 +144,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 +158,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;
|
||||
}
|
||||
|
||||
@@ -169,16 +177,17 @@ HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
|
||||
/* Drop unneeded samples */
|
||||
clock->n_samples -= best_start;
|
||||
|
||||
/* If the fit doesn't cross the error interval of the last sample, throw away
|
||||
all previous samples and keep only the frequency estimate */
|
||||
if (fabs(clock->offset) > err) {
|
||||
DEBUG_LOG(LOGF_HwClocks, "HW clock reset offset=%e", clock->offset);
|
||||
clock->offset = 0.0;
|
||||
clock->n_samples = 1;
|
||||
/* If the fit doesn't cross the error interval of the last sample,
|
||||
or the frequency is not sane, drop all samples and start again */
|
||||
if (fabs(clock->offset) > err ||
|
||||
fabs(clock->frequency - 1.0) > MAX_FREQ_OFFSET) {
|
||||
DEBUG_LOG("HW clock reset");
|
||||
clock->n_samples = 0;
|
||||
clock->valid_coefs = 0;
|
||||
}
|
||||
|
||||
DEBUG_LOG(LOGF_HwClocks, "HW clock samples=%d offset=%e freq=%.9e raw_freq=%.9e err=%e ref_diff=%e",
|
||||
clock->n_samples, clock->offset, clock->frequency, raw_freq, err,
|
||||
DEBUG_LOG("HW clock samples=%d offset=%e freq=%e raw_freq=%e err=%e ref_diff=%e",
|
||||
clock->n_samples, clock->offset, clock->frequency - 1.0, raw_freq - 1.0, err,
|
||||
UTI_DiffTimespecsToDouble(&clock->hw_ref, &clock->local_ref));
|
||||
}
|
||||
|
||||
@@ -193,12 +202,12 @@ HCL_CookTime(HCL_Instance clock, struct timespec *raw, struct timespec *cooked,
|
||||
return 0;
|
||||
|
||||
elapsed = UTI_DiffTimespecsToDouble(raw, &clock->hw_ref);
|
||||
offset = clock->offset + elapsed / clock->frequency;
|
||||
offset = elapsed / clock->frequency - clock->offset;
|
||||
UTI_AddDoubleToTimespec(&clock->local_ref, offset, cooked);
|
||||
|
||||
/* 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);
|
||||
|
||||
63
logging.c
63
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;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -77,9 +79,11 @@ LOG_Initialise(void)
|
||||
void
|
||||
LOG_Finalise(void)
|
||||
{
|
||||
if (system_log) {
|
||||
if (system_log)
|
||||
closelog();
|
||||
}
|
||||
|
||||
if (file_log)
|
||||
fclose(file_log);
|
||||
|
||||
LOG_CycleLogFiles();
|
||||
|
||||
@@ -112,8 +116,8 @@ static void log_message(int fatal, LOG_Severity severity, const char *message)
|
||||
assert(0);
|
||||
}
|
||||
syslog(priority, fatal ? "Fatal error : %s" : "%s", message);
|
||||
} else {
|
||||
fprintf(stderr, fatal ? "Fatal error : %s\n" : "%s\n", message);
|
||||
} else if (file_log) {
|
||||
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, ...)
|
||||
{
|
||||
@@ -131,15 +134,15 @@ void LOG_Message(LOG_Severity severity,
|
||||
time_t t;
|
||||
struct tm stm;
|
||||
|
||||
if (!system_log) {
|
||||
if (!system_log && file_log) {
|
||||
/* Don't clutter up syslog with timestamps and internal debugging info */
|
||||
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
|
||||
}
|
||||
|
||||
@@ -157,16 +160,14 @@ void LOG_Message(LOG_Severity severity,
|
||||
case LOGS_FATAL:
|
||||
log_message(1, severity, buf);
|
||||
|
||||
/* With syslog, send the message also to the grandparent
|
||||
process or write it to stderr if not detached */
|
||||
if (system_log) {
|
||||
if (parent_fd > 0) {
|
||||
if (write(parent_fd, buf, strlen(buf) + 1) < 0)
|
||||
; /* Not much we can do here */
|
||||
} else if (parent_fd == 0) {
|
||||
system_log = 0;
|
||||
log_message(1, severity, buf);
|
||||
}
|
||||
/* Send the message also to the foreground process if it is
|
||||
still running, or stderr if it is still open */
|
||||
if (parent_fd > 0) {
|
||||
if (write(parent_fd, buf, strlen(buf) + 1) < 0)
|
||||
; /* Not much we can do here */
|
||||
} else if (system_log && parent_fd == 0) {
|
||||
system_log = 0;
|
||||
log_message(1, severity, buf);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -174,6 +175,24 @@ void LOG_Message(LOG_Severity severity,
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LOG_OpenFileLog(const char *log_file)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
f = fopen(log_file, "a");
|
||||
if (!f)
|
||||
LOG_FATAL("Could not open log file %s", log_file);
|
||||
|
||||
/* Enable line buffering */
|
||||
setvbuf(f, NULL, _IOLBF, BUFSIZ);
|
||||
|
||||
file_log = f;
|
||||
}
|
||||
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
@@ -199,6 +218,8 @@ void
|
||||
LOG_SetParentFd(int fd)
|
||||
{
|
||||
parent_fd = fd;
|
||||
if (file_log == stderr)
|
||||
file_log = NULL;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -241,7 +262,7 @@ LOG_FileWrite(LOG_FileID id, const char *format, ...)
|
||||
char filename[512], *logdir = CNF_GetLogDir();
|
||||
|
||||
if (logdir[0] == '\0') {
|
||||
LOG(LOGS_WARN, LOGF_Logging, "logdir not specified");
|
||||
LOG(LOGS_WARN, "logdir not specified");
|
||||
logfiles[id].name = NULL;
|
||||
return;
|
||||
}
|
||||
@@ -249,7 +270,7 @@ LOG_FileWrite(LOG_FileID id, const char *format, ...)
|
||||
if (snprintf(filename, sizeof(filename), "%s/%s.log",
|
||||
logdir, logfiles[id].name) >= sizeof (filename) ||
|
||||
!(logfiles[id].file = fopen(filename, "a"))) {
|
||||
LOG(LOGS_WARN, LOGF_Logging, "Could not open log file %s", filename);
|
||||
LOG(LOGS_WARN, "Could not open log file %s", filename);
|
||||
logfiles[id].name = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
70
logging.h
70
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,10 +99,13 @@ 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);
|
||||
|
||||
/* Send fatal message also to the foreground process */
|
||||
/* Stop using stderr and send fatal message to the foreground process */
|
||||
extern void LOG_SetParentFd(int fd);
|
||||
|
||||
/* Close the pipe to the foreground process so it can exit */
|
||||
|
||||
317
main.c
317
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-2017
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -86,6 +86,10 @@ static void
|
||||
delete_pidfile(void)
|
||||
{
|
||||
const char *pidfile = CNF_GetPidFile();
|
||||
|
||||
if (!pidfile[0])
|
||||
return;
|
||||
|
||||
/* Don't care if this fails, there's not a lot we can do */
|
||||
unlink(pidfile);
|
||||
}
|
||||
@@ -97,7 +101,7 @@ MAI_CleanupAndExit(void)
|
||||
{
|
||||
if (!initialised) exit(exit_status);
|
||||
|
||||
if (CNF_GetDumpOnExit()) {
|
||||
if (CNF_GetDumpDir()[0] != '\0') {
|
||||
SRC_DumpSources();
|
||||
}
|
||||
|
||||
@@ -127,9 +131,8 @@ MAI_CleanupAndExit(void)
|
||||
delete_pidfile();
|
||||
|
||||
CNF_Finalise();
|
||||
LOG_Finalise();
|
||||
|
||||
HSH_Finalise();
|
||||
LOG_Finalise();
|
||||
|
||||
exit(exit_status);
|
||||
}
|
||||
@@ -242,55 +245,45 @@ post_init_rtc_hook(void *anything)
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Return 1 if the process exists on the system. */
|
||||
|
||||
static int
|
||||
does_process_exist(int pid)
|
||||
{
|
||||
int status;
|
||||
status = getsid(pid);
|
||||
if (status >= 0) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
maybe_another_chronyd_running(int *other_pid)
|
||||
static void
|
||||
check_pidfile(void)
|
||||
{
|
||||
const char *pidfile = CNF_GetPidFile();
|
||||
FILE *in;
|
||||
int pid, count;
|
||||
|
||||
*other_pid = 0;
|
||||
|
||||
in = fopen(pidfile, "r");
|
||||
if (!in) return 0;
|
||||
if (!in)
|
||||
return;
|
||||
|
||||
count = fscanf(in, "%d", &pid);
|
||||
fclose(in);
|
||||
|
||||
if (count != 1) return 0;
|
||||
if (count != 1)
|
||||
return;
|
||||
|
||||
*other_pid = pid;
|
||||
return does_process_exist(pid);
|
||||
|
||||
if (getsid(pid) < 0)
|
||||
return;
|
||||
|
||||
LOG_FATAL("Another chronyd may already be running (pid=%d), check %s",
|
||||
pid, pidfile);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
write_lockfile(void)
|
||||
write_pidfile(void)
|
||||
{
|
||||
const char *pidfile = CNF_GetPidFile();
|
||||
FILE *out;
|
||||
|
||||
if (!pidfile[0])
|
||||
return;
|
||||
|
||||
out = fopen(pidfile, "w");
|
||||
if (!out) {
|
||||
LOG_FATAL(LOGF_Main, "could not open lockfile %s for writing", pidfile);
|
||||
LOG_FATAL("Could not open %s : %s", pidfile, strerror(errno));
|
||||
} else {
|
||||
fprintf(out, "%d\n", (int)getpid());
|
||||
fclose(out);
|
||||
@@ -299,6 +292,8 @@ write_lockfile(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#define DEV_NULL "/dev/null"
|
||||
|
||||
static void
|
||||
go_daemon(void)
|
||||
{
|
||||
@@ -307,14 +302,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 +320,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 +335,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 +343,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
|
||||
@@ -358,148 +354,199 @@ go_daemon(void)
|
||||
}
|
||||
|
||||
LOG_SetParentFd(pipefd[1]);
|
||||
|
||||
/* Open /dev/null as new stdin/out/err */
|
||||
errno = 0;
|
||||
if (open(DEV_NULL, O_RDONLY) != STDIN_FILENO ||
|
||||
open(DEV_NULL, O_WRONLY) != STDOUT_FILENO ||
|
||||
open(DEV_NULL, O_RDWR) != STDERR_FILENO)
|
||||
LOG_FATAL("Could not open %s : %s", DEV_NULL, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
print_help(const char *progname)
|
||||
{
|
||||
printf("Usage: %s [-4|-6] [-n|-d] [-q|-Q] [-r] [-R] [-s] [-t TIMEOUT] [-f FILE|COMMAND...]\n",
|
||||
progname);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
print_version(void)
|
||||
{
|
||||
printf("chronyd (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYD_FEATURES);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
parse_int_arg(const char *arg)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (sscanf(arg, "%d", &i) != 1)
|
||||
LOG_FATAL("Invalid argument %s", arg);
|
||||
return i;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int main
|
||||
(int argc, char **argv)
|
||||
{
|
||||
const char *conf_file = DEFAULT_CONF_FILE;
|
||||
const char *progname = argv[0];
|
||||
char *user = NULL;
|
||||
char *user = NULL, *log_file = NULL;
|
||||
struct passwd *pw;
|
||||
int debug = 0, nofork = 0, address_family = IPADDR_UNSPEC;
|
||||
int do_init_rtc = 0, restarted = 0, timeout = 0;
|
||||
int other_pid;
|
||||
int opt, debug = 0, nofork = 0, address_family = IPADDR_UNSPEC;
|
||||
int do_init_rtc = 0, restarted = 0, client_only = 0, timeout = 0;
|
||||
int scfilter_level = 0, lock_memory = 0, sched_priority = 0;
|
||||
int system_log = 1;
|
||||
int clock_control = 1, system_log = 1;
|
||||
int config_args = 0;
|
||||
|
||||
do_platform_checks();
|
||||
|
||||
LOG_Initialise();
|
||||
|
||||
/* Parse command line options */
|
||||
while (++argv, (--argc)>0) {
|
||||
|
||||
if (!strcmp("-f", *argv)) {
|
||||
++argv, --argc;
|
||||
conf_file = *argv;
|
||||
} else if (!strcmp("-P", *argv)) {
|
||||
++argv, --argc;
|
||||
if (argc == 0 || sscanf(*argv, "%d", &sched_priority) != 1) {
|
||||
LOG_FATAL(LOGF_Main, "Bad scheduler priority");
|
||||
}
|
||||
} else if (!strcmp("-m", *argv)) {
|
||||
lock_memory = 1;
|
||||
} else if (!strcmp("-r", *argv)) {
|
||||
reload = 1;
|
||||
} else if (!strcmp("-R", *argv)) {
|
||||
restarted = 1;
|
||||
} else if (!strcmp("-u", *argv)) {
|
||||
++argv, --argc;
|
||||
if (argc == 0) {
|
||||
LOG_FATAL(LOGF_Main, "Missing user name");
|
||||
} else {
|
||||
user = *argv;
|
||||
}
|
||||
} else if (!strcmp("-F", *argv)) {
|
||||
++argv, --argc;
|
||||
if (argc == 0 || sscanf(*argv, "%d", &scfilter_level) != 1)
|
||||
LOG_FATAL(LOGF_Main, "Bad syscall filter level");
|
||||
} else if (!strcmp("-s", *argv)) {
|
||||
do_init_rtc = 1;
|
||||
} else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
|
||||
/* This write to the terminal is OK, it comes before we turn into a daemon */
|
||||
printf("chronyd (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYD_FEATURES);
|
||||
/* Parse (undocumented) long command-line options */
|
||||
for (optind = 1; optind < argc; optind++) {
|
||||
if (!strcmp("--help", argv[optind])) {
|
||||
print_help(progname);
|
||||
return 0;
|
||||
} else if (!strcmp("-n", *argv)) {
|
||||
nofork = 1;
|
||||
} else if (!strcmp("-d", *argv)) {
|
||||
debug++;
|
||||
nofork = 1;
|
||||
system_log = 0;
|
||||
} else if (!strcmp("-q", *argv)) {
|
||||
ref_mode = REF_ModeUpdateOnce;
|
||||
nofork = 1;
|
||||
system_log = 0;
|
||||
} else if (!strcmp("-Q", *argv)) {
|
||||
ref_mode = REF_ModePrintOnce;
|
||||
nofork = 1;
|
||||
system_log = 0;
|
||||
} else if (!strcmp("-t", *argv)) {
|
||||
++argv, --argc;
|
||||
if (argc == 0 || sscanf(*argv, "%d", &timeout) != 1 || timeout <= 0)
|
||||
LOG_FATAL(LOGF_Main, "Bad timeout");
|
||||
} else if (!strcmp("-4", *argv)) {
|
||||
address_family = IPADDR_INET4;
|
||||
} else if (!strcmp("-6", *argv)) {
|
||||
address_family = IPADDR_INET6;
|
||||
} else if (!strcmp("-h", *argv) || !strcmp("--help", *argv)) {
|
||||
printf("Usage: %s [-4|-6] [-n|-d] [-q|-Q] [-r] [-R] [-s] [-t TIMEOUT] [-f FILE|COMMAND...]\n",
|
||||
progname);
|
||||
} else if (!strcmp("--version", argv[optind])) {
|
||||
print_version();
|
||||
return 0;
|
||||
} else if (*argv[0] == '-') {
|
||||
LOG_FATAL(LOGF_Main, "Unrecognized command line option [%s]", *argv);
|
||||
} else {
|
||||
/* Process remaining arguments and configuration lines */
|
||||
config_args = argc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (getuid() != 0) {
|
||||
/* This write to the terminal is OK, it comes before we turn into a daemon */
|
||||
fprintf(stderr,"Not superuser\n");
|
||||
return 1;
|
||||
optind = 1;
|
||||
|
||||
/* Parse short command-line options */
|
||||
while ((opt = getopt(argc, argv, "46df:F:hl:mnP:qQrRst:u:vx")) != -1) {
|
||||
switch (opt) {
|
||||
case '4':
|
||||
case '6':
|
||||
address_family = opt == '4' ? IPADDR_INET4 : IPADDR_INET6;
|
||||
break;
|
||||
case 'd':
|
||||
debug++;
|
||||
nofork = 1;
|
||||
system_log = 0;
|
||||
break;
|
||||
case 'f':
|
||||
conf_file = optarg;
|
||||
break;
|
||||
case 'F':
|
||||
scfilter_level = parse_int_arg(optarg);
|
||||
break;
|
||||
case 'l':
|
||||
log_file = optarg;
|
||||
break;
|
||||
case 'm':
|
||||
lock_memory = 1;
|
||||
break;
|
||||
case 'n':
|
||||
nofork = 1;
|
||||
break;
|
||||
case 'P':
|
||||
sched_priority = parse_int_arg(optarg);
|
||||
break;
|
||||
case 'q':
|
||||
ref_mode = REF_ModeUpdateOnce;
|
||||
nofork = 1;
|
||||
client_only = 0;
|
||||
system_log = 0;
|
||||
break;
|
||||
case 'Q':
|
||||
ref_mode = REF_ModePrintOnce;
|
||||
nofork = 1;
|
||||
client_only = 1;
|
||||
clock_control = 0;
|
||||
system_log = 0;
|
||||
break;
|
||||
case 'r':
|
||||
reload = 1;
|
||||
break;
|
||||
case 'R':
|
||||
restarted = 1;
|
||||
break;
|
||||
case 's':
|
||||
do_init_rtc = 1;
|
||||
break;
|
||||
case 't':
|
||||
timeout = parse_int_arg(optarg);
|
||||
break;
|
||||
case 'u':
|
||||
user = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
print_version();
|
||||
return 0;
|
||||
case 'x':
|
||||
clock_control = 0;
|
||||
break;
|
||||
default:
|
||||
print_help(progname);
|
||||
return opt != 'h';
|
||||
}
|
||||
}
|
||||
|
||||
if (getuid() && !client_only)
|
||||
LOG_FATAL("Not superuser");
|
||||
|
||||
/* Turn into a daemon */
|
||||
if (!nofork) {
|
||||
go_daemon();
|
||||
}
|
||||
|
||||
if (system_log) {
|
||||
if (log_file) {
|
||||
LOG_OpenFileLog(log_file);
|
||||
} else if (system_log) {
|
||||
LOG_OpenSystemLog();
|
||||
}
|
||||
|
||||
LOG_SetDebugLevel(debug);
|
||||
|
||||
LOG(LOGS_INFO, LOGF_Main, "chronyd version %s starting (%s)",
|
||||
CHRONY_VERSION, CHRONYD_FEATURES);
|
||||
LOG(LOGS_INFO, "chronyd version %s starting (%s)", CHRONY_VERSION, CHRONYD_FEATURES);
|
||||
|
||||
DNS_SetAddressFamily(address_family);
|
||||
|
||||
CNF_Initialise(restarted);
|
||||
CNF_Initialise(restarted, client_only);
|
||||
|
||||
/* Parse the config file or the remaining command line arguments */
|
||||
config_args = argc - optind;
|
||||
if (!config_args) {
|
||||
CNF_ReadFile(conf_file);
|
||||
} else {
|
||||
do {
|
||||
CNF_ParseLine(NULL, config_args - argc + 1, *argv);
|
||||
} while (++argv, --argc);
|
||||
for (; optind < argc; optind++)
|
||||
CNF_ParseLine(NULL, config_args + optind - argc + 1, argv[optind]);
|
||||
}
|
||||
|
||||
/* Check whether another chronyd may already be running. Do this after
|
||||
* forking, so that message logging goes to the right place (i.e. syslog), in
|
||||
* case this chronyd is being run from a boot script. */
|
||||
if (maybe_another_chronyd_running(&other_pid)) {
|
||||
LOG_FATAL(LOGF_Main, "Another chronyd may already be running (pid=%d), check lockfile (%s)",
|
||||
other_pid, CNF_GetPidFile());
|
||||
}
|
||||
/* Check whether another chronyd may already be running */
|
||||
check_pidfile();
|
||||
|
||||
/* Write our lockfile to prevent other chronyds running. This has *GOT* to
|
||||
* be done *AFTER* the daemon-creation fork() */
|
||||
write_lockfile();
|
||||
/* Write our pidfile to prevent other chronyds running */
|
||||
write_pidfile();
|
||||
|
||||
if (!user)
|
||||
user = CNF_GetUser();
|
||||
|
||||
pw = getpwnam(user);
|
||||
if (!pw)
|
||||
LOG_FATAL("Could not get user/group ID of %s", user);
|
||||
|
||||
/* Create directories for sockets, log files, and dump files */
|
||||
CNF_CreateDirs(pw->pw_uid, pw->pw_gid);
|
||||
|
||||
PRV_Initialise();
|
||||
LCL_Initialise();
|
||||
SCH_Initialise();
|
||||
SYS_Initialise();
|
||||
SYS_Initialise(clock_control);
|
||||
RTC_Initialise(do_init_rtc);
|
||||
SRC_Initialise();
|
||||
RCL_Initialise();
|
||||
@@ -523,18 +570,8 @@ int main
|
||||
SYS_LockMemory();
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
user = CNF_GetUser();
|
||||
}
|
||||
|
||||
if ((pw = getpwnam(user)) == NULL)
|
||||
LOG_FATAL(LOGF_Main, "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 +600,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 +613,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);
|
||||
|
||||
34
memory.c
34
memory.c
@@ -2,7 +2,7 @@
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2014
|
||||
* Copyright (C) Miroslav Lichvar 2014, 2017
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -37,7 +37,7 @@ Malloc(size_t size)
|
||||
|
||||
r = malloc(size);
|
||||
if (!r && size)
|
||||
LOG_FATAL(LOGF_Memory, "Could not allocate memory");
|
||||
LOG_FATAL("Could not allocate memory");
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -49,11 +49,37 @@ Realloc(void *ptr, size_t size)
|
||||
|
||||
r = realloc(ptr, size);
|
||||
if (!r && size)
|
||||
LOG_FATAL(LOGF_Memory, "Could not allocate memory");
|
||||
LOG_FATAL("Could not allocate memory");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static size_t
|
||||
get_array_size(size_t nmemb, size_t size)
|
||||
{
|
||||
size_t array_size;
|
||||
|
||||
array_size = nmemb * size;
|
||||
|
||||
/* Check for overflow */
|
||||
if (nmemb > 0 && array_size / nmemb != size)
|
||||
LOG_FATAL("Could not allocate memory");
|
||||
|
||||
return array_size;
|
||||
}
|
||||
|
||||
void *
|
||||
Malloc2(size_t nmemb, size_t size)
|
||||
{
|
||||
return Malloc(get_array_size(nmemb, size));
|
||||
}
|
||||
|
||||
void *
|
||||
Realloc2(void *ptr, size_t nmemb, size_t size)
|
||||
{
|
||||
return Realloc(ptr, get_array_size(nmemb, size));
|
||||
}
|
||||
|
||||
char *
|
||||
Strdup(const char *s)
|
||||
{
|
||||
@@ -61,7 +87,7 @@ Strdup(const char *s)
|
||||
|
||||
r = strdup(s);
|
||||
if (!r)
|
||||
LOG_FATAL(LOGF_Memory, "Could not allocate memory");
|
||||
LOG_FATAL("Could not allocate memory");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
6
memory.h
6
memory.h
@@ -30,12 +30,14 @@
|
||||
/* Wrappers checking for errors */
|
||||
extern void *Malloc(size_t size);
|
||||
extern void *Realloc(void *ptr, size_t size);
|
||||
extern void *Malloc2(size_t nmemb, size_t size);
|
||||
extern void *Realloc2(void *ptr, size_t nmemb, size_t size);
|
||||
extern char *Strdup(const char *s);
|
||||
|
||||
/* Convenient macros */
|
||||
#define MallocNew(T) ((T *) Malloc(sizeof(T)))
|
||||
#define MallocArray(T, n) ((T *) Malloc((n) * sizeof(T)))
|
||||
#define ReallocArray(T,n,x) ((T *) Realloc((void *)(x), (n)*sizeof(T)))
|
||||
#define MallocArray(T, n) ((T *) Malloc2(n, sizeof(T)))
|
||||
#define ReallocArray(T, n, x) ((T *) Realloc2((void *)(x), n, sizeof(T)))
|
||||
#define Free(x) free(x)
|
||||
|
||||
#endif /* GOT_MEMORY_H */
|
||||
|
||||
14
nameserv.c
14
nameserv.c
@@ -53,7 +53,19 @@ DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
|
||||
max_addrs = MIN(max_addrs, DNS_MAX_ADDRESSES);
|
||||
|
||||
memset(&hints, 0, sizeof (hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
|
||||
switch (address_family) {
|
||||
case IPADDR_INET4:
|
||||
hints.ai_family = AF_INET;
|
||||
break;
|
||||
#ifdef FEAT_IPV6
|
||||
case IPADDR_INET6:
|
||||
hints.ai_family = AF_INET6;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
}
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
result = getaddrinfo(name, NULL, &hints, &res);
|
||||
|
||||
@@ -78,7 +78,7 @@ end_resolving(int fd, int event, void *anything)
|
||||
int i;
|
||||
|
||||
if (pthread_join(inst->thread, NULL)) {
|
||||
LOG_FATAL(LOGF_Nameserv, "pthread_join() failed");
|
||||
LOG_FATAL("pthread_join() failed");
|
||||
}
|
||||
|
||||
resolving_threads--;
|
||||
@@ -110,7 +110,7 @@ DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *
|
||||
inst->status = DNS_Failure;
|
||||
|
||||
if (pipe(inst->pipe)) {
|
||||
LOG_FATAL(LOGF_Nameserv, "pipe() failed");
|
||||
LOG_FATAL("pipe() failed");
|
||||
}
|
||||
|
||||
UTI_FdSetCloexec(inst->pipe[0]);
|
||||
@@ -120,7 +120,7 @@ DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *
|
||||
assert(resolving_threads <= 1);
|
||||
|
||||
if (pthread_create(&inst->thread, NULL, start_resolving, inst)) {
|
||||
LOG_FATAL(LOGF_Nameserv, "pthread_create() failed");
|
||||
LOG_FATAL("pthread_create() failed");
|
||||
}
|
||||
|
||||
SCH_AddFileHandler(inst->pipe[0], SCH_FILE_INPUT, end_resolving, inst);
|
||||
|
||||
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
|
||||
|
||||
|
||||
812
ntp_core.c
812
ntp_core.c
File diff suppressed because it is too large
Load Diff
92
ntp_io.c
92
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;
|
||||
@@ -321,6 +318,9 @@ close_socket(int sock_fd)
|
||||
if (sock_fd == INVALID_SOCK_FD)
|
||||
return;
|
||||
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
NIO_Linux_NotifySocketClosing(sock_fd);
|
||||
#endif
|
||||
SCH_RemoveFileHandler(sock_fd);
|
||||
close(sock_fd);
|
||||
}
|
||||
@@ -364,8 +364,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 +430,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 +578,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 +597,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 +619,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 +631,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 +659,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 */
|
||||
@@ -687,6 +688,11 @@ read_from_socket(int sock_fd, int event, void *anything)
|
||||
unsigned int i, n;
|
||||
int status, flags = 0;
|
||||
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
if (NIO_Linux_ProcessEvent(sock_fd, event))
|
||||
return;
|
||||
#endif
|
||||
|
||||
hdr = ARR_GetElements(recv_headers);
|
||||
n = ARR_GetSize(recv_headers);
|
||||
assert(n >= 1);
|
||||
@@ -711,7 +717,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 +748,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 +824,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);
|
||||
|
||||
|
||||
509
ntp_io_linux.c
509
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
|
||||
@@ -32,7 +32,6 @@
|
||||
#include <linux/errqueue.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/ptp_clock.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <net/if.h>
|
||||
|
||||
@@ -61,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;
|
||||
|
||||
@@ -82,22 +94,42 @@ static int ts_tx_flags;
|
||||
/* Flag indicating the socket options can't be changed in control messages */
|
||||
static int permanent_ts_options;
|
||||
|
||||
/* When sending client requests to a close and fast server, it is possible that
|
||||
a response will be received before the HW transmit timestamp of the request
|
||||
itself. To avoid processing of the response without the HW timestamp, we
|
||||
monitor events returned by select() and suspend reading of packets from the
|
||||
receive queue for up to 200 microseconds. As the requests are normally
|
||||
separated by at least 200 milliseconds, it is sufficient to monitor and
|
||||
suspend one socket at a time. */
|
||||
static int monitored_socket;
|
||||
static int suspended_socket;
|
||||
static SCH_TimeoutID resume_timeout_id;
|
||||
|
||||
#define RESUME_TIMEOUT 200.0e-6
|
||||
|
||||
/* Unbound socket keeping the kernel RX timestamping permanently enabled
|
||||
in order to avoid a race condition between receiving a server response
|
||||
and the kernel actually starting to timestamp received packets after
|
||||
enabling the timestamping and sending a request */
|
||||
static int dummy_rxts_socket;
|
||||
|
||||
#define INVALID_SOCK_FD -3
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
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(name, ((struct Interface *)ARR_GetElement(interfaces, i))->name))
|
||||
if (!strcmp(conf_iface->name, ((struct Interface *)ARR_GetElement(interfaces, i))->name))
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -108,13 +140,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;
|
||||
}
|
||||
@@ -125,50 +158,82 @@ 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_ANY:
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP
|
||||
if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_NTP_ALL))
|
||||
ts_config.rx_filter = HWTSTAMP_FILTER_NTP_ALL;
|
||||
else
|
||||
#endif
|
||||
if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_ALL))
|
||||
ts_config.rx_filter = HWTSTAMP_FILTER_ALL;
|
||||
else
|
||||
ts_config.rx_filter = HWTSTAMP_FILTER_NONE;
|
||||
break;
|
||||
case CNF_HWTS_RXFILTER_NONE:
|
||||
ts_config.rx_filter = HWTSTAMP_FILTER_NONE;
|
||||
break;
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP
|
||||
case CNF_HWTS_RXFILTER_NTP:
|
||||
ts_config.rx_filter = HWTSTAMP_FILTER_NTP_ALL;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ts_config.rx_filter = HWTSTAMP_FILTER_ALL;
|
||||
break;
|
||||
}
|
||||
|
||||
req.ifr_data = (char *)&ts_config;
|
||||
|
||||
if (ioctl(sock_fd, SIOCSHWTSTAMP, &req)) {
|
||||
DEBUG_LOG(LOGF_NtpIOLinux, "ioctl(%s) failed : %s", "SIOCSHWTSTAMP", strerror(errno));
|
||||
DEBUG_LOG("ioctl(%s) failed : %s", "SIOCSHWTSTAMP", strerror(errno));
|
||||
close(sock_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
DEBUG_LOG(LOGF_NtpIOLinux, "Enabled HW timestamping on %s", name);
|
||||
iface->clock = HCL_CreateInstance(UTI_Log2ToDouble(MAX(conf_iface->minpoll, MIN_PHC_POLL)));
|
||||
|
||||
LOG(LOGS_INFO, "Enabled HW timestamping %son %s",
|
||||
ts_config.rx_filter == HWTSTAMP_FILTER_NONE ? "(TX only) " : "", iface->name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -176,18 +241,22 @@ add_interface(const char *name)
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
add_all_interfaces(void)
|
||||
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(LOGF_NtpIOLinux, "getifaddrs() failed : %s", strerror(errno));
|
||||
DEBUG_LOG("getifaddrs() failed : %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (r = 0, ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
|
||||
if (add_interface(ifa->ifa_name))
|
||||
conf_iface.name = ifa->ifa_name;
|
||||
if (add_interface(&conf_iface))
|
||||
r = 1;
|
||||
}
|
||||
|
||||
@@ -204,7 +273,7 @@ update_interface_speed(struct Interface *iface)
|
||||
{
|
||||
struct ethtool_cmd cmd;
|
||||
struct ifreq req;
|
||||
int sock_fd;
|
||||
int sock_fd, link_speed;
|
||||
|
||||
sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock_fd < 0)
|
||||
@@ -218,14 +287,65 @@ 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;
|
||||
}
|
||||
|
||||
close(sock_fd);
|
||||
|
||||
iface->link_speed = ethtool_cmd_speed(&cmd);
|
||||
link_speed = ethtool_cmd_speed(&cmd);
|
||||
|
||||
if (iface->link_speed != link_speed) {
|
||||
iface->link_speed = link_speed;
|
||||
DEBUG_LOG("Updated speed of %s to %d Mb/s", iface->name, link_speed);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#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
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
open_dummy_socket(void)
|
||||
{
|
||||
int sock_fd, events = 0;
|
||||
|
||||
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0
|
||||
#ifdef FEAT_IPV6
|
||||
&& (sock_fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0
|
||||
#endif
|
||||
)
|
||||
return INVALID_SOCK_FD;
|
||||
|
||||
if (!NIO_Linux_SetTimestampSocketOptions(sock_fd, 1, &events)) {
|
||||
close(sock_fd);
|
||||
return INVALID_SOCK_FD;
|
||||
}
|
||||
|
||||
UTI_FdSetCloexec(sock_fd);
|
||||
return sock_fd;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -233,42 +353,45 @@ update_interface_speed(struct Interface *iface)
|
||||
void
|
||||
NIO_Linux_Initialise(void)
|
||||
{
|
||||
ARR_Instance config_hwts_ifaces;
|
||||
char *if_name;
|
||||
CNF_HwTsInterface *conf_iface;
|
||||
unsigned int i;
|
||||
int wildcard, hwts;
|
||||
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. */
|
||||
|
||||
for (i = wildcard = 0; i < ARR_GetSize(config_hwts_ifaces); i++) {
|
||||
if (!strcmp("*", *(char **)ARR_GetElement(config_hwts_ifaces, i)))
|
||||
wildcard = 1;
|
||||
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;
|
||||
}
|
||||
|
||||
if (!wildcard && 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);
|
||||
}
|
||||
hwts = 1;
|
||||
} else if (wildcard && add_all_interfaces()) {
|
||||
hwts = 1;
|
||||
} else {
|
||||
hwts = 0;
|
||||
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;
|
||||
} else {
|
||||
ts_flags = SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_RX_SOFTWARE;
|
||||
ts_tx_flags = SOF_TIMESTAMPING_TX_SOFTWARE;
|
||||
ts_flags |= SOF_TIMESTAMPING_RAW_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE;
|
||||
ts_tx_flags |= SOF_TIMESTAMPING_TX_HARDWARE;
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO
|
||||
if (check_timestamping_option(SOF_TIMESTAMPING_OPT_PKTINFO))
|
||||
ts_flags |= SOF_TIMESTAMPING_OPT_PKTINFO;
|
||||
#endif
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING_OPT_TX_SWHW
|
||||
if (check_timestamping_option(SOF_TIMESTAMPING_OPT_TX_SWHW))
|
||||
ts_flags |= SOF_TIMESTAMPING_OPT_TX_SWHW;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Enable IP_PKTINFO in messages looped back to the error queue */
|
||||
@@ -276,6 +399,10 @@ NIO_Linux_Initialise(void)
|
||||
|
||||
/* Kernels before 4.7 ignore timestamping flags set in control messages */
|
||||
permanent_ts_options = !SYS_Linux_CheckKernelVersion(4, 7);
|
||||
|
||||
monitored_socket = INVALID_SOCK_FD;
|
||||
suspended_socket = INVALID_SOCK_FD;
|
||||
dummy_rxts_socket = INVALID_SOCK_FD;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -286,6 +413,9 @@ NIO_Linux_Finalise(void)
|
||||
struct Interface *iface;
|
||||
unsigned int i;
|
||||
|
||||
if (dummy_rxts_socket != INVALID_SOCK_FD)
|
||||
close(dummy_rxts_socket);
|
||||
|
||||
for (i = 0; i < ARR_GetSize(interfaces); i++) {
|
||||
iface = ARR_GetElement(interfaces, i);
|
||||
HCL_DestroyInstance(iface->clock);
|
||||
@@ -315,13 +445,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;
|
||||
}
|
||||
@@ -332,64 +462,69 @@ 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)
|
||||
static void
|
||||
resume_socket(int sock_fd)
|
||||
{
|
||||
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;
|
||||
if (monitored_socket == sock_fd)
|
||||
monitored_socket = INVALID_SOCK_FD;
|
||||
|
||||
/* Silence valgrind */
|
||||
memset(&sys_off, 0, sizeof (sys_off));
|
||||
if (sock_fd == INVALID_SOCK_FD || sock_fd != suspended_socket)
|
||||
return;
|
||||
|
||||
sys_off.n_samples = PHC_READINGS;
|
||||
suspended_socket = INVALID_SOCK_FD;
|
||||
|
||||
if (ioctl(phc_fd, PTP_SYS_OFFSET, &sys_off)) {
|
||||
DEBUG_LOG(LOGF_NtpIOLinux, "ioctl(%s) failed : %s", "PTP_SYS_OFFSET", strerror(errno));
|
||||
SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_INPUT, 1);
|
||||
|
||||
DEBUG_LOG("Resumed RX processing %s timeout fd=%d",
|
||||
resume_timeout_id ? "before" : "on", sock_fd);
|
||||
|
||||
if (resume_timeout_id) {
|
||||
SCH_RemoveTimeout(resume_timeout_id);
|
||||
resume_timeout_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
resume_timeout(void *arg)
|
||||
{
|
||||
resume_timeout_id = 0;
|
||||
resume_socket(suspended_socket);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
suspend_socket(int sock_fd)
|
||||
{
|
||||
resume_socket(suspended_socket);
|
||||
|
||||
suspended_socket = sock_fd;
|
||||
|
||||
SCH_SetFileHandlerEvent(suspended_socket, SCH_FILE_INPUT, 0);
|
||||
resume_timeout_id = SCH_AddTimeoutByDelay(RESUME_TIMEOUT, resume_timeout, NULL);
|
||||
|
||||
DEBUG_LOG("Suspended RX processing fd=%d", sock_fd);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NIO_Linux_ProcessEvent(int sock_fd, int event)
|
||||
{
|
||||
if (sock_fd != monitored_socket)
|
||||
return 0;
|
||||
|
||||
if (event == SCH_FILE_INPUT) {
|
||||
suspend_socket(monitored_socket);
|
||||
monitored_socket = INVALID_SOCK_FD;
|
||||
|
||||
/* Don't process the message yet */
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -415,38 +550,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;
|
||||
}
|
||||
|
||||
@@ -491,14 +644,43 @@ extract_udp_data(unsigned char *msg, NTP_Remote_Address *remote_addr, int len)
|
||||
len -= ihl + 8, msg += ihl + 8;
|
||||
#ifdef FEAT_IPV6
|
||||
} else if (len >= 48 && msg[0] >> 4 == 6) {
|
||||
/* IPv6 extension headers are not supported */
|
||||
if (msg[6] != 17)
|
||||
return 0;
|
||||
int eh_len, next_header = msg[6];
|
||||
|
||||
memcpy(&addr.in6.sin6_addr.s6_addr, msg + 24, 16);
|
||||
addr.in6.sin6_port = *(uint16_t *)(msg + 40 + 2);
|
||||
len -= 40, msg += 40;
|
||||
|
||||
/* Skip IPv6 extension headers if present */
|
||||
while (next_header != 17) {
|
||||
switch (next_header) {
|
||||
case 44: /* Fragment Header */
|
||||
/* Process only the first fragment */
|
||||
if (ntohs(*(uint16_t *)(msg + 2)) >> 3 != 0)
|
||||
return 0;
|
||||
eh_len = 8;
|
||||
break;
|
||||
case 0: /* Hop-by-Hop Options */
|
||||
case 43: /* Routing Header */
|
||||
case 60: /* Destination Options */
|
||||
case 135: /* Mobility Header */
|
||||
eh_len = 8 * (msg[1] + 1);
|
||||
break;
|
||||
case 51: /* Authentication Header */
|
||||
eh_len = 4 * (msg[1] + 2);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (eh_len < 8 || len < eh_len + 8)
|
||||
return 0;
|
||||
|
||||
next_header = msg[0];
|
||||
len -= eh_len, msg += eh_len;
|
||||
}
|
||||
|
||||
addr.in6.sin6_port = *(uint16_t *)(msg + 2);
|
||||
addr.in6.sin6_family = AF_INET6;
|
||||
len -= 48, msg += 48;
|
||||
len -= 8, msg += 8;
|
||||
#endif
|
||||
} else {
|
||||
return 0;
|
||||
@@ -517,33 +699,55 @@ 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 a HW transmit timestamp was received, resume processing
|
||||
of non-error messages on this socket */
|
||||
if (is_tx)
|
||||
resume_socket(local_addr->sock_fd);
|
||||
}
|
||||
|
||||
if (local_ts->source == NTP_TS_DAEMON && !UTI_IsZeroTimespec(&ts3.ts[0]) &&
|
||||
(!is_tx || UTI_IsZeroTimespec(&ts3.ts[2]))) {
|
||||
LCL_CookTime(&ts3.ts[0], &local_ts->ts, &local_ts->err);
|
||||
local_ts->source = NTP_TS_KERNEL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -555,13 +759,21 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If the kernel is slow with enabling RX timestamping, open a dummy
|
||||
socket to keep the kernel RX timestamping permanently enabled */
|
||||
if (!is_tx && local_ts->source == NTP_TS_DAEMON && ts_flags) {
|
||||
DEBUG_LOG("Missing kernel RX timestamp");
|
||||
if (dummy_rxts_socket == INVALID_SOCK_FD)
|
||||
dummy_rxts_socket = open_dummy_socket();
|
||||
}
|
||||
|
||||
/* Return the message if it's not received from the error queue */
|
||||
if (!is_tx)
|
||||
return 0;
|
||||
@@ -572,9 +784,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) {
|
||||
@@ -584,9 +796,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;
|
||||
}
|
||||
|
||||
@@ -606,6 +818,15 @@ NIO_Linux_RequestTxTimestamp(struct msghdr *msg, int cmsglen, int sock_fd)
|
||||
{
|
||||
struct cmsghdr *cmsg;
|
||||
|
||||
if (!ts_flags)
|
||||
return cmsglen;
|
||||
|
||||
/* If a HW transmit timestamp is requested on a client socket, monitor
|
||||
events on the socket in order to avoid processing of a fast response
|
||||
without the HW timestamp of the request */
|
||||
if (ts_tx_flags & SOF_TIMESTAMPING_TX_HARDWARE && !NIO_IsServerSocket(sock_fd))
|
||||
monitored_socket = sock_fd;
|
||||
|
||||
/* Check if TX timestamping is disabled on this socket */
|
||||
if (permanent_ts_options || !NIO_IsServerSocket(sock_fd))
|
||||
return cmsglen;
|
||||
@@ -625,3 +846,11 @@ NIO_Linux_RequestTxTimestamp(struct msghdr *msg, int cmsglen, int sock_fd)
|
||||
|
||||
return cmsglen;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NIO_Linux_NotifySocketClosing(int sock_fd)
|
||||
{
|
||||
resume_socket(sock_fd);
|
||||
}
|
||||
|
||||
@@ -24,14 +24,22 @@
|
||||
This is the header file for the Linux-specific NTP socket I/O bits.
|
||||
*/
|
||||
|
||||
#ifndef GOT_NTP_IO_LINUX_H
|
||||
#define GOT_NTP_IO_LINUX_H
|
||||
|
||||
extern void NIO_Linux_Initialise(void);
|
||||
|
||||
extern void NIO_Linux_Finalise(void);
|
||||
|
||||
extern int NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events);
|
||||
|
||||
extern int NIO_Linux_ProcessEvent(int sock_fd, int event);
|
||||
|
||||
extern int NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
|
||||
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);
|
||||
|
||||
extern void NIO_Linux_NotifySocketClosing(int sock_fd);
|
||||
|
||||
#endif
|
||||
|
||||
47
ntp_signd.c
47
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 */
|
||||
@@ -235,12 +235,12 @@ read_write_socket(int sock_fd, int event, void *anything)
|
||||
return;
|
||||
|
||||
/* Disable output and wait for a response */
|
||||
SCH_SetFileHandlerEvents(sock_fd, SCH_FILE_INPUT);
|
||||
SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_OUTPUT, 0);
|
||||
}
|
||||
|
||||
if (event == SCH_FILE_INPUT) {
|
||||
if (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;
|
||||
}
|
||||
@@ -283,7 +283,7 @@ read_write_socket(int sock_fd, int event, void *anything)
|
||||
/* Move the head and enable output for the next packet */
|
||||
queue_head = NEXT_QUEUE_INDEX(queue_head);
|
||||
if (!IS_QUEUE_EMPTY())
|
||||
SCH_SetFileHandlerEvents(sock_fd, SCH_FILE_INPUT | SCH_FILE_OUTPUT);
|
||||
SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_OUTPUT, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -369,12 +369,11 @@ NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_Remote_Address *r
|
||||
|
||||
/* Enable output if there was no pending request */
|
||||
if (IS_QUEUE_EMPTY())
|
||||
SCH_SetFileHandlerEvents(sock_fd, SCH_FILE_INPUT | SCH_FILE_OUTPUT);
|
||||
SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_OUTPUT, 1);
|
||||
|
||||
queue_tail = NEXT_QUEUE_INDEX(queue_tail);
|
||||
|
||||
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 */
|
||||
|
||||
28
pktlength.c
28
pktlength.c
@@ -114,8 +114,11 @@ static const struct request_length request_lengths[] = {
|
||||
client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX2 */
|
||||
REQ_LENGTH_ENTRY(local, null), /* LOCAL2 */
|
||||
REQ_LENGTH_ENTRY(ntp_data, ntp_data), /* NTP_DATA */
|
||||
REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_SERVER2 */
|
||||
REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_PEER2 */
|
||||
{ 0, 0 }, /* ADD_SERVER2 */
|
||||
{ 0, 0 }, /* ADD_PEER2 */
|
||||
REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_SERVER3 */
|
||||
REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_PEER3 */
|
||||
REQ_LENGTH_ENTRY(null, null), /* SHUTDOWN */
|
||||
};
|
||||
|
||||
static const uint16_t reply_lengths[] = {
|
||||
@@ -123,19 +126,21 @@ 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 */
|
||||
0, /* SUBNETS_ACCESSED - not supported */
|
||||
0, /* CLIENT_ACCESSES - not supported */
|
||||
0, /* CLIENT_ACCESSES_BY_INDEX - not supported */
|
||||
0, /* MANUAL_LIST - variable length */
|
||||
0, /* MANUAL_LIST - not supported */
|
||||
RPY_LENGTH_ENTRY(activity), /* ACTIVITY */
|
||||
RPY_LENGTH_ENTRY(smoothing), /* SMOOTHING */
|
||||
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 */
|
||||
RPY_LENGTH_ENTRY(manual_list), /* MANUAL_LIST2 */
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
@@ -192,21 +197,6 @@ PKL_ReplyLength(CMD_Reply *r)
|
||||
if (type < 1 || type >= N_REPLY_TYPES)
|
||||
return 0;
|
||||
|
||||
/* Length of MANUAL_LIST depends on number of samples stored in it */
|
||||
if (type == RPY_MANUAL_LIST) {
|
||||
uint32_t ns;
|
||||
|
||||
if (r->status != htons(STT_SUCCESS))
|
||||
return offsetof(CMD_Reply, data);
|
||||
|
||||
ns = ntohl(r->data.manual_list.n_samples);
|
||||
if (ns > MAX_MANUAL_LIST_SAMPLES)
|
||||
return 0;
|
||||
|
||||
return offsetof(CMD_Reply, data.manual_list.samples) +
|
||||
ns * sizeof (RPY_ManualListSample);
|
||||
}
|
||||
|
||||
return reply_lengths[type];
|
||||
}
|
||||
|
||||
|
||||
67
privops.c
67
privops.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Bryan Christianson 2015
|
||||
* Copyright (C) Miroslav Lichvar 2016
|
||||
* Copyright (C) Miroslav Lichvar 2017
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -40,6 +40,7 @@
|
||||
#define OP_SETTIME 1026
|
||||
#define OP_BINDSOCKET 1027
|
||||
#define OP_NAME2IPADDRESS 1028
|
||||
#define OP_RELOADDNS 1029
|
||||
#define OP_QUIT 1099
|
||||
|
||||
union sockaddr_in46 {
|
||||
@@ -293,8 +294,6 @@ do_name_to_ipaddress(ReqName2IPAddress *req, PrvResponse *res)
|
||||
/* make sure the string is terminated */
|
||||
req->name[sizeof (req->name) - 1] = '\0';
|
||||
|
||||
DNS_Reload();
|
||||
|
||||
res->rc = DNS_Name2IPAddress(req->name, res->data.name_to_ipaddress.addresses,
|
||||
DNS_MAX_ADDRESSES);
|
||||
}
|
||||
@@ -302,6 +301,19 @@ do_name_to_ipaddress(ReqName2IPAddress *req, PrvResponse *res)
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
/* HELPER - perform DNS_Reload() */
|
||||
|
||||
#ifdef PRIVOPS_RELOADDNS
|
||||
static void
|
||||
do_reload_dns(PrvResponse *res)
|
||||
{
|
||||
DNS_Reload();
|
||||
res->rc = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
/* HELPER - main loop - action requests from the daemon */
|
||||
|
||||
static void
|
||||
@@ -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);
|
||||
|
||||
208
refclock.c
208
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-2017
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -75,15 +75,19 @@ 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;
|
||||
int stratum;
|
||||
int tai;
|
||||
struct MedianFilter filter;
|
||||
uint32_t ref_id;
|
||||
uint32_t lock_ref;
|
||||
double offset;
|
||||
double delay;
|
||||
double precision;
|
||||
double pulse_width;
|
||||
SCH_TimeoutID timeout_id;
|
||||
SRC_Instance source;
|
||||
};
|
||||
@@ -93,7 +97,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 +168,6 @@ RCL_Finalise(void)
|
||||
int
|
||||
RCL_AddRefclock(RefclockParameters *params)
|
||||
{
|
||||
int pps_source = 0;
|
||||
RCL_Instance inst;
|
||||
|
||||
inst = MallocNew(struct RCL_Instance_Record);
|
||||
@@ -172,27 +175,21 @@ 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);
|
||||
return 0;
|
||||
LOG_FATAL("unknown refclock driver %s", params->driver_name);
|
||||
}
|
||||
|
||||
if (!inst->driver->init && !inst->driver->poll) {
|
||||
LOG_FATAL(LOGF_Refclock, "refclock driver %s is not compiled in", params->driver_name);
|
||||
return 0;
|
||||
}
|
||||
if (!inst->driver->init && !inst->driver->poll)
|
||||
LOG_FATAL("refclock driver %s is not compiled in", params->driver_name);
|
||||
|
||||
if (params->tai && !CNF_GetLeapSecTimezone())
|
||||
LOG_FATAL("refclock tai option requires leapsectz");
|
||||
|
||||
inst->data = NULL;
|
||||
inst->driver_parameter = params->driver_parameter;
|
||||
@@ -201,14 +198,18 @@ 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->stratum = params->stratum;
|
||||
inst->tai = params->tai;
|
||||
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 +222,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,25 +248,22 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (inst->driver->init)
|
||||
if (!inst->driver->init(inst)) {
|
||||
LOG_FATAL(LOGF_Refclock, "refclock %s initialisation failed", params->driver_name);
|
||||
return 0;
|
||||
}
|
||||
if (inst->driver->init && !inst->driver->init(inst))
|
||||
LOG_FATAL("refclock %s initialisation failed", params->driver_name);
|
||||
|
||||
filter_init(&inst->filter, params->filter_length, params->max_dispersion);
|
||||
|
||||
inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, params->sel_options, NULL,
|
||||
params->min_samples, params->max_samples);
|
||||
params->min_samples, params->max_samples, 0.0, 0.0);
|
||||
|
||||
DEBUG_LOG(LOGF_Refclock, "refclock %s refid=%s poll=%d dpoll=%d filter=%d",
|
||||
DEBUG_LOG("refclock %s refid=%s poll=%d dpoll=%d filter=%d",
|
||||
params->driver_name, UTI_RefidToString(inst->ref_id),
|
||||
inst->poll, inst->driver_poll, params->filter_length);
|
||||
|
||||
@@ -363,19 +357,44 @@ RCL_GetDriverOption(RCL_Instance instance, char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
convert_tai_offset(struct timespec *sample_time, double *offset)
|
||||
{
|
||||
struct timespec tai_ts, utc_ts;
|
||||
int tai_offset;
|
||||
|
||||
/* Get approximate TAI-UTC offset for the reference time in TAI */
|
||||
UTI_AddDoubleToTimespec(sample_time, *offset, &tai_ts);
|
||||
tai_offset = REF_GetTaiOffset(&tai_ts);
|
||||
|
||||
/* Get TAI-UTC offset for the reference time in UTC +/- 1 second */
|
||||
UTI_AddDoubleToTimespec(&tai_ts, -tai_offset, &utc_ts);
|
||||
tai_offset = REF_GetTaiOffset(&utc_ts);
|
||||
|
||||
if (!tai_offset)
|
||||
return 0;
|
||||
|
||||
*offset -= tai_offset;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
RCL_AddSample(RCL_Instance instance, struct timespec *sample_time, double offset, int leap)
|
||||
{
|
||||
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,10 +404,15 @@ 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;
|
||||
}
|
||||
|
||||
if (instance->tai && !convert_tai_offset(sample_time, &offset)) {
|
||||
DEBUG_LOG("refclock sample ignored unknown TAI offset");
|
||||
return 0;
|
||||
}
|
||||
|
||||
filter_add_sample(&instance->filter, &cooked_time, offset - correction + instance->offset, dispersion);
|
||||
instance->pps_active = 0;
|
||||
|
||||
@@ -404,24 +428,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 +496,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 +518,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 +539,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 +569,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;
|
||||
}
|
||||
|
||||
@@ -587,7 +663,7 @@ poll_timeout(void *arg)
|
||||
/* Handle special case when PPS is used with local stratum */
|
||||
stratum = pps_stratum(inst, &sample_time);
|
||||
else
|
||||
stratum = 0;
|
||||
stratum = inst->stratum;
|
||||
|
||||
SRC_UpdateReachability(inst->source, 1);
|
||||
SRC_AccumulateSample(inst->source, &sample_time, offset,
|
||||
@@ -713,7 +789,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 +979,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,17 +37,21 @@ typedef struct {
|
||||
int driver_poll;
|
||||
int poll;
|
||||
int filter_length;
|
||||
int pps_forced;
|
||||
int pps_rate;
|
||||
int min_samples;
|
||||
int max_samples;
|
||||
int sel_options;
|
||||
int max_lock_age;
|
||||
int stratum;
|
||||
int tai;
|
||||
uint32_t ref_id;
|
||||
uint32_t lock_ref_id;
|
||||
double offset;
|
||||
double delay;
|
||||
double precision;
|
||||
double max_dispersion;
|
||||
double pulse_width;
|
||||
} RefclockParameters;
|
||||
|
||||
typedef struct RCL_Instance_Record *RCL_Instance;
|
||||
@@ -71,5 +75,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;
|
||||
}
|
||||
|
||||
|
||||
256
reference.c
256
reference.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2009-2016
|
||||
* Copyright (C) Miroslav Lichvar 2009-2017
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -49,6 +49,7 @@ static int local_orphan;
|
||||
static double local_distance;
|
||||
static NTP_Leap our_leap_status;
|
||||
static int our_leap_sec;
|
||||
static int our_tai_offset;
|
||||
static int our_stratum;
|
||||
static uint32_t our_ref_id;
|
||||
static IPAddr our_ref_ip;
|
||||
@@ -111,8 +112,6 @@ static SCH_TimeoutID leap_timeout_id;
|
||||
|
||||
/* Name of a system timezone containing leap seconds occuring at midnight */
|
||||
static char *leap_tzname;
|
||||
static time_t last_tz_leap_check;
|
||||
static NTP_Leap tz_leap;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -141,7 +140,7 @@ static double last_ref_update_interval;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static NTP_Leap get_tz_leap(time_t when);
|
||||
static NTP_Leap get_tz_leap(time_t when, int *tai_offset);
|
||||
static void update_leap_status(NTP_Leap leap, time_t now, int reset);
|
||||
|
||||
/* ================================================== */
|
||||
@@ -157,7 +156,8 @@ handle_slew(struct timespec *raw,
|
||||
double delta;
|
||||
struct timespec now;
|
||||
|
||||
UTI_AdjustTimespec(&our_ref_time, cooked, &our_ref_time, &delta, dfreq, doffset);
|
||||
if (!UTI_IsZeroTimespec(&our_ref_time))
|
||||
UTI_AdjustTimespec(&our_ref_time, cooked, &our_ref_time, &delta, dfreq, doffset);
|
||||
|
||||
if (change_type == LCL_ChangeUnknownStep) {
|
||||
UTI_ZeroTimespec(&last_ref_update);
|
||||
@@ -181,11 +181,13 @@ REF_Initialise(void)
|
||||
FILE *in;
|
||||
double file_freq_ppm, file_skew_ppm;
|
||||
double our_frequency_ppm;
|
||||
int tai_offset;
|
||||
|
||||
mode = REF_ModeNormal;
|
||||
are_we_synchronised = 0;
|
||||
our_leap_status = LEAP_Unsynchronised;
|
||||
our_leap_sec = 0;
|
||||
our_tai_offset = 0;
|
||||
initialised = 1;
|
||||
our_root_dispersion = 1.0;
|
||||
our_root_delay = 1.0;
|
||||
@@ -205,11 +207,11 @@ REF_Initialise(void)
|
||||
our_skew = 1.0e-6 * file_skew_ppm;
|
||||
if (our_skew < MIN_SKEW)
|
||||
our_skew = MIN_SKEW;
|
||||
LOG(LOGS_INFO, LOGF_Reference, "Frequency %.3f +/- %.3f ppm read from %s",
|
||||
LOG(LOGS_INFO, "Frequency %.3f +/- %.3f ppm read from %s",
|
||||
file_freq_ppm, file_skew_ppm, drift_file);
|
||||
LCL_SetAbsoluteFrequency(our_frequency_ppm);
|
||||
} else {
|
||||
LOG(LOGS_WARN, LOGF_Reference, "Could not read valid frequency and skew from driftfile %s",
|
||||
LOG(LOGS_WARN, "Could not read valid frequency and skew from driftfile %s",
|
||||
drift_file);
|
||||
}
|
||||
fclose(in);
|
||||
@@ -219,12 +221,12 @@ REF_Initialise(void)
|
||||
if (our_frequency_ppm == 0.0) {
|
||||
our_frequency_ppm = LCL_ReadAbsoluteFrequency();
|
||||
if (our_frequency_ppm != 0.0) {
|
||||
LOG(LOGS_INFO, LOGF_Reference, "Initial frequency %.3f ppm", our_frequency_ppm);
|
||||
LOG(LOGS_INFO, "Initial frequency %.3f ppm", our_frequency_ppm);
|
||||
}
|
||||
}
|
||||
|
||||
logfileid = CNF_GetLogTracking() ? LOG_FileOpen("tracking",
|
||||
" Date (UTC) Time IP Address St Freq ppm Skew ppm Offset L Co Offset sd Rem. corr.")
|
||||
" Date (UTC) Time IP Address St Freq ppm Skew ppm Offset L Co Offset sd Rem. corr. Root delay Root disp. Max. error")
|
||||
: -1;
|
||||
|
||||
max_update_skew = fabs(CNF_GetMaxUpdateSkew()) * 1.0e-6;
|
||||
@@ -243,11 +245,11 @@ REF_Initialise(void)
|
||||
leap_tzname = CNF_GetLeapSecTimezone();
|
||||
if (leap_tzname) {
|
||||
/* Check that the timezone has good data for Jun 30 2012 and Dec 31 2012 */
|
||||
if (get_tz_leap(1341014400) == LEAP_InsertSecond &&
|
||||
get_tz_leap(1356912000) == LEAP_Normal) {
|
||||
LOG(LOGS_INFO, LOGF_Reference, "Using %s timezone to obtain leap second data", leap_tzname);
|
||||
if (get_tz_leap(1341014400, &tai_offset) == LEAP_InsertSecond && tai_offset == 34 &&
|
||||
get_tz_leap(1356912000, &tai_offset) == LEAP_Normal && tai_offset == 35) {
|
||||
LOG(LOGS_INFO, "Using %s timezone to obtain leap second data", leap_tzname);
|
||||
} else {
|
||||
LOG(LOGS_WARN, LOGF_Reference, "Timezone %s failed leap second check, ignoring", leap_tzname);
|
||||
LOG(LOGS_WARN, "Timezone %s failed leap second check, ignoring", leap_tzname);
|
||||
leap_tzname = NULL;
|
||||
}
|
||||
}
|
||||
@@ -266,6 +268,7 @@ REF_Initialise(void)
|
||||
fb_drift_timeout_id = 0;
|
||||
}
|
||||
|
||||
UTI_ZeroTimespec(&our_ref_time);
|
||||
UTI_ZeroTimespec(&last_ref_update);
|
||||
last_ref_update_interval = 0.0;
|
||||
|
||||
@@ -364,7 +367,7 @@ update_drift_file(double freq_ppm, double skew)
|
||||
out = fopen(temp_drift_file, "w");
|
||||
if (!out) {
|
||||
Free(temp_drift_file);
|
||||
LOG(LOGS_WARN, LOGF_Reference, "Could not open temporary driftfile %s.tmp for writing",
|
||||
LOG(LOGS_WARN, "Could not open temporary driftfile %s.tmp for writing",
|
||||
drift_file);
|
||||
return;
|
||||
}
|
||||
@@ -374,7 +377,7 @@ update_drift_file(double freq_ppm, double skew)
|
||||
r2 = fclose(out);
|
||||
if (r1 < 0 || r2) {
|
||||
Free(temp_drift_file);
|
||||
LOG(LOGS_WARN, LOGF_Reference, "Could not write to temporary driftfile %s.tmp",
|
||||
LOG(LOGS_WARN, "Could not write to temporary driftfile %s.tmp",
|
||||
drift_file);
|
||||
return;
|
||||
}
|
||||
@@ -384,8 +387,7 @@ update_drift_file(double freq_ppm, double skew)
|
||||
if (!stat(drift_file,&buf)) {
|
||||
if (chown(temp_drift_file,buf.st_uid,buf.st_gid) ||
|
||||
chmod(temp_drift_file,buf.st_mode & 0777)) {
|
||||
LOG(LOGS_WARN, LOGF_Reference,
|
||||
"Could not change ownership or permissions of temporary driftfile %s.tmp",
|
||||
LOG(LOGS_WARN, "Could not change ownership or permissions of temporary driftfile %s.tmp",
|
||||
drift_file);
|
||||
}
|
||||
}
|
||||
@@ -395,7 +397,7 @@ update_drift_file(double freq_ppm, double skew)
|
||||
if (rename(temp_drift_file,drift_file)) {
|
||||
unlink(temp_drift_file);
|
||||
Free(temp_drift_file);
|
||||
LOG(LOGS_WARN, LOGF_Reference, "Could not replace old driftfile %s with new one %s.tmp",
|
||||
LOG(LOGS_WARN, "Could not replace old driftfile %s with new one %s.tmp",
|
||||
drift_file,drift_file);
|
||||
return;
|
||||
}
|
||||
@@ -443,8 +445,8 @@ update_fb_drifts(double freq_ppm, double update_interval)
|
||||
(freq_ppm - fb_drifts[i].freq);
|
||||
}
|
||||
|
||||
DEBUG_LOG(LOGF_Reference, "Fallback drift %d updated: %f ppm %f seconds",
|
||||
i + fb_drift_min, fb_drifts[i].freq, fb_drifts[i].secs);
|
||||
DEBUG_LOG("Fallback drift %d updated: %f ppm %f seconds",
|
||||
i + fb_drift_min, fb_drifts[i].freq, fb_drifts[i].secs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -457,7 +459,7 @@ fb_drift_timeout(void *arg)
|
||||
|
||||
fb_drift_timeout_id = 0;
|
||||
|
||||
DEBUG_LOG(LOGF_Reference, "Fallback drift %d active: %f ppm",
|
||||
DEBUG_LOG("Fallback drift %d active: %f ppm",
|
||||
next_fb_drift, fb_drifts[next_fb_drift - fb_drift_min].freq);
|
||||
LCL_SetAbsoluteFrequency(fb_drifts[next_fb_drift - fb_drift_min].freq);
|
||||
REF_SetUnsynchronised();
|
||||
@@ -492,14 +494,14 @@ schedule_fb_drift(struct timespec *now)
|
||||
if (c > next_fb_drift) {
|
||||
LCL_SetAbsoluteFrequency(fb_drifts[c - fb_drift_min].freq);
|
||||
next_fb_drift = c;
|
||||
DEBUG_LOG(LOGF_Reference, "Fallback drift %d set", c);
|
||||
DEBUG_LOG("Fallback drift %d set", c);
|
||||
}
|
||||
|
||||
if (i <= fb_drift_max) {
|
||||
next_fb_drift = i;
|
||||
UTI_AddDoubleToTimespec(now, secs - unsynchronised, &when);
|
||||
fb_drift_timeout_id = SCH_AddTimeout(&when, fb_drift_timeout, NULL);
|
||||
DEBUG_LOG(LOGF_Reference, "Fallback drift %d scheduled", i);
|
||||
DEBUG_LOG("Fallback drift %d scheduled", i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,8 +533,7 @@ maybe_log_offset(double offset, time_t now)
|
||||
abs_offset = fabs(offset);
|
||||
|
||||
if (abs_offset > log_change_threshold) {
|
||||
LOG(LOGS_WARN, LOGF_Reference,
|
||||
"System clock wrong by %.6f seconds, adjustment started",
|
||||
LOG(LOGS_WARN, "System clock wrong by %.6f seconds, adjustment started",
|
||||
-offset);
|
||||
}
|
||||
|
||||
@@ -558,8 +559,7 @@ maybe_log_offset(double offset, time_t now)
|
||||
-offset, mail_change_threshold);
|
||||
pclose(p);
|
||||
} else {
|
||||
LOG(LOGS_ERR, LOGF_Reference,
|
||||
"Could not send mail notification to user %s\n",
|
||||
LOG(LOGS_ERR, "Could not send mail notification to user %s\n",
|
||||
mail_change_user);
|
||||
}
|
||||
}
|
||||
@@ -594,7 +594,7 @@ is_offset_ok(double offset)
|
||||
|
||||
offset = fabs(offset);
|
||||
if (offset > max_offset) {
|
||||
LOG(LOGS_WARN, LOGF_Reference,
|
||||
LOG(LOGS_WARN,
|
||||
"Adjustment of %.3f seconds exceeds the allowed maximum of %.3f seconds (%s) ",
|
||||
-offset, max_offset, !max_offset_ignore ? "exiting" : "ignored");
|
||||
if (!max_offset_ignore)
|
||||
@@ -609,7 +609,14 @@ is_offset_ok(double offset)
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
is_leap_second_day(struct tm *stm) {
|
||||
is_leap_second_day(time_t when)
|
||||
{
|
||||
struct tm *stm;
|
||||
|
||||
stm = gmtime(&when);
|
||||
if (!stm)
|
||||
return 0;
|
||||
|
||||
/* Allow leap second only on the last day of June and December */
|
||||
return (stm->tm_mon == 5 && stm->tm_mday == 30) ||
|
||||
(stm->tm_mon == 11 && stm->tm_mday == 31);
|
||||
@@ -618,12 +625,18 @@ is_leap_second_day(struct tm *stm) {
|
||||
/* ================================================== */
|
||||
|
||||
static NTP_Leap
|
||||
get_tz_leap(time_t when)
|
||||
get_tz_leap(time_t when, int *tai_offset)
|
||||
{
|
||||
struct tm stm;
|
||||
static time_t last_tz_leap_check;
|
||||
static NTP_Leap tz_leap;
|
||||
static int tz_tai_offset;
|
||||
|
||||
struct tm stm, *tm;
|
||||
time_t t;
|
||||
char *tz_env, tz_orig[128];
|
||||
|
||||
*tai_offset = tz_tai_offset;
|
||||
|
||||
/* Do this check at most twice a day */
|
||||
when = when / (12 * 3600) * (12 * 3600);
|
||||
if (last_tz_leap_check == when)
|
||||
@@ -631,12 +644,14 @@ get_tz_leap(time_t when)
|
||||
|
||||
last_tz_leap_check = when;
|
||||
tz_leap = LEAP_Normal;
|
||||
tz_tai_offset = 0;
|
||||
|
||||
stm = *gmtime(&when);
|
||||
|
||||
if (!is_leap_second_day(&stm))
|
||||
tm = gmtime(&when);
|
||||
if (!tm)
|
||||
return tz_leap;
|
||||
|
||||
stm = *tm;
|
||||
|
||||
/* Temporarily switch to the timezone containing leap seconds */
|
||||
tz_env = getenv("TZ");
|
||||
if (tz_env) {
|
||||
@@ -647,6 +662,11 @@ get_tz_leap(time_t when)
|
||||
setenv("TZ", leap_tzname, 1);
|
||||
tzset();
|
||||
|
||||
/* Get the TAI-UTC offset, which started at the epoch at 10 seconds */
|
||||
t = mktime(&stm);
|
||||
if (t != -1)
|
||||
tz_tai_offset = t - when + 10;
|
||||
|
||||
/* Set the time to 23:59:60 and see how it overflows in mktime() */
|
||||
stm.tm_sec = 60;
|
||||
stm.tm_min = 59;
|
||||
@@ -668,6 +688,8 @@ get_tz_leap(time_t when)
|
||||
else if (stm.tm_sec == 1)
|
||||
tz_leap = LEAP_DeleteSecond;
|
||||
|
||||
*tai_offset = tz_tai_offset;
|
||||
|
||||
return tz_leap;
|
||||
}
|
||||
|
||||
@@ -678,10 +700,13 @@ leap_end_timeout(void *arg)
|
||||
{
|
||||
leap_timeout_id = 0;
|
||||
leap_in_progress = 0;
|
||||
|
||||
if (our_tai_offset)
|
||||
our_tai_offset += our_leap_sec;
|
||||
our_leap_sec = 0;
|
||||
|
||||
if (leap_mode == REF_LeapModeSystem)
|
||||
LCL_SetSystemLeap(0);
|
||||
LCL_SetSystemLeap(our_leap_sec, our_tai_offset);
|
||||
|
||||
if (our_leap_status == LEAP_InsertSecond ||
|
||||
our_leap_status == LEAP_DeleteSecond)
|
||||
@@ -697,20 +722,20 @@ leap_start_timeout(void *arg)
|
||||
|
||||
switch (leap_mode) {
|
||||
case REF_LeapModeSystem:
|
||||
DEBUG_LOG(LOGF_Reference, "Waiting for system clock leap second correction");
|
||||
DEBUG_LOG("Waiting for system clock leap second correction");
|
||||
break;
|
||||
case REF_LeapModeSlew:
|
||||
LCL_NotifyLeap(our_leap_sec);
|
||||
LCL_AccumulateOffset(our_leap_sec, 0.0);
|
||||
LOG(LOGS_WARN, LOGF_Reference, "Adjusting system clock for leap second");
|
||||
LOG(LOGS_WARN, "Adjusting system clock for leap second");
|
||||
break;
|
||||
case REF_LeapModeStep:
|
||||
LCL_NotifyLeap(our_leap_sec);
|
||||
LCL_ApplyStepOffset(our_leap_sec);
|
||||
LOG(LOGS_WARN, LOGF_Reference, "System clock was stepped for leap second");
|
||||
LOG(LOGS_WARN, "System clock was stepped for leap second");
|
||||
break;
|
||||
case REF_LeapModeIgnore:
|
||||
LOG(LOGS_WARN, LOGF_Reference, "Ignoring leap second");
|
||||
LOG(LOGS_WARN, "Ignoring leap second");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -755,17 +780,22 @@ set_leap_timeout(time_t now)
|
||||
static void
|
||||
update_leap_status(NTP_Leap leap, time_t now, int reset)
|
||||
{
|
||||
int leap_sec;
|
||||
NTP_Leap tz_leap;
|
||||
int leap_sec, tai_offset;
|
||||
|
||||
leap_sec = 0;
|
||||
tai_offset = 0;
|
||||
|
||||
if (leap_tzname && now && leap == LEAP_Normal)
|
||||
leap = get_tz_leap(now);
|
||||
if (leap_tzname && now) {
|
||||
tz_leap = get_tz_leap(now, &tai_offset);
|
||||
if (leap == LEAP_Normal)
|
||||
leap = tz_leap;
|
||||
}
|
||||
|
||||
if (leap == LEAP_InsertSecond || leap == LEAP_DeleteSecond) {
|
||||
/* Check that leap second is allowed today */
|
||||
|
||||
if (is_leap_second_day(gmtime(&now))) {
|
||||
if (is_leap_second_day(now)) {
|
||||
if (leap == LEAP_InsertSecond) {
|
||||
leap_sec = 1;
|
||||
} else {
|
||||
@@ -776,12 +806,14 @@ update_leap_status(NTP_Leap leap, time_t now, int reset)
|
||||
}
|
||||
}
|
||||
|
||||
if (leap_sec != our_leap_sec && !REF_IsLeapSecondClose()) {
|
||||
if ((leap_sec != our_leap_sec || tai_offset != our_tai_offset)
|
||||
&& !REF_IsLeapSecondClose()) {
|
||||
our_leap_sec = leap_sec;
|
||||
our_tai_offset = tai_offset;
|
||||
|
||||
switch (leap_mode) {
|
||||
case REF_LeapModeSystem:
|
||||
LCL_SetSystemLeap(our_leap_sec);
|
||||
LCL_SetSystemLeap(our_leap_sec, our_tai_offset);
|
||||
/* Fall through */
|
||||
case REF_LeapModeSlew:
|
||||
case REF_LeapModeStep:
|
||||
@@ -801,18 +833,43 @@ update_leap_status(NTP_Leap leap, time_t now, int reset)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static double
|
||||
get_root_dispersion(struct timespec *ts)
|
||||
{
|
||||
if (UTI_IsZeroTimespec(&our_ref_time))
|
||||
return 1.0;
|
||||
|
||||
return our_root_dispersion +
|
||||
fabs(UTI_DiffTimespecsToDouble(ts, &our_ref_time)) *
|
||||
(our_skew + fabs(our_residual_freq) + LCL_GetMaxClockError());
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
write_log(struct timespec *ref_time, char *ref, int stratum, NTP_Leap leap,
|
||||
double freq, double skew, double offset, int combined_sources,
|
||||
double offset_sd, double uncorrected_offset)
|
||||
write_log(struct timespec *now, int combined_sources, double freq,
|
||||
double offset, double offset_sd, double uncorrected_offset,
|
||||
double orig_root_distance)
|
||||
{
|
||||
const char leap_codes[4] = {'N', '+', '-', '?'};
|
||||
if (logfileid != -1) {
|
||||
LOG_FileWrite(logfileid, "%s %-15s %2d %10.3f %10.3f %10.3e %1c %2d %10.3e %10.3e",
|
||||
UTI_TimeToLogForm(ref_time->tv_sec), ref, stratum, freq, skew,
|
||||
offset, leap_codes[leap], combined_sources, offset_sd,
|
||||
uncorrected_offset);
|
||||
}
|
||||
double root_dispersion, max_error;
|
||||
static double last_sys_offset = 0.0;
|
||||
|
||||
if (logfileid == -1)
|
||||
return;
|
||||
|
||||
max_error = orig_root_distance + fabs(last_sys_offset);
|
||||
root_dispersion = get_root_dispersion(now);
|
||||
last_sys_offset = offset - uncorrected_offset;
|
||||
|
||||
LOG_FileWrite(logfileid,
|
||||
"%s %-15s %2d %10.3f %10.3f %10.3e %1c %2d %10.3e %10.3e %10.3e %10.3e %10.3e",
|
||||
UTI_TimeToLogForm(now->tv_sec),
|
||||
our_ref_ip.family != IPADDR_UNSPEC ?
|
||||
UTI_IPToString(&our_ref_ip) : UTI_RefidToString(our_ref_id),
|
||||
our_stratum, freq, 1.0e6 * our_skew, offset,
|
||||
leap_codes[our_leap_status], combined_sources, offset_sd,
|
||||
uncorrected_offset, our_root_delay, root_dispersion, max_error);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -825,15 +882,14 @@ special_mode_sync(int valid, double offset)
|
||||
switch (mode) {
|
||||
case REF_ModeInitStepSlew:
|
||||
if (!valid) {
|
||||
LOG(LOGS_WARN, LOGF_Reference, "No suitable source for initstepslew");
|
||||
LOG(LOGS_WARN, "No suitable source for initstepslew");
|
||||
end_ref_mode(0);
|
||||
break;
|
||||
}
|
||||
|
||||
step = fabs(offset) >= CNF_GetInitStepThreshold();
|
||||
|
||||
LOG(LOGS_INFO, LOGF_Reference,
|
||||
"System's initial offset : %.6f seconds %s of true (%s)",
|
||||
LOG(LOGS_INFO, "System's initial offset : %.6f seconds %s of true (%s)",
|
||||
fabs(offset), offset >= 0 ? "fast" : "slow", step ? "step" : "slew");
|
||||
|
||||
if (step)
|
||||
@@ -847,14 +903,14 @@ special_mode_sync(int valid, double offset)
|
||||
case REF_ModeUpdateOnce:
|
||||
case REF_ModePrintOnce:
|
||||
if (!valid) {
|
||||
LOG(LOGS_WARN, LOGF_Reference, "No suitable source for synchronisation");
|
||||
LOG(LOGS_WARN, "No suitable source for synchronisation");
|
||||
end_ref_mode(0);
|
||||
break;
|
||||
}
|
||||
|
||||
step = mode == REF_ModeUpdateOnce;
|
||||
|
||||
LOG(LOGS_INFO, LOGF_Reference, "System clock wrong by %.6f seconds (%s)",
|
||||
LOG(LOGS_INFO, "System clock wrong by %.6f seconds (%s)",
|
||||
-offset, step ? "step" : "ignored");
|
||||
|
||||
if (step)
|
||||
@@ -897,8 +953,7 @@ REF_SetReference(int stratum,
|
||||
double our_frequency;
|
||||
double abs_freq_ppm;
|
||||
double update_interval;
|
||||
double elapsed;
|
||||
double correction_rate;
|
||||
double elapsed, correction_rate, orig_root_distance;
|
||||
double uncorrected_offset, accumulate_offset, step_offset;
|
||||
struct timespec now, raw_now;
|
||||
NTP_int64 ref_fuzz;
|
||||
@@ -911,28 +966,10 @@ REF_SetReference(int stratum,
|
||||
return;
|
||||
}
|
||||
|
||||
/* Guard against dividing by zero */
|
||||
if (skew < MIN_SKEW)
|
||||
/* Guard against dividing by zero and NaN */
|
||||
if (!(skew > MIN_SKEW))
|
||||
skew = MIN_SKEW;
|
||||
|
||||
/* If we get a serious rounding error in the source stats regression
|
||||
processing, there is a remote chance that the skew argument is a
|
||||
'not a number'. If such a quantity gets propagated into the
|
||||
machine's kernel clock variables, nasty things will happen ..
|
||||
|
||||
To guard against this we need to check whether the skew argument
|
||||
is a reasonable real number. I don't think isnan, isinf etc are
|
||||
platform independent, so the following algorithm is used. */
|
||||
|
||||
{
|
||||
double t;
|
||||
t = (skew + skew) / skew; /* Skew shouldn't be zero either */
|
||||
if ((t < 1.9) || (t > 2.1)) {
|
||||
LOG(LOGS_WARN, LOGF_Reference, "Bogus skew value encountered");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LCL_ReadRawTime(&raw_now);
|
||||
LCL_GetOffsetCorrection(&raw_now, &uncorrected_offset, NULL);
|
||||
UTI_AddDoubleToTimespec(&raw_now, uncorrected_offset, &now);
|
||||
@@ -943,6 +980,8 @@ REF_SetReference(int stratum,
|
||||
if (!is_offset_ok(our_offset))
|
||||
return;
|
||||
|
||||
orig_root_distance = our_root_delay / 2.0 + get_root_dispersion(&now);
|
||||
|
||||
are_we_synchronised = leap != LEAP_Unsynchronised ? 1 : 0;
|
||||
our_stratum = stratum + 1;
|
||||
our_ref_id = ref_id;
|
||||
@@ -1025,7 +1064,7 @@ REF_SetReference(int stratum,
|
||||
LCL_AccumulateFrequencyAndOffset(our_frequency, accumulate_offset, correction_rate);
|
||||
|
||||
} else {
|
||||
DEBUG_LOG(LOGF_Reference, "Skew %f too large to track, offset=%f", skew, accumulate_offset);
|
||||
DEBUG_LOG("Skew %f too large to track, offset=%f", skew, accumulate_offset);
|
||||
|
||||
LCL_AccumulateOffset(accumulate_offset, correction_rate);
|
||||
|
||||
@@ -1037,7 +1076,7 @@ REF_SetReference(int stratum,
|
||||
|
||||
if (step_offset != 0.0) {
|
||||
if (LCL_ApplyStepOffset(step_offset))
|
||||
LOG(LOGS_WARN, LOGF_Reference, "System clock was stepped by %.6f seconds", -step_offset);
|
||||
LOG(LOGS_WARN, "System clock was stepped by %.6f seconds", -step_offset);
|
||||
}
|
||||
|
||||
LCL_SetSyncStatus(are_we_synchronised, offset_sd, offset_sd + root_delay / 2.0 + root_dispersion);
|
||||
@@ -1053,16 +1092,8 @@ REF_SetReference(int stratum,
|
||||
|
||||
abs_freq_ppm = LCL_ReadAbsoluteFrequency();
|
||||
|
||||
write_log(&now,
|
||||
our_ref_ip.family != IPADDR_UNSPEC ? UTI_IPToString(&our_ref_ip) : UTI_RefidToString(our_ref_id),
|
||||
our_stratum,
|
||||
our_leap_status,
|
||||
abs_freq_ppm,
|
||||
1.0e6*our_skew,
|
||||
our_offset,
|
||||
combined_sources,
|
||||
offset_sd,
|
||||
uncorrected_offset);
|
||||
write_log(&now, combined_sources, abs_freq_ppm, our_offset, offset_sd,
|
||||
uncorrected_offset, orig_root_distance);
|
||||
|
||||
if (drift_file) {
|
||||
/* Update drift file at most once per hour */
|
||||
@@ -1074,7 +1105,7 @@ REF_SetReference(int stratum,
|
||||
}
|
||||
|
||||
/* Update fallback drifts */
|
||||
if (fb_drifts) {
|
||||
if (fb_drifts && are_we_synchronised) {
|
||||
update_fb_drifts(abs_freq_ppm, update_interval);
|
||||
schedule_fb_drift(&now);
|
||||
}
|
||||
@@ -1136,20 +1167,15 @@ REF_SetUnsynchronised(void)
|
||||
}
|
||||
|
||||
update_leap_status(LEAP_Unsynchronised, 0, 0);
|
||||
our_ref_ip.family = IPADDR_INET4;
|
||||
our_ref_ip.addr.in4 = 0;
|
||||
our_stratum = 0;
|
||||
are_we_synchronised = 0;
|
||||
|
||||
LCL_SetSyncStatus(0, 0.0, 0.0);
|
||||
|
||||
write_log(&now,
|
||||
"0.0.0.0",
|
||||
0,
|
||||
our_leap_status,
|
||||
LCL_ReadAbsoluteFrequency(),
|
||||
1.0e6*our_skew,
|
||||
0.0,
|
||||
0,
|
||||
0.0,
|
||||
uncorrected_offset);
|
||||
write_log(&now, 0, LCL_ReadAbsoluteFrequency(), 0.0, 0.0, uncorrected_offset,
|
||||
our_root_delay / 2.0 + get_root_dispersion(&now));
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1167,14 +1193,12 @@ REF_GetReferenceParams
|
||||
double *root_dispersion
|
||||
)
|
||||
{
|
||||
double elapsed, dispersion;
|
||||
double dispersion;
|
||||
|
||||
assert(initialised);
|
||||
|
||||
if (are_we_synchronised) {
|
||||
elapsed = UTI_DiffTimespecsToDouble(local_time, &our_ref_time);
|
||||
dispersion = our_root_dispersion +
|
||||
(our_skew + fabs(our_residual_freq) + LCL_GetMaxClockError()) * elapsed;
|
||||
dispersion = get_root_dispersion(local_time);
|
||||
} else {
|
||||
dispersion = 0.0;
|
||||
}
|
||||
@@ -1214,7 +1238,7 @@ REF_GetReferenceParams
|
||||
*leap_status = LEAP_Normal;
|
||||
|
||||
*root_delay = 0.0;
|
||||
*root_dispersion = LCL_GetSysPrecisionAsQuantum();
|
||||
*root_dispersion = 0.0;
|
||||
|
||||
} else {
|
||||
|
||||
@@ -1332,6 +1356,18 @@ int REF_IsLeapSecondClose(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
REF_GetTaiOffset(struct timespec *ts)
|
||||
{
|
||||
int tai_offset;
|
||||
|
||||
get_tz_leap(ts->tv_sec, &tai_offset);
|
||||
|
||||
return tai_offset;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
REF_GetTrackingReport(RPT_TrackingReport *rep)
|
||||
{
|
||||
@@ -1348,7 +1384,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;
|
||||
|
||||
@@ -184,6 +184,9 @@ extern void REF_DisableLocal(void);
|
||||
and is better to discard any measurements */
|
||||
extern int REF_IsLeapSecondClose(void);
|
||||
|
||||
/* Return TAI-UTC offset corresponding to a time in UTC if available */
|
||||
extern int REF_GetTaiOffset(struct timespec *ts);
|
||||
|
||||
extern void REF_GetTrackingReport(RPT_TrackingReport *rep);
|
||||
|
||||
#endif /* GOT_REFERENCE_H */
|
||||
|
||||
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-2017
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "logging.h"
|
||||
#include "util.h"
|
||||
|
||||
#define MAX_POINTS 128
|
||||
#define MAX_POINTS 64
|
||||
|
||||
void
|
||||
RGR_WeightedRegression
|
||||
@@ -285,7 +285,7 @@ RGR_FindBestRegression
|
||||
n - start <= min_samples) {
|
||||
if (start != resid_start) {
|
||||
/* Ignore extra samples in returned nruns */
|
||||
nruns = n_runs_from_residuals(resid - resid_start + start, n - start);
|
||||
nruns = n_runs_from_residuals(resid + (start - resid_start), n - start);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
@@ -340,7 +340,7 @@ RGR_FindBestRegression
|
||||
0-521-43108-5). */
|
||||
|
||||
static double
|
||||
find_ordered_entry_with_flags(double *x, int n, int index, int *flags)
|
||||
find_ordered_entry_with_flags(double *x, int n, int index, char *flags)
|
||||
{
|
||||
int u, v, l, r;
|
||||
double temp;
|
||||
@@ -403,9 +403,9 @@ find_ordered_entry_with_flags(double *x, int n, int index, int *flags)
|
||||
static double
|
||||
find_ordered_entry(double *x, int n, int index)
|
||||
{
|
||||
int flags[MAX_POINTS];
|
||||
char flags[MAX_POINTS];
|
||||
|
||||
memset(flags, 0, n * sizeof(int));
|
||||
memset(flags, 0, n * sizeof (flags[0]));
|
||||
return find_ordered_entry_with_flags(x, n, index, flags);
|
||||
}
|
||||
#endif
|
||||
@@ -417,9 +417,9 @@ static double
|
||||
find_median(double *x, int n)
|
||||
{
|
||||
int k;
|
||||
int flags[MAX_POINTS];
|
||||
char flags[MAX_POINTS];
|
||||
|
||||
memset(flags, 0, n*sizeof(int));
|
||||
memset(flags, 0, n * sizeof (flags[0]));
|
||||
k = n>>1;
|
||||
if (n&1) {
|
||||
return find_ordered_entry_with_flags(x, n, k, flags);
|
||||
@@ -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
|
||||
|
||||
25
sched.c
25
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) {
|
||||
@@ -219,13 +219,16 @@ SCH_RemoveFileHandler(int fd)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SCH_SetFileHandlerEvents(int fd, int events)
|
||||
SCH_SetFileHandlerEvent(int fd, int event, int enable)
|
||||
{
|
||||
FileHandlerEntry *ptr;
|
||||
|
||||
assert(events);
|
||||
ptr = ARR_GetElement(file_handlers, fd);
|
||||
ptr->events = events;
|
||||
|
||||
if (enable)
|
||||
ptr->events |= event;
|
||||
else
|
||||
ptr->events &= ~event;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -350,7 +353,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 +515,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 +683,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 +745,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 +765,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 */
|
||||
|
||||
5
sched.h
5
sched.h
@@ -34,7 +34,8 @@ typedef unsigned int SCH_TimeoutID;
|
||||
|
||||
typedef enum {
|
||||
SCH_ReservedTimeoutValue = 0,
|
||||
SCH_NtpSamplingClass,
|
||||
SCH_NtpClientClass,
|
||||
SCH_NtpPeerClass,
|
||||
SCH_NtpBroadcastClass,
|
||||
SCH_NumberOfClasses /* needs to be last */
|
||||
} SCH_TimeoutClass;
|
||||
@@ -59,7 +60,7 @@ extern void SCH_Finalise(void);
|
||||
/* Register a handler for when select goes true on a file descriptor */
|
||||
extern void SCH_AddFileHandler(int fd, int events, SCH_FileHandler handler, SCH_ArbitraryArgument arg);
|
||||
extern void SCH_RemoveFileHandler(int fd);
|
||||
extern void SCH_SetFileHandlerEvents(int fd, int events);
|
||||
extern void SCH_SetFileHandlerEvent(int fd, int event, int enable);
|
||||
|
||||
/* Get the time stamp taken after a file descriptor became ready or a timeout expired */
|
||||
extern void SCH_GetLastEventTime(struct timespec *cooked, double *err, struct timespec *raw);
|
||||
|
||||
11
smooth.c
11
smooth.c
@@ -208,7 +208,7 @@ update_stages(void)
|
||||
stages[2].length = l3;
|
||||
|
||||
for (i = 0; i < NUM_STAGES; i++) {
|
||||
DEBUG_LOG(LOGF_Smooth, "Smooth stage %d wander %e length %f",
|
||||
DEBUG_LOG("Smooth stage %d wander %e length %f",
|
||||
i + 1, stages[i].wander, stages[i].length);
|
||||
}
|
||||
}
|
||||
@@ -230,7 +230,7 @@ update_smoothing(struct timespec *now, double offset, double freq)
|
||||
|
||||
update_stages();
|
||||
|
||||
DEBUG_LOG(LOGF_Smooth, "Smooth offset %e freq %e", smooth_offset, smooth_freq);
|
||||
DEBUG_LOG("Smooth offset %e freq %e", smooth_offset, smooth_freq);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -246,7 +246,8 @@ handle_slew(struct timespec *raw, struct timespec *cooked, double dfreq,
|
||||
update_smoothing(cooked, doffset, dfreq);
|
||||
}
|
||||
|
||||
UTI_AdjustTimespec(&last_update, cooked, &last_update, &delta, dfreq, doffset);
|
||||
if (!UTI_IsZeroTimespec(&last_update))
|
||||
UTI_AdjustTimespec(&last_update, cooked, &last_update, &delta, dfreq, doffset);
|
||||
}
|
||||
|
||||
void SMT_Initialise(void)
|
||||
@@ -264,6 +265,8 @@ void SMT_Initialise(void)
|
||||
max_freq *= 1e-6;
|
||||
max_wander *= 1e-6;
|
||||
|
||||
UTI_ZeroTimespec(&last_update);
|
||||
|
||||
LCL_AddParameterChangeHandler(handle_slew, NULL);
|
||||
}
|
||||
|
||||
@@ -295,7 +298,7 @@ SMT_Activate(struct timespec *now)
|
||||
if (!enabled || !locked)
|
||||
return;
|
||||
|
||||
LOG(LOGS_INFO, LOGF_Smooth, "Time smoothing activated%s", leap_only_mode ?
|
||||
LOG(LOGS_INFO, "Time smoothing activated%s", leap_only_mode ?
|
||||
" (leap seconds only)" : "");
|
||||
locked = 0;
|
||||
last_update = *now;
|
||||
|
||||
57
sources.c
57
sources.c
@@ -213,7 +213,9 @@ void SRC_Finalise(void)
|
||||
/* Function to create a new instance. This would be called by one of
|
||||
the individual source-type instance creation routines. */
|
||||
|
||||
SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_options, IPAddr *addr, int min_samples, int max_samples)
|
||||
SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_options,
|
||||
IPAddr *addr, int min_samples, int max_samples,
|
||||
double min_delay, double asymmetry)
|
||||
{
|
||||
SRC_Instance result;
|
||||
|
||||
@@ -225,7 +227,8 @@ SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_optio
|
||||
max_samples = CNF_GetMaxSamples();
|
||||
|
||||
result = MallocNew(struct SRC_Instance_Record);
|
||||
result->stats = SST_CreateInstance(ref_id, addr, min_samples, max_samples);
|
||||
result->stats = SST_CreateInstance(ref_id, addr, min_samples, max_samples,
|
||||
min_delay, asymmetry);
|
||||
|
||||
if (n_sources == max_n_sources) {
|
||||
/* Reallocate memory */
|
||||
@@ -348,12 +351,12 @@ void SRC_AccumulateSample
|
||||
|
||||
inst->leap_status = leap_status;
|
||||
|
||||
DEBUG_LOG(LOGF_Sources, "ip=[%s] t=%s ofs=%f del=%f disp=%f str=%d",
|
||||
DEBUG_LOG("ip=[%s] t=%s ofs=%f del=%f disp=%f str=%d",
|
||||
source_to_string(inst), UTI_TimespecToString(sample_time), -offset,
|
||||
root_delay, root_dispersion, stratum);
|
||||
|
||||
if (REF_IsLeapSecondClose()) {
|
||||
LOG(LOGS_INFO, LOGF_Sources, "Dropping sample around leap second");
|
||||
LOG(LOGS_INFO, "Dropping sample around leap second");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -425,10 +428,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 +454,7 @@ log_selection_message(char *format, char *arg)
|
||||
{
|
||||
if (REF_GetMode() != REF_ModeNormal)
|
||||
return;
|
||||
LOG(LOGS_INFO, LOGF_Sources, format, arg);
|
||||
LOG(LOGS_INFO, format, arg);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -562,7 +566,7 @@ combine_sources(int n_sel_sources, struct timespec *ref_time, double *offset,
|
||||
offset_weight = 1.0 / sources[index]->sel_info.root_distance;
|
||||
frequency_weight = 1.0 / src_skew;
|
||||
|
||||
DEBUG_LOG(LOGF_Sources, "combining index=%d oweight=%e offset=%e sd=%e fweight=%e freq=%e skew=%e",
|
||||
DEBUG_LOG("combining index=%d oweight=%e offset=%e sd=%e fweight=%e freq=%e skew=%e",
|
||||
index, offset_weight, src_offset, src_offset_sd, frequency_weight, src_frequency, src_skew);
|
||||
|
||||
sum_offset_weight += offset_weight;
|
||||
@@ -583,7 +587,7 @@ combine_sources(int n_sel_sources, struct timespec *ref_time, double *offset,
|
||||
*frequency = sum_frequency / sum_frequency_weight;
|
||||
*skew = 1.0 / sqrt(inv_sum2_skew);
|
||||
|
||||
DEBUG_LOG(LOGF_Sources, "combined result offset=%e sd=%e freq=%e skew=%e",
|
||||
DEBUG_LOG("combined result offset=%e sd=%e freq=%e skew=%e",
|
||||
*offset, *offset_sd, *frequency, *skew);
|
||||
|
||||
return combined;
|
||||
@@ -661,6 +665,16 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Include extra dispersion in the root distance of sources that don't
|
||||
have new samples (the last sample is older than span of all samples) */
|
||||
if (first_sample_ago < 2.0 * si->last_sample_ago) {
|
||||
double extra_disp = LCL_GetMaxClockError() *
|
||||
(2.0 * si->last_sample_ago - first_sample_ago);
|
||||
si->root_distance += extra_disp;
|
||||
si->lo_limit -= extra_disp;
|
||||
si->hi_limit += extra_disp;
|
||||
}
|
||||
|
||||
/* Require the root distance to be below the allowed maximum */
|
||||
if (si->root_distance > max_distance) {
|
||||
sources[i]->status = SRC_BAD_DISTANCE;
|
||||
@@ -735,12 +749,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 +777,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 +1015,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 +1039,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 +1110,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 +1165,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 +1176,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 +1219,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 +1260,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]);
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,9 @@ typedef enum {
|
||||
/* Function to create a new instance. This would be called by one of
|
||||
the individual source-type instance creation routines. */
|
||||
|
||||
extern SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_options, IPAddr *addr, int min_samples, int max_samples);
|
||||
extern SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_options,
|
||||
IPAddr *addr, int min_samples, int max_samples,
|
||||
double min_delay, double asymmetry);
|
||||
|
||||
/* Function to get rid of a source when it is being unconfigured.
|
||||
This may cause the current reference source to be reselected, if this
|
||||
|
||||
179
sourcestats.c
179
sourcestats.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2011-2014
|
||||
* Copyright (C) Miroslav Lichvar 2011-2014, 2016-2017
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -51,8 +51,8 @@
|
||||
#define MIN_SKEW 1.0e-12
|
||||
#define MAX_SKEW 1.0e+02
|
||||
|
||||
/* The minimum assumed std dev for weighting */
|
||||
#define MIN_WEIGHT_SD 1.0e-9
|
||||
/* The minimum standard deviation */
|
||||
#define MIN_STDDEV 1.0e-9
|
||||
|
||||
/* The asymmetry of network jitter when all jitter is in one direction */
|
||||
#define MAX_ASYMMETRY 0.5
|
||||
@@ -85,6 +85,12 @@ struct SST_Stats_Record {
|
||||
int min_samples;
|
||||
int max_samples;
|
||||
|
||||
/* User defined minimum delay */
|
||||
double fixed_min_delay;
|
||||
|
||||
/* User defined asymmetry of network jitter */
|
||||
double fixed_asymmetry;
|
||||
|
||||
/* Number of samples currently stored. The samples are stored in circular
|
||||
buffer. */
|
||||
int n_samples;
|
||||
@@ -200,13 +206,16 @@ SST_Finalise(void)
|
||||
/* This function creates a new instance of the statistics handler */
|
||||
|
||||
SST_Stats
|
||||
SST_CreateInstance(uint32_t refid, IPAddr *addr, int min_samples, int max_samples)
|
||||
SST_CreateInstance(uint32_t refid, IPAddr *addr, int min_samples, int max_samples,
|
||||
double min_delay, double asymmetry)
|
||||
{
|
||||
SST_Stats inst;
|
||||
inst = MallocNew(struct SST_Stats_Record);
|
||||
|
||||
inst->min_samples = min_samples;
|
||||
inst->max_samples = max_samples;
|
||||
inst->fixed_min_delay = min_delay;
|
||||
inst->fixed_asymmetry = asymmetry;
|
||||
|
||||
SST_SetRefid(inst, refid, addr);
|
||||
SST_ResetInstance(inst);
|
||||
@@ -295,7 +304,7 @@ SST_AccumulateSample(SST_Stats inst, struct timespec *sample_time,
|
||||
/* Make sure it's newer than the last sample */
|
||||
if (inst->n_samples &&
|
||||
UTI_CompareTimespecs(&inst->sample_times[inst->last_sample], sample_time) >= 0) {
|
||||
LOG(LOGS_WARN, LOGF_SourceStats, "Out of order sample detected, discarding history for %s",
|
||||
LOG(LOGS_WARN, "Out of order sample detected, discarding history for %s",
|
||||
inst->ip_addr ? UTI_IPToString(inst->ip_addr) : UTI_RefidToString(inst->refid));
|
||||
SST_ResetInstance(inst);
|
||||
}
|
||||
@@ -313,6 +322,9 @@ SST_AccumulateSample(SST_Stats inst, struct timespec *sample_time,
|
||||
inst->root_dispersions[m] = root_dispersion;
|
||||
inst->strata[m] = stratum;
|
||||
|
||||
if (inst->peer_delays[n] < inst->fixed_min_delay)
|
||||
inst->peer_delays[n] = 2.0 * inst->fixed_min_delay - inst->peer_delays[n];
|
||||
|
||||
if (!inst->n_samples || inst->peer_delays[n] < inst->peer_delays[inst->min_delay_sample])
|
||||
inst->min_delay_sample = n;
|
||||
|
||||
@@ -418,45 +430,63 @@ find_min_delay_sample(SST_Stats inst)
|
||||
minimum network delay. This can significantly improve the accuracy and
|
||||
stability of the estimated offset and frequency. */
|
||||
|
||||
static int
|
||||
estimate_asymmetry(double *times_back, double *offsets, double *delays, int n,
|
||||
double *asymmetry, int *asymmetry_run)
|
||||
{
|
||||
double a;
|
||||
|
||||
/* Reset the counter when the regression fails or the sign changes */
|
||||
if (!RGR_MultipleRegress(times_back, delays, offsets, n, &a) ||
|
||||
a * *asymmetry_run < 0.0) {
|
||||
*asymmetry = 0;
|
||||
*asymmetry_run = 0.0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (a <= -MIN_ASYMMETRY && *asymmetry_run > -MAX_ASYMMETRY_RUN)
|
||||
(*asymmetry_run)--;
|
||||
else if (a >= MIN_ASYMMETRY && *asymmetry_run < MAX_ASYMMETRY_RUN)
|
||||
(*asymmetry_run)++;
|
||||
|
||||
if (abs(*asymmetry_run) < MIN_ASYMMETRY_RUN)
|
||||
return 0;
|
||||
|
||||
*asymmetry = CLAMP(-MAX_ASYMMETRY, a, MAX_ASYMMETRY);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
correct_asymmetry(SST_Stats inst, double *times_back, double *offsets)
|
||||
{
|
||||
double asymmetry, delays[MAX_SAMPLES * REGRESS_RUNS_RATIO];
|
||||
double min_delay, delays[MAX_SAMPLES * REGRESS_RUNS_RATIO];
|
||||
int i, n;
|
||||
|
||||
/* Don't try to estimate the asymmetry with reference clocks */
|
||||
if (!inst->ip_addr)
|
||||
/* Check if the asymmetry was not specified to be zero */
|
||||
if (inst->fixed_asymmetry == 0.0)
|
||||
return;
|
||||
|
||||
min_delay = SST_MinRoundTripDelay(inst);
|
||||
n = inst->runs_samples + inst->n_samples;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
delays[i] = inst->peer_delays[get_runsbuf_index(inst, i - inst->runs_samples)] -
|
||||
inst->peer_delays[inst->min_delay_sample];
|
||||
min_delay;
|
||||
|
||||
/* Reset the counter when the regression fails or the sign changes */
|
||||
if (!RGR_MultipleRegress(times_back, delays, offsets, n, &asymmetry) ||
|
||||
asymmetry * inst->asymmetry_run < 0.0) {
|
||||
inst->asymmetry_run = 0;
|
||||
inst->asymmetry = 0.0;
|
||||
return;
|
||||
if (fabs(inst->fixed_asymmetry) <= MAX_ASYMMETRY) {
|
||||
inst->asymmetry = inst->fixed_asymmetry;
|
||||
} else {
|
||||
if (!estimate_asymmetry(times_back, offsets, delays, n,
|
||||
&inst->asymmetry, &inst->asymmetry_run))
|
||||
return;
|
||||
}
|
||||
|
||||
asymmetry = CLAMP(-MAX_ASYMMETRY, asymmetry, MAX_ASYMMETRY);
|
||||
|
||||
if (asymmetry <= -MIN_ASYMMETRY && inst->asymmetry_run > -MAX_ASYMMETRY_RUN)
|
||||
inst->asymmetry_run--;
|
||||
else if (asymmetry >= MIN_ASYMMETRY && inst->asymmetry_run < MAX_ASYMMETRY_RUN)
|
||||
inst->asymmetry_run++;
|
||||
|
||||
if (abs(inst->asymmetry_run) < MIN_ASYMMETRY_RUN)
|
||||
return;
|
||||
|
||||
/* Correct the offsets */
|
||||
for (i = 0; i < n; i++)
|
||||
offsets[i] -= asymmetry * delays[i];
|
||||
|
||||
inst->asymmetry = asymmetry;
|
||||
offsets[i] -= inst->asymmetry * delays[i];
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -466,7 +496,7 @@ correct_asymmetry(SST_Stats inst, double *times_back, double *offsets)
|
||||
time. E.g. a value of 4 means that we think the standard deviation
|
||||
is four times the fluctuation of the peer distance */
|
||||
|
||||
#define SD_TO_DIST_RATIO 1.0
|
||||
#define SD_TO_DIST_RATIO 0.7
|
||||
|
||||
/* ================================================== */
|
||||
/* This function runs the linear regression operation on the data. It
|
||||
@@ -486,9 +516,10 @@ SST_DoNewRegression(SST_Stats inst)
|
||||
int best_start, times_back_start;
|
||||
double est_intercept, est_slope, est_var, est_intercept_sd, est_slope_sd;
|
||||
int i, j, nruns;
|
||||
double min_distance, mean_distance;
|
||||
double min_distance, median_distance;
|
||||
double sd_weight, sd;
|
||||
double old_skew, old_freq, stress;
|
||||
double precision;
|
||||
|
||||
convert_to_intervals(inst, times_back + inst->runs_samples);
|
||||
|
||||
@@ -497,24 +528,28 @@ SST_DoNewRegression(SST_Stats inst)
|
||||
offsets[i + inst->runs_samples] = inst->offsets[get_runsbuf_index(inst, i)];
|
||||
}
|
||||
|
||||
for (i = 0, mean_distance = 0.0, min_distance = DBL_MAX; i < inst->n_samples; i++) {
|
||||
for (i = 0, min_distance = DBL_MAX; i < inst->n_samples; i++) {
|
||||
j = get_buf_index(inst, i);
|
||||
peer_distances[i] = 0.5 * inst->peer_delays[get_runsbuf_index(inst, i)] +
|
||||
inst->peer_dispersions[j];
|
||||
mean_distance += peer_distances[i];
|
||||
if (peer_distances[i] < min_distance) {
|
||||
min_distance = peer_distances[i];
|
||||
}
|
||||
}
|
||||
mean_distance /= inst->n_samples;
|
||||
|
||||
/* And now, work out the weight vector */
|
||||
|
||||
sd = mean_distance - min_distance;
|
||||
sd = CLAMP(MIN_WEIGHT_SD, sd, min_distance);
|
||||
precision = LCL_GetSysPrecisionAsQuantum();
|
||||
median_distance = RGR_FindMedian(peer_distances, inst->n_samples);
|
||||
|
||||
sd = (median_distance - min_distance) / SD_TO_DIST_RATIO;
|
||||
sd = CLAMP(precision, sd, min_distance);
|
||||
min_distance += precision;
|
||||
|
||||
for (i=0; i<inst->n_samples; i++) {
|
||||
sd_weight = 1.0 + SD_TO_DIST_RATIO * (peer_distances[i] - min_distance) / sd;
|
||||
sd_weight = 1.0;
|
||||
if (peer_distances[i] > min_distance)
|
||||
sd_weight += (peer_distances[i] - min_distance) / sd;
|
||||
weights[i] = sd_weight * sd_weight;
|
||||
}
|
||||
}
|
||||
@@ -539,13 +574,13 @@ SST_DoNewRegression(SST_Stats inst)
|
||||
inst->estimated_offset = est_intercept;
|
||||
inst->offset_time = inst->sample_times[inst->last_sample];
|
||||
inst->estimated_offset_sd = est_intercept_sd;
|
||||
inst->std_dev = sqrt(est_var);
|
||||
inst->std_dev = MAX(MIN_STDDEV, sqrt(est_var));
|
||||
inst->nruns = nruns;
|
||||
|
||||
inst->skew = CLAMP(MIN_SKEW, inst->skew, MAX_SKEW);
|
||||
stress = fabs(old_freq - inst->estimated_frequency) / old_skew;
|
||||
|
||||
DEBUG_LOG(LOGF_SourceStats, "off=%e freq=%e skew=%e n=%d bs=%d runs=%d asym=%f arun=%d",
|
||||
DEBUG_LOG("off=%e freq=%e skew=%e n=%d bs=%d runs=%d asym=%f arun=%d",
|
||||
inst->estimated_offset, inst->estimated_frequency, inst->skew,
|
||||
inst->n_samples, best_start, inst->nruns,
|
||||
inst->asymmetry, inst->asymmetry_run);
|
||||
@@ -624,7 +659,7 @@ SST_GetSelectionData(SST_Stats inst, struct timespec *now,
|
||||
*stratum = inst->strata[get_buf_index(inst, inst->n_samples - 1)];
|
||||
*std_dev = inst->std_dev;
|
||||
|
||||
sample_elapsed = UTI_DiffTimespecsToDouble(now, &inst->sample_times[i]);
|
||||
sample_elapsed = fabs(UTI_DiffTimespecsToDouble(now, &inst->sample_times[i]));
|
||||
offset = inst->offsets[i] + sample_elapsed * inst->estimated_frequency;
|
||||
*root_distance = 0.5 * inst->root_delays[j] +
|
||||
inst->root_dispersions[j] + sample_elapsed * inst->skew;
|
||||
@@ -653,7 +688,7 @@ SST_GetSelectionData(SST_Stats inst, struct timespec *now,
|
||||
|
||||
*select_ok = inst->regression_ok;
|
||||
|
||||
DEBUG_LOG(LOGF_SourceStats, "n=%d off=%f dist=%f sd=%f first_ago=%f last_ago=%f selok=%d",
|
||||
DEBUG_LOG("n=%d off=%f dist=%f sd=%f first_ago=%f last_ago=%f selok=%d",
|
||||
inst->n_samples, offset, *root_distance, *std_dev,
|
||||
*first_sample_ago, *last_sample_ago, *select_ok);
|
||||
}
|
||||
@@ -684,8 +719,9 @@ SST_GetTrackingData(SST_Stats inst, struct timespec *ref_time,
|
||||
elapsed_sample = UTI_DiffTimespecsToDouble(&inst->offset_time, &inst->sample_times[i]);
|
||||
*root_dispersion = inst->root_dispersions[j] + inst->skew * elapsed_sample;
|
||||
|
||||
DEBUG_LOG(LOGF_SourceStats, "n=%d freq=%f (%.3fppm) skew=%f (%.3fppm) avoff=%f offsd=%f disp=%f",
|
||||
inst->n_samples, *frequency, 1.0e6* *frequency, *skew, 1.0e6* *skew, *average_offset, *offset_sd, *root_dispersion);
|
||||
DEBUG_LOG("n=%d freq=%f (%.3fppm) skew=%f (%.3fppm) avoff=%f offsd=%f disp=%f",
|
||||
inst->n_samples, *frequency, 1.0e6* *frequency, *skew, 1.0e6* *skew,
|
||||
*average_offset, *offset_sd, *root_dispersion);
|
||||
|
||||
}
|
||||
|
||||
@@ -719,7 +755,7 @@ SST_SlewSamples(SST_Stats inst, struct timespec *when, double dfreq, double doff
|
||||
inst->estimated_offset += delta_time;
|
||||
inst->estimated_frequency = (inst->estimated_frequency - dfreq) / (1.0 - dfreq);
|
||||
|
||||
DEBUG_LOG(LOGF_SourceStats, "n=%d m=%d old_off_time=%s new=%s old_off=%f new_off=%f old_freq=%.3f new_freq=%.3f",
|
||||
DEBUG_LOG("n=%d m=%d old_off_time=%s new=%s old_off=%f new_off=%f old_freq=%.3f new_freq=%.3f",
|
||||
inst->n_samples, inst->runs_samples,
|
||||
UTI_TimespecToString(&prev), UTI_TimespecToString(&inst->offset_time),
|
||||
prev_offset, inst->estimated_offset,
|
||||
@@ -768,47 +804,33 @@ SST_PredictOffset(SST_Stats inst, struct timespec *when)
|
||||
double
|
||||
SST_MinRoundTripDelay(SST_Stats inst)
|
||||
{
|
||||
if (inst->fixed_min_delay > 0.0)
|
||||
return inst->fixed_min_delay;
|
||||
|
||||
if (!inst->n_samples)
|
||||
return DBL_MAX;
|
||||
|
||||
return inst->peer_delays[inst->min_delay_sample];
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SST_IsGoodSample(SST_Stats inst, double offset, double delay,
|
||||
double max_delay_dev_ratio, double clock_error, struct timespec *when)
|
||||
SST_GetDelayTestData(SST_Stats inst, struct timespec *sample_time,
|
||||
double *last_sample_ago, double *predicted_offset,
|
||||
double *min_delay, double *skew, double *std_dev)
|
||||
{
|
||||
double elapsed, allowed_increase, delay_increase;
|
||||
if (inst->n_samples < 6)
|
||||
return 0;
|
||||
|
||||
if (inst->n_samples < 3)
|
||||
return 1;
|
||||
*last_sample_ago = UTI_DiffTimespecsToDouble(sample_time, &inst->offset_time);
|
||||
*predicted_offset = inst->estimated_offset +
|
||||
*last_sample_ago * inst->estimated_frequency;
|
||||
*min_delay = SST_MinRoundTripDelay(inst);
|
||||
*skew = inst->skew;
|
||||
*std_dev = inst->std_dev;
|
||||
|
||||
elapsed = UTI_DiffTimespecsToDouble(when, &inst->offset_time);
|
||||
|
||||
/* Require that the ratio of the increase in delay from the minimum to the
|
||||
standard deviation is less than max_delay_dev_ratio. In the allowed
|
||||
increase in delay include also skew and clock_error. */
|
||||
|
||||
allowed_increase = inst->std_dev * max_delay_dev_ratio +
|
||||
elapsed * (inst->skew + clock_error);
|
||||
delay_increase = (delay - SST_MinRoundTripDelay(inst)) / 2.0;
|
||||
|
||||
if (delay_increase < allowed_increase)
|
||||
return 1;
|
||||
|
||||
offset -= inst->estimated_offset + elapsed * inst->estimated_frequency;
|
||||
|
||||
/* Before we decide to drop the sample, make sure the difference between
|
||||
measured offset and predicted offset is not significantly larger than
|
||||
the increase in delay */
|
||||
if (fabs(offset) - delay_increase > allowed_increase)
|
||||
return 1;
|
||||
|
||||
DEBUG_LOG(LOGF_SourceStats, "Bad sample: offset=%f delay=%f incr_delay=%f allowed=%f",
|
||||
offset, delay, allowed_increase, delay_increase);
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -865,7 +887,7 @@ SST_LoadFromFile(SST_Stats inst, FILE *in)
|
||||
char line[1024];
|
||||
double weight;
|
||||
|
||||
assert(!inst->n_samples);
|
||||
SST_ResetInstance(inst);
|
||||
|
||||
if (fgets(line, sizeof(line), in) &&
|
||||
sscanf(line, "%d", &inst->n_samples) == 1 &&
|
||||
@@ -914,7 +936,6 @@ SST_LoadFromFile(SST_Stats inst, FILE *in)
|
||||
return 1;
|
||||
|
||||
inst->last_sample = inst->n_samples - 1;
|
||||
inst->runs_samples = 0;
|
||||
|
||||
find_min_delay_sample(inst);
|
||||
SST_DoNewRegression(inst);
|
||||
@@ -928,7 +949,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);
|
||||
@@ -938,8 +959,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;
|
||||
|
||||
@@ -38,7 +38,9 @@ extern void SST_Initialise(void);
|
||||
extern void SST_Finalise(void);
|
||||
|
||||
/* This function creates a new instance of the statistics handler */
|
||||
extern SST_Stats SST_CreateInstance(uint32_t refid, IPAddr *addr, int min_samples, int max_samples);
|
||||
extern SST_Stats SST_CreateInstance(uint32_t refid, IPAddr *addr,
|
||||
int min_samples, int max_samples,
|
||||
double min_delay, double asymmetry);
|
||||
|
||||
/* This function deletes an instance of the statistics handler. */
|
||||
extern void SST_DeleteInstance(SST_Stats inst);
|
||||
@@ -124,10 +126,10 @@ extern double SST_PredictOffset(SST_Stats inst, struct timespec *when);
|
||||
/* Find the minimum round trip delay in the register */
|
||||
extern double SST_MinRoundTripDelay(SST_Stats inst);
|
||||
|
||||
/* This routine determines if a new sample is good enough that it should be
|
||||
accumulated */
|
||||
extern int SST_IsGoodSample(SST_Stats inst, double offset, double delay,
|
||||
double max_delay_dev_ratio, double clock_error, struct timespec *when);
|
||||
/* Get data needed for testing NTP delay */
|
||||
extern int SST_GetDelayTestData(SST_Stats inst, struct timespec *sample_time,
|
||||
double *last_sample_ago, double *predicted_offset,
|
||||
double *min_delay, double *skew, double *std_dev);
|
||||
|
||||
extern void SST_SaveToFile(SST_Stats inst, FILE *out);
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ typedef struct {
|
||||
int online;
|
||||
int auto_offline;
|
||||
int presend_minpoll;
|
||||
int burst;
|
||||
int iburst;
|
||||
int min_stratum;
|
||||
int poll_target;
|
||||
@@ -48,6 +49,8 @@ typedef struct {
|
||||
double max_delay;
|
||||
double max_delay_ratio;
|
||||
double max_delay_dev_ratio;
|
||||
double min_delay;
|
||||
double asymmetry;
|
||||
double offset;
|
||||
} SourceParameters;
|
||||
|
||||
@@ -63,6 +66,7 @@ typedef struct {
|
||||
#define SRC_DEFAULT_MAXSOURCES 4
|
||||
#define SRC_DEFAULT_MINSAMPLES (-1)
|
||||
#define SRC_DEFAULT_MAXSAMPLES (-1)
|
||||
#define SRC_DEFAULT_ASYMMETRY 1.0
|
||||
#define INACTIVE_AUTHKEY 0
|
||||
|
||||
/* Flags for source selection */
|
||||
|
||||
4
stubs.c
4
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
|
||||
@@ -91,7 +91,7 @@ DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *
|
||||
inst->arg = anything;
|
||||
|
||||
if (pipe(inst->pipe))
|
||||
LOG_FATAL(LOGF_Nameserv, "pipe() failed");
|
||||
LOG_FATAL("pipe() failed");
|
||||
|
||||
UTI_FdSetCloexec(inst->pipe[0]);
|
||||
UTI_FdSetCloexec(inst->pipe[1]);
|
||||
|
||||
26
sys.c
26
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)
|
||||
@@ -83,7 +97,7 @@ SYS_Finalise(void)
|
||||
void SYS_DropRoot(uid_t uid, gid_t gid)
|
||||
{
|
||||
#if defined(LINUX) && defined (FEAT_PRIVDROP)
|
||||
SYS_Linux_DropRoot(uid, gid);
|
||||
SYS_Linux_DropRoot(uid, gid, !null_driver);
|
||||
#elif defined(SOLARIS) && defined(FEAT_PRIVDROP)
|
||||
SYS_Solaris_DropRoot(uid, gid);
|
||||
#elif (defined(NETBSD) || defined(FREEBSD)) && defined(FEAT_PRIVDROP)
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
303
sys_linux.c
303
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-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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -378,6 +380,18 @@ test_step_offset(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
report_time_adjust_blockers(void)
|
||||
{
|
||||
#ifdef FEAT_PRIVDROP
|
||||
if (CAP_IS_SUPPORTED(CAP_SYS_TIME) && cap_get_bound(CAP_SYS_TIME))
|
||||
return;
|
||||
LOG(LOGS_WARN, "CAP_SYS_TIME not present");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Initialisation code for this module */
|
||||
|
||||
@@ -386,10 +400,12 @@ SYS_Linux_Initialise(void)
|
||||
{
|
||||
get_version_specific_details();
|
||||
|
||||
report_time_adjust_blockers();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -413,27 +429,30 @@ SYS_Linux_Finalise(void)
|
||||
|
||||
#ifdef FEAT_PRIVDROP
|
||||
void
|
||||
SYS_Linux_DropRoot(uid_t uid, gid_t gid)
|
||||
SYS_Linux_DropRoot(uid_t uid, gid_t gid, int clock_control)
|
||||
{
|
||||
const char *cap_text;
|
||||
char cap_text[256];
|
||||
cap_t cap;
|
||||
|
||||
if (prctl(PR_SET_KEEPCAPS, 1)) {
|
||||
LOG_FATAL(LOGF_SysLinux, "prctl() failed");
|
||||
LOG_FATAL("prctl() failed");
|
||||
}
|
||||
|
||||
UTI_DropRoot(uid, gid);
|
||||
|
||||
/* Keep CAP_NET_BIND_SERVICE only if NTP port can be opened */
|
||||
cap_text = CNF_GetNTPPort() ?
|
||||
"cap_net_bind_service,cap_sys_time=ep" : "cap_sys_time=ep";
|
||||
/* Keep CAP_NET_BIND_SERVICE only if a server NTP port can be opened
|
||||
and keep CAP_SYS_TIME only if the clock control is enabled */
|
||||
if (snprintf(cap_text, sizeof (cap_text), "%s %s",
|
||||
CNF_GetNTPPort() ? "cap_net_bind_service=ep" : "",
|
||||
clock_control ? "cap_sys_time=ep" : "") >= sizeof (cap_text))
|
||||
assert(0);
|
||||
|
||||
if ((cap = cap_from_text(cap_text)) == NULL) {
|
||||
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 +471,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 +484,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 +507,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 +534,13 @@ SYS_Linux_EnableSystemCallFilter(int level)
|
||||
const static unsigned long ioctls[] = {
|
||||
FIONREAD, TCGETS,
|
||||
#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
|
||||
PTP_SYS_OFFSET,
|
||||
PTP_EXTTS_REQUEST, PTP_SYS_OFFSET,
|
||||
#ifdef PTP_PIN_SETFUNC
|
||||
PTP_PIN_SETFUNC,
|
||||
#endif
|
||||
#ifdef PTP_SYS_OFFSET_PRECISE
|
||||
PTP_SYS_OFFSET_PRECISE,
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FEAT_PPS
|
||||
PPS_FETCH,
|
||||
@@ -541,7 +567,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 +608,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 +629,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 +641,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 +662,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 +687,210 @@ 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_extts_request extts_req;
|
||||
#ifdef PTP_PIN_SETFUNC
|
||||
struct ptp_pin_desc pin_desc;
|
||||
|
||||
memset(&pin_desc, 0, sizeof (pin_desc));
|
||||
pin_desc.index = pin;
|
||||
pin_desc.func = enable ? PTP_PF_EXTTS : PTP_PF_NONE;
|
||||
pin_desc.chan = channel;
|
||||
|
||||
if (ioctl(fd, PTP_PIN_SETFUNC, &pin_desc)) {
|
||||
DEBUG_LOG("ioctl(%s) failed : %s", "PTP_PIN_SETFUNC", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
DEBUG_LOG("Missing PTP_PIN_SETFUNC");
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
memset(&extts_req, 0, sizeof (extts_req));
|
||||
extts_req.index = channel;
|
||||
extts_req.flags = (enable ? PTP_ENABLE_FEATURE : 0) |
|
||||
(rising ? PTP_RISING_EDGE : 0) |
|
||||
(falling ? PTP_FALLING_EDGE : 0);
|
||||
|
||||
if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_req)) {
|
||||
DEBUG_LOG("ioctl(%s) failed : %s", "PTP_EXTTS_REQUEST", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SYS_Linux_ReadPHCExtTimestamp(int fd, struct timespec *phc_ts, int *channel)
|
||||
{
|
||||
struct ptp_extts_event extts_event;
|
||||
|
||||
if (read(fd, &extts_event, sizeof (extts_event)) != sizeof (extts_event)) {
|
||||
DEBUG_LOG("Could not read PHC extts event");
|
||||
return 0;
|
||||
}
|
||||
|
||||
phc_ts->tv_sec = extts_event.t.sec;
|
||||
phc_ts->tv_nsec = extts_event.t.nsec;
|
||||
*channel = extts_event.index;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
12
sys_linux.h
12
sys_linux.h
@@ -31,7 +31,7 @@ extern void SYS_Linux_Initialise(void);
|
||||
|
||||
extern void SYS_Linux_Finalise(void);
|
||||
|
||||
extern void SYS_Linux_DropRoot(uid_t uid, gid_t gid);
|
||||
extern void SYS_Linux_DropRoot(uid_t uid, gid_t gid, int clock_control);
|
||||
|
||||
extern void SYS_Linux_EnableSystemCallFilter(int level);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
103
sys_macosx.c
103
sys_macosx.c
@@ -4,7 +4,7 @@
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2001
|
||||
* Copyright (C) J. Hannken-Illjes 2001
|
||||
* Copyright (C) Bryan Christianson 2015
|
||||
* Copyright (C) Bryan Christianson 2015, 2017
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -46,6 +46,15 @@
|
||||
#include "privops.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef HAVE_MACOS_SYS_TIMEX
|
||||
#include <dlfcn.h>
|
||||
#include "sys_netbsd.h"
|
||||
#include "sys_timex.h"
|
||||
|
||||
static int have_ntp_adjtime = 0;
|
||||
static int have_bad_adjtime = 0;
|
||||
#endif
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* This register contains the number of seconds by which the local
|
||||
@@ -116,7 +125,7 @@ clock_initialise(void)
|
||||
newadj.tv_usec = 0;
|
||||
|
||||
if (PRV_AdjustTime(&newadj, &oldadj) < 0) {
|
||||
LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed");
|
||||
LOG_FATAL("adjtime() failed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,10 +163,9 @@ start_adjust(void)
|
||||
|
||||
predicted_error = (current_drift_removal_interval - drift_removal_elapsed) / 2.0 * current_freq;
|
||||
|
||||
DEBUG_LOG(LOGF_SysMacOSX, "drift_removal_elapsed: %.3f current_drift_removal_interval: %.3f predicted_error: %.3f",
|
||||
1.0e6 * drift_removal_elapsed,
|
||||
1.0e6 * current_drift_removal_interval,
|
||||
1.0e6 * predicted_error);
|
||||
DEBUG_LOG("drift_removal_elapsed: %.3f current_drift_removal_interval: %.3f predicted_error: %.3f",
|
||||
1.0e6 * drift_removal_elapsed, 1.0e6 * current_drift_removal_interval,
|
||||
1.0e6 * predicted_error);
|
||||
|
||||
adjust_required = - (accrued_error + offset_register + predicted_error);
|
||||
|
||||
@@ -166,7 +174,7 @@ start_adjust(void)
|
||||
rounding_error = adjust_required - adjustment_requested;
|
||||
|
||||
if (PRV_AdjustTime(&newadj, &oldadj) < 0) {
|
||||
LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed");
|
||||
LOG_FATAL("adjtime() failed");
|
||||
}
|
||||
|
||||
old_adjust_remaining = UTI_TimevalToDouble(&oldadj);
|
||||
@@ -190,7 +198,7 @@ stop_adjust(void)
|
||||
zeroadj.tv_usec = 0;
|
||||
|
||||
if (PRV_AdjustTime(&zeroadj, &remadj) < 0) {
|
||||
LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed");
|
||||
LOG_FATAL("adjtime() failed");
|
||||
}
|
||||
|
||||
LCL_ReadRawTime(&T1);
|
||||
@@ -239,7 +247,7 @@ apply_step_offset(double offset)
|
||||
UTI_TimespecToTimeval(&new_time, &new_time_tv);
|
||||
|
||||
if (PRV_SetTime(&new_time_tv, NULL) < 0) {
|
||||
DEBUG_LOG(LOGF_SysMacOSX, "settimeofday() failed");
|
||||
DEBUG_LOG("settimeofday() failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -338,14 +346,14 @@ set_sync_status(int synchronised, double est_error, double max_error)
|
||||
/* update the RTC by applying a step of 0.0 secs */
|
||||
apply_step_offset(0.0);
|
||||
last_rtc_sync = now;
|
||||
DEBUG_LOG(LOGF_SysMacOSX, "rtc synchronised");
|
||||
DEBUG_LOG("rtc synchronised");
|
||||
}
|
||||
}
|
||||
|
||||
interval = ERROR_WEIGHT * est_error / (fabs(current_freq) + FREQUENCY_RES);
|
||||
drift_removal_interval = MAX(interval, DRIFT_REMOVAL_INTERVAL_MIN);
|
||||
|
||||
DEBUG_LOG(LOGF_SysMacOSX, "est_error: %.3f current_freq: %.3f est drift_removal_interval: %.3f act drift_removal_interval: %.3f",
|
||||
DEBUG_LOG("est_error: %.3f current_freq: %.3f est drift_removal_interval: %.3f act drift_removal_interval: %.3f",
|
||||
est_error * 1.0e6, current_freq * 1.0e6, interval, drift_removal_interval);
|
||||
}
|
||||
|
||||
@@ -389,7 +397,7 @@ set_realtime(void)
|
||||
THREAD_TIME_CONSTRAINT_POLICY_COUNT);
|
||||
|
||||
if (kr != KERN_SUCCESS) {
|
||||
LOG(LOGS_WARN, LOGF_SysMacOSX, "Cannot set real-time priority: %d", kr);
|
||||
LOG(LOGS_WARN, "Cannot set real-time priority: %d", kr);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -418,8 +426,8 @@ void SYS_MacOSX_DropRoot(uid_t uid, gid_t gid)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SYS_MacOSX_Initialise(void)
|
||||
static void
|
||||
legacy_MacOSX_Initialise(void)
|
||||
{
|
||||
clock_initialise();
|
||||
|
||||
@@ -435,8 +443,8 @@ SYS_MacOSX_Initialise(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SYS_MacOSX_Finalise(void)
|
||||
static void
|
||||
legacy_MacOSX_Finalise(void)
|
||||
{
|
||||
SCH_RemoveTimeout(drift_removal_id);
|
||||
|
||||
@@ -445,4 +453,67 @@ SYS_MacOSX_Finalise(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#ifdef HAVE_MACOS_SYS_TIMEX
|
||||
/*
|
||||
Test adjtime() to see if Apple have fixed the signed/unsigned bug
|
||||
*/
|
||||
static int
|
||||
test_adjtime()
|
||||
{
|
||||
struct timeval tv1 = {-1, 0};
|
||||
struct timeval tv2 = {0, 0};
|
||||
struct timeval tv;
|
||||
|
||||
if (PRV_AdjustTime(&tv1, &tv) != 0) {
|
||||
return 0;
|
||||
}
|
||||
if (PRV_AdjustTime(&tv2, &tv) != 0) {
|
||||
return 0;
|
||||
}
|
||||
if (tv.tv_sec < -1 || tv.tv_sec > 1) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SYS_MacOSX_Initialise(void)
|
||||
{
|
||||
#ifdef HAVE_MACOS_SYS_TIMEX
|
||||
have_ntp_adjtime = (dlsym(RTLD_NEXT, "ntp_adjtime") != NULL);
|
||||
if (have_ntp_adjtime) {
|
||||
have_bad_adjtime = !test_adjtime();
|
||||
if (have_bad_adjtime) {
|
||||
LOG(LOGS_WARN, "adjtime() is buggy - using timex driver");
|
||||
SYS_Timex_Initialise();
|
||||
} else {
|
||||
SYS_NetBSD_Initialise();
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
legacy_MacOSX_Initialise();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SYS_MacOSX_Finalise(void)
|
||||
{
|
||||
#ifdef HAVE_MACOS_SYS_TIMEX
|
||||
if (have_ntp_adjtime) {
|
||||
if (have_bad_adjtime) {
|
||||
SYS_Timex_Finalise();
|
||||
} else {
|
||||
SYS_NetBSD_Finalise();
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
legacy_MacOSX_Finalise();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
17
sys_netbsd.c
17
sys_netbsd.c
@@ -65,14 +65,14 @@ accrue_offset(double offset, double corr_rate)
|
||||
UTI_DoubleToTimeval(-offset, &newadj);
|
||||
|
||||
if (PRV_AdjustTime(&newadj, &oldadj) < 0)
|
||||
LOG_FATAL(LOGF_SysNetBSD, "adjtime() failed");
|
||||
LOG_FATAL("adjtime() failed");
|
||||
|
||||
/* Add the old remaining adjustment if not zero */
|
||||
doldadj = UTI_TimevalToDouble(&oldadj);
|
||||
if (doldadj != 0.0) {
|
||||
UTI_DoubleToTimeval(-offset + doldadj, &newadj);
|
||||
if (PRV_AdjustTime(&newadj, NULL) < 0)
|
||||
LOG_FATAL(LOGF_SysNetBSD, "adjtime() failed");
|
||||
LOG_FATAL("adjtime() failed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,9 +84,18 @@ get_offset_correction(struct timespec *raw,
|
||||
{
|
||||
struct timeval remadj;
|
||||
double adjustment_remaining;
|
||||
#ifdef MACOSX
|
||||
struct timeval tv = {0, 0};
|
||||
|
||||
if (PRV_AdjustTime(&tv, &remadj) < 0)
|
||||
LOG_FATAL("adjtime() failed");
|
||||
|
||||
if (PRV_AdjustTime(&remadj, NULL) < 0)
|
||||
LOG_FATAL("adjtime() failed");
|
||||
#else
|
||||
if (PRV_AdjustTime(NULL, &remadj) < 0)
|
||||
LOG_FATAL(LOGF_SysNetBSD, "adjtime() failed");
|
||||
LOG_FATAL("adjtime() failed");
|
||||
#endif
|
||||
|
||||
adjustment_remaining = UTI_TimevalToDouble(&remadj);
|
||||
|
||||
@@ -138,7 +147,7 @@ SYS_NetBSD_DropRoot(uid_t uid, gid_t gid)
|
||||
/* Check if we have write access to /dev/clockctl */
|
||||
fd = open("/dev/clockctl", O_WRONLY);
|
||||
if (fd < 0)
|
||||
LOG_FATAL(LOGF_SysNetBSD, "Can't write to /dev/clockctl");
|
||||
LOG_FATAL("Can't write to /dev/clockctl");
|
||||
close(fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
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
|
||||
73
sys_timex.c
73
sys_timex.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2009-2012, 2014-2015
|
||||
* Copyright (C) Miroslav Lichvar 2009-2012, 2014-2015, 2017
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -61,7 +61,10 @@
|
||||
#define MIN_TICK_RATE 100
|
||||
|
||||
/* Saved timex status */
|
||||
static int status;
|
||||
static int sys_status;
|
||||
|
||||
/* Saved TAI-UTC offset */
|
||||
static int sys_tai_offset;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -95,33 +98,47 @@ set_frequency(double freq_ppm)
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
set_leap(int leap)
|
||||
set_leap(int leap, int tai_offset)
|
||||
{
|
||||
struct timex txc;
|
||||
int applied;
|
||||
int applied, prev_status;
|
||||
|
||||
applied = 0;
|
||||
if (!leap) {
|
||||
txc.modes = 0;
|
||||
if (SYS_Timex_Adjust(&txc, 1) == TIME_WAIT)
|
||||
applied = 1;
|
||||
}
|
||||
txc.modes = 0;
|
||||
applied = SYS_Timex_Adjust(&txc, 0) == TIME_WAIT;
|
||||
|
||||
status &= ~(STA_INS | STA_DEL);
|
||||
prev_status = sys_status;
|
||||
sys_status &= ~(STA_INS | STA_DEL);
|
||||
|
||||
if (leap > 0)
|
||||
status |= STA_INS;
|
||||
sys_status |= STA_INS;
|
||||
else if (leap < 0)
|
||||
status |= STA_DEL;
|
||||
sys_status |= STA_DEL;
|
||||
|
||||
txc.modes = MOD_STATUS;
|
||||
txc.status = status;
|
||||
txc.status = sys_status;
|
||||
|
||||
#ifdef MOD_TAI
|
||||
if (tai_offset) {
|
||||
txc.modes |= MOD_TAI;
|
||||
txc.constant = tai_offset;
|
||||
|
||||
if (applied && !(sys_status & (STA_INS | STA_DEL)))
|
||||
sys_tai_offset += prev_status & STA_INS ? 1 : -1;
|
||||
|
||||
if (sys_tai_offset != tai_offset) {
|
||||
sys_tai_offset = tai_offset;
|
||||
LOG(LOGS_INFO, "System clock TAI offset set to %d seconds", tai_offset);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
SYS_Timex_Adjust(&txc, 0);
|
||||
|
||||
LOG(LOGS_INFO, LOGF_SysTimex, "System clock status %s leap second",
|
||||
leap ? (leap > 0 ? "set to insert" : "set to delete") :
|
||||
(applied ? "reset after" : "set to not insert/delete"));
|
||||
if (prev_status != sys_status) {
|
||||
LOG(LOGS_INFO, "System clock status %s leap second",
|
||||
leap ? (leap > 0 ? "set to insert" : "set to delete") :
|
||||
(applied ? "reset after" : "set to not insert/delete"));
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -149,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
|
||||
|
||||
@@ -6,8 +6,9 @@ for opts in \
|
||||
"--host-system=Linux" \
|
||||
"--host-system=NetBSD" \
|
||||
"--host-system=FreeBSD" \
|
||||
"--without-nss" \
|
||||
"--without-tomcrypt --without-nss"
|
||||
"--without-nettle" \
|
||||
"--without-nettle --without-nss" \
|
||||
"--without-nettle --without-nss --without-tomcrypt"
|
||||
do
|
||||
./configure $opts
|
||||
scan-build make "$@" || exit 1
|
||||
|
||||
@@ -8,11 +8,20 @@ limit=1000
|
||||
refclock_jitter=$jitter
|
||||
min_sync_time=45
|
||||
max_sync_time=70
|
||||
client_conf="refclock SHM 0"
|
||||
chronyc_start=70
|
||||
client_conf="refclock SHM 0 stratum 3 delay 1e-3 refid GPS"
|
||||
chronyc_conf="tracking"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
check_chronyc_output "^Reference ID.*47505300 \(GPS\)
|
||||
Stratum.*: 4
|
||||
.*
|
||||
Root delay : 0.001000000 seconds
|
||||
.*
|
||||
Update interval : 16\.. seconds
|
||||
.*$" || test_fail
|
||||
|
||||
test_pass
|
||||
|
||||
@@ -4,14 +4,30 @@
|
||||
|
||||
test_start "chronyc"
|
||||
|
||||
chronyc_conf="tracking
|
||||
refclock_jitter=$jitter
|
||||
client_conf="
|
||||
refclock SHM 0 noselect
|
||||
smoothtime 400 0.001 leaponly"
|
||||
|
||||
chronyc_conf="activity
|
||||
tracking
|
||||
sources
|
||||
sourcestats"
|
||||
sourcestats
|
||||
manual list
|
||||
smoothing
|
||||
waitsync
|
||||
rtcdata"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
|
||||
check_chronyc_output "^Reference ID : C0A87B01 \(192\.168\.123\.1\)
|
||||
check_chronyc_output "^200 OK
|
||||
1 sources online
|
||||
0 sources offline
|
||||
0 sources doing burst \(return to online\)
|
||||
0 sources doing burst \(return to offline\)
|
||||
0 sources with unknown address
|
||||
Reference ID : C0A87B01 \(192\.168\.123\.1\)
|
||||
Stratum : 2
|
||||
Ref time \(UTC\) : Fri Jan 01 00:1.:.. 2010
|
||||
System time : 0\.0000..... seconds (slow|fast) of NTP time
|
||||
@@ -20,18 +36,31 @@ 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
|
||||
210 Number of sources = 2
|
||||
MS Name/IP address Stratum Poll Reach LastRx Last sample
|
||||
===============================================================================
|
||||
#\? SHM0 0 4 377 [0-9]+ [0-9 +-]+[un]s\[[0-9 +-]+[un]s\] \+/-[ 0-9]+[un]s
|
||||
\^\* 192\.168\.123\.1 1 [67] 377 [0-9]+ [0-9 +-]+[un]s\[[0-9 +-]+[un]s\] \+/-[ 0-9]+[un]s
|
||||
210 Number of sources = 1
|
||||
210 Number of sources = 2
|
||||
Name/IP Address NP NR Span Frequency Freq Skew Offset Std Dev
|
||||
==============================================================================
|
||||
192\.168\.123\.1 [0-9 ]+ [0-9 ]+ [0-9 ]+ [ +-][01]\.... [0-9 ]+\.... [0-9 +-]+[un]s [0-9 ]+[un]s$" \
|
||||
SHM0 [0-9 ]+ [0-9 ]+ [0-9 ]+ [ +-][01]\.... [0-9 ]+\.... [0-9 +-]+[un]s [0-9 ]+[un]s
|
||||
192\.168\.123\.1 [0-9 ]+ [0-9 ]+ [0-9 ]+ [ +-][01]\.... [0-9 ]+\.... [0-9 +-]+[un]s [0-9 ]+[un]s
|
||||
210 n_samples = 0
|
||||
# Date Time\(UTC\) Slewed Original Residual
|
||||
=======================================================
|
||||
Active : Yes \(leap second only\)
|
||||
Offset : \+0\.000000000 seconds
|
||||
Frequency : \+0\.000000 ppm
|
||||
Wander : \+0\.000000 ppm per second
|
||||
Last update : [0-9]+\.. seconds ago
|
||||
Remaining time : 0\.0 seconds
|
||||
try: 1, refid: C0A87B01, correction: 0\.000......, skew: .\....
|
||||
513 RTC driver not running$" \
|
||||
|| test_fail
|
||||
|
||||
test_pass
|
||||
|
||||
@@ -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"; do
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_packet_interval || test_fail
|
||||
|
||||
@@ -5,8 +5,9 @@ test_start "smoothtime option"
|
||||
|
||||
server_strata=2
|
||||
server_conf="smoothtime 400 0.001"
|
||||
min_sync_time=250
|
||||
max_sync_time=1000
|
||||
server_server_options="minpoll 8"
|
||||
min_sync_time=600
|
||||
max_sync_time=800
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
@@ -22,16 +23,25 @@ server_conf="refclock SHM 0 dpoll 4 poll 6
|
||||
smoothtime 2000 1
|
||||
maxjitter 10.0"
|
||||
time_offset=-10
|
||||
server_server_options=""
|
||||
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
|
||||
|
||||
@@ -17,6 +17,7 @@ max_sync_time=500
|
||||
base_delay="(+ 1e-4 (* -1 (equal 0.1 from 2) (equal 0.1 to 1)))"
|
||||
|
||||
client_lpeer_options="xleave minpoll 5 maxpoll 5"
|
||||
client_rpeer_options="minpoll 5 maxpoll 5"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
|
||||
27
test/simulation/123-mindelay
Executable file
27
test/simulation/123-mindelay
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
|
||||
. ./test.common
|
||||
|
||||
test_start "mindelay and asymmetry options"
|
||||
|
||||
jitter_asymmetry=0.499
|
||||
time_rms_limit=1e-6
|
||||
time_freq_limit=1e-9
|
||||
wander=1e-12
|
||||
|
||||
for client_server_options in "mindelay 2e-4 asymmetry 0.499"; do
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_packet_interval || test_fail
|
||||
check_sync || test_fail
|
||||
done
|
||||
|
||||
for client_server_options in "mindelay 1e-4 asymmetry 0.499" "mindelay 2e-4 asymmetry 0.0"; do
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync && test_fail
|
||||
done
|
||||
|
||||
test_pass
|
||||
42
test/simulation/124-tai
Executable file
42
test/simulation/124-tai
Executable file
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
|
||||
. ./test.common
|
||||
test_start "tai option"
|
||||
|
||||
export CLKNETSIM_START_DATE=$(TZ=UTC date -d 'Dec 31 2008 23:50:00' +'%s')
|
||||
|
||||
leap=$[10 * 60]
|
||||
limit=$[20 * 60]
|
||||
min_sync_time=2
|
||||
max_sync_time=15
|
||||
refclock_jitter=1e-6
|
||||
servers=0
|
||||
|
||||
refclock_offset="(+ -34 (equal 0.1 (max (sum 1.0) $leap) $leap))"
|
||||
client_conf="
|
||||
refclock SHM 0 dpoll 0 poll 0 tai
|
||||
leapsectz right/UTC
|
||||
leapsecmode ignore
|
||||
maxchange 1e-3 1 0"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
export CLKNETSIM_START_DATE=$(TZ=UTC date -d 'Jan 01 2009 00:10:00' +'%s')
|
||||
|
||||
time_offset=-1000
|
||||
refclock_offset="(+ -34)"
|
||||
client_conf="
|
||||
refclock SHM 0 dpoll 0 poll 0 tai
|
||||
leapsectz right/UTC
|
||||
makestep 1 1
|
||||
maxchange 1e-3 1 0"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
test_pass
|
||||
29
test/simulation/125-packetloss
Executable file
29
test/simulation/125-packetloss
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
. ./test.common
|
||||
|
||||
test_start "packet loss"
|
||||
|
||||
# Drop 33% of packets by default and 100% on the 3->1 path
|
||||
base_delay=$(cat <<-EOF | tr -d '\n'
|
||||
(+ 1e-4
|
||||
(* -1 (equal 0.33 (uniform) 1.0))
|
||||
(* -1 (equal 0.1 from 3) (equal 0.1 to 1)))
|
||||
EOF
|
||||
)
|
||||
clients=2
|
||||
peers=2
|
||||
jitter=1e-5
|
||||
limit=20000
|
||||
max_sync_time=10000
|
||||
|
||||
for options in "maxpoll 8" "maxpoll 8 xleave"; do
|
||||
client_server_options=$options
|
||||
client_peer_options=$options
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_sync || test_fail
|
||||
done
|
||||
|
||||
test_pass
|
||||
29
test/simulation/126-burst
Executable file
29
test/simulation/126-burst
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
. ./test.common
|
||||
|
||||
test_start "burst option"
|
||||
|
||||
# Pass every fourth packet on the 2->1 path
|
||||
base_delay=$(cat <<-EOF | tr -d '\n'
|
||||
(+ 1e-4
|
||||
(* -1
|
||||
(equal 0.1 from 2)
|
||||
(equal 0.1 to 1)
|
||||
(equal 0.1 (min (% (sum 1) 4) 1) 1)))
|
||||
EOF
|
||||
)
|
||||
|
||||
client_server_options="burst polltarget 1"
|
||||
min_sync_time=700
|
||||
max_sync_time=730
|
||||
client_max_min_out_interval=2.2
|
||||
client_min_mean_out_interval=150.0
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_packet_interval || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
test_pass
|
||||
@@ -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 ]
|
||||
|
||||
@@ -71,6 +71,9 @@ default_freq_rms_limit=1e-5
|
||||
default_min_sync_time=120
|
||||
default_max_sync_time=210
|
||||
|
||||
default_client_min_mean_out_interval=0.0
|
||||
default_client_max_min_out_interval=inf
|
||||
|
||||
# Initialize test settings from their defaults
|
||||
for defopt in $(declare | grep '^default_'); do
|
||||
defoptname=${defopt%%=*}
|
||||
@@ -251,6 +254,7 @@ check_chronyd_exit() {
|
||||
test_message 3 0 "node $i:"
|
||||
|
||||
tail -n 1 tmp/log.$i | grep -q 'chronyd exiting' && \
|
||||
! grep -q 'Adjustment.*exceeds.*exiting' tmp/log.$i && \
|
||||
test_ok || test_bad
|
||||
[ $? -eq 0 ] || ret=1
|
||||
done
|
||||
@@ -302,10 +306,12 @@ check_packet_interval() {
|
||||
([ $i -gt $servers ] || \
|
||||
check_stat $mean_in_interval 0.0 $mean_out_interval 10*$jitter) && \
|
||||
([ $i -le $[$servers * $server_strata] ] || \
|
||||
check_stat $mean_out_interval 0.0 $mean_in_interval 10*$jitter) && \
|
||||
check_stat $mean_out_interval $client_min_mean_out_interval \
|
||||
$mean_in_interval 10*$jitter) && \
|
||||
([ $i -le $[$servers * $server_strata] ] || \
|
||||
check_stat $min_out_interval \
|
||||
$([ $servers -gt 1 ] && echo 0.18 || echo 1.8) inf) && \
|
||||
$([ $servers -gt 1 ] && echo 0.18 || echo 1.8) \
|
||||
$client_max_min_out_interval) && \
|
||||
test_ok || test_bad
|
||||
|
||||
[ $? -eq 0 ] || ret=1
|
||||
|
||||
@@ -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();
|
||||
|
||||
123
test/unit/hash.c
Normal file
123
test/unit/hash.c
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2018
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <sysincl.h>
|
||||
#include <hash.h>
|
||||
#include <logging.h>
|
||||
#include "test.h"
|
||||
|
||||
struct hash_test {
|
||||
const char *name;
|
||||
const unsigned char out[MAX_HASH_LENGTH];
|
||||
unsigned int length;
|
||||
};
|
||||
|
||||
void
|
||||
test_unit(void)
|
||||
{
|
||||
unsigned char data1[] = "abcdefghijklmnopqrstuvwxyz";
|
||||
unsigned char data2[] = "12345678910";
|
||||
unsigned char out[MAX_HASH_LENGTH];
|
||||
struct hash_test tests[] = {
|
||||
{ "MD5", "\xfc\x24\x97\x1b\x52\x66\xdc\x46\xef\xe0\xe8\x08\x46\x89\xb6\x88", 16 },
|
||||
{ "SHA1", "\xd8\x85\xb3\x86\xce\xea\x93\xeb\x92\xcd\x7b\x94\xb9\x8d\xc2\x8e"
|
||||
"\x3e\x31\x13\xdd", 20},
|
||||
{ "SHA256", "\x0e\x35\x14\xe7\x15\x7a\x1d\xdd\xea\x11\x78\xd3\x41\xf6\xb9\x3e"
|
||||
"\xa0\x42\x96\x73\x3c\x54\x74\x0b\xfa\x6b\x9e\x29\x59\xad\x69\xd3", 32 },
|
||||
{ "SHA384", "\x2c\xeb\xbd\x4d\x95\xed\xad\x03\xed\x80\xc4\xf3\xa6\x10\x21\xde"
|
||||
"\x40\x69\x54\xed\x42\x70\xb8\x95\xb0\x6f\x01\x1d\x04\xdf\x57\xbc"
|
||||
"\x1d\xb5\x85\xbf\x4f\x03\x88\xd5\x83\x93\xbc\x81\x90\xb0\xa9\x9b", 48 },
|
||||
{ "SHA512", "\x20\xba\xec\xcb\x68\x98\x33\x5b\x70\x26\x63\x13\xe2\xf7\x0e\x67"
|
||||
"\x08\xf3\x77\x4f\xbd\xeb\xc4\xa8\xc5\x94\xe2\x39\x40\x7e\xed\x0b"
|
||||
"\x69\x0e\x18\xa5\xa2\x03\x73\xe7\x1d\x20\x7d\x3f\xc8\x70\x2d\x64"
|
||||
"\x9e\x89\x6d\x20\x6a\x4a\x5a\x46\xe7\x4f\x2c\xf9\x0f\x0a\x54\xdc", 64 },
|
||||
{ "SHA3-224", "\x3b\xa2\x22\x28\xdd\x26\x18\xec\x3b\xb9\x25\x39\x5e\xbd\x94\x25"
|
||||
"\xd4\x20\x8a\x76\x76\xc0\x3c\x5d\x9e\x0a\x06\x46", 28},
|
||||
{ "SHA3-256", "\x26\xd1\x19\xb2\xc1\x64\xc8\xb8\x10\xd8\xa8\x1c\xb6\xa4\x0d\x29"
|
||||
"\x09\xc9\x8e\x2e\x2d\xde\x7a\x74\x8c\x43\x70\xb8\xaa\x0f\x09\x17", 32 },
|
||||
{ "SHA3-384", "\x6a\x64\xb9\x89\x08\x29\xd0\xa7\x4b\x84\xba\xa6\x65\xf5\xe7\x54"
|
||||
"\xe2\x18\x12\xc3\x63\x34\xc6\xba\x26\xf5\x6e\x99\xe2\x54\xcc\x9d"
|
||||
"\x01\x10\x9d\xee\x35\x38\x04\x83\xe5\x71\x70\xd8\xc8\x99\x96\xd8", 48 },
|
||||
{ "SHA3-512", "\xa8\xe3\x2b\x65\x1f\x87\x90\x73\x19\xc8\xa0\x3f\xe3\x85\x60\x3c"
|
||||
"\x39\xfc\xcb\xc1\x29\xe1\x23\x7d\x8b\x56\x54\xe3\x08\x9d\xf9\x74"
|
||||
"\x78\x69\x2e\x3c\x7e\x51\x1e\x9d\xab\x09\xbe\xe7\x6b\x1a\xa1\x22"
|
||||
"\x93\xb1\x2b\x82\x9d\x1e\xcf\xa8\x99\xc5\xec\x7b\x1d\x89\x07\x2b", 64 },
|
||||
{ "RMD128", "\x6f\xd7\x1f\x37\x47\x0f\xbd\x42\x57\xc8\xbb\xee\xba\x65\xf9\x35", 16 },
|
||||
{ "RMD160", "\x7a\x88\xec\xc7\x09\xc5\x65\x34\x11\x24\xe3\xf9\xf7\xa5\xbf\xc6"
|
||||
"\x01\xe2\xc9\x32", 20},
|
||||
{ "RMD256", "\x59\xdf\xd4\xcb\xc9\xbe\x7c\x27\x08\xa7\x23\xf7\xb3\x0c\xf0\x0d"
|
||||
"\xa0\xcf\x5b\x18\x16\x51\x56\x6d\xda\x7b\x87\x24\x9d\x83\x35\xe1", 32 },
|
||||
{ "RMD320", "\x68\x98\x10\xf4\xb6\x79\xb6\x15\xf1\x48\x2d\x73\xd0\x23\x84\x01"
|
||||
"\xbf\xaa\x67\xcf\x1e\x35\x5c\xbf\xe9\xb8\xaf\xe1\xee\x0d\xf0\x6b"
|
||||
"\xe2\x3a\x9a\x3a\xa7\x56\xad\x70", 40},
|
||||
{ "TIGER", "\x1c\xcd\x68\x74\xca\xd6\xd5\x17\xba\x3e\x82\xaf\xbd\x70\xdc\x66"
|
||||
"\x99\xaa\xae\x16\x72\x59\xd1\x64", 24},
|
||||
{ "WHIRLPOOL", "\xe3\xcd\xe6\xbf\xe1\x8c\xe4\x4d\xc8\xb4\xa5\x7c\x36\x8d\xc8\x8a"
|
||||
"\x8b\xad\x52\x24\xc0\x4e\x99\x5b\x7e\x86\x94\x2d\x10\x56\x12\xa3"
|
||||
"\x29\x2a\x65\x0f\x9e\x07\xbc\x15\x21\x14\xe6\x07\xfc\xe6\xb9\x2f"
|
||||
"\x13\xe2\x57\xe9\x0a\xb0\xd2\xf4\xa3\x20\x36\x9c\x88\x92\x8e\xc9", 64 },
|
||||
{ "", "", 0 }
|
||||
};
|
||||
|
||||
unsigned int length;
|
||||
int i, j, hash_id;
|
||||
|
||||
for (i = 0; tests[i].name[0] != '\0'; i++) {
|
||||
hash_id = HSH_GetHashId(tests[i].name);
|
||||
if (hash_id < 0) {
|
||||
TEST_CHECK(strcmp(tests[i].name, "MD5"));
|
||||
#ifdef FEAT_SECHASH
|
||||
TEST_CHECK(strcmp(tests[i].name, "SHA1"));
|
||||
TEST_CHECK(strcmp(tests[i].name, "SHA256"));
|
||||
TEST_CHECK(strcmp(tests[i].name, "SHA384"));
|
||||
TEST_CHECK(strcmp(tests[i].name, "SHA512"));
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
DEBUG_LOG("testing %s", tests[i].name);
|
||||
|
||||
for (j = 0; j <= sizeof (out); j++) {
|
||||
TEST_CHECK(HSH_GetHashId(tests[i].name) == hash_id);
|
||||
TEST_CHECK(HSH_GetHashId("nosuchhash") < 0);
|
||||
|
||||
memset(out, 0, sizeof (out));
|
||||
length = HSH_Hash(hash_id, data1, sizeof (data1) - 1, data2, sizeof (data2) - 1,
|
||||
out, j);
|
||||
|
||||
if (j >= tests[i].length)
|
||||
TEST_CHECK(length == tests[i].length);
|
||||
else
|
||||
TEST_CHECK(length == 0 || length == j);
|
||||
|
||||
TEST_CHECK(!memcmp(out, tests[i].out, length));
|
||||
}
|
||||
|
||||
for (j = 0; j < 10000; j++) {
|
||||
length = HSH_Hash(hash_id, data1, random() % sizeof (data1),
|
||||
random() % 2 ? data2 : NULL, random() % sizeof (data2),
|
||||
out, sizeof (out));
|
||||
TEST_CHECK(length == tests[i].length);
|
||||
}
|
||||
}
|
||||
|
||||
HSH_Finalise();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user