Compare commits

...

95 Commits

Author SHA1 Message Date
Miroslav Lichvar
ebab36e859 doc: update NEWS 2014-09-10 17:00:54 +02:00
Miroslav Lichvar
3988a1e9a8 doc: mention that directives are not case-sensitive 2014-09-10 17:00:54 +02:00
Miroslav Lichvar
949ef3e1dc doc: add section to FAQ on improving accuracy with NTP 2014-09-10 17:00:54 +02:00
Miroslav Lichvar
dd12303276 doc: remove minpoll and maxpoll options from configuration example 2014-09-10 17:00:54 +02:00
Miroslav Lichvar
f1379a6574 sched: fix Clang warning 2014-09-10 17:00:50 +02:00
Miroslav Lichvar
ad58384760 client: describe error when could not open config or keyfile 2014-09-10 11:34:48 +02:00
Miroslav Lichvar
0e786f5907 Ignore measurements around leap second
When current time is within 5 seconds of a leap second, don't accumulate
new samples or update the leap second status to increase the chances of
getting through safely.
2014-09-09 17:08:30 +02:00
Miroslav Lichvar
e1accce498 ntp: print warning 10 years before supported time ends 2014-09-09 17:08:30 +02:00
Miroslav Lichvar
28db0fdde9 configure: check if pkg-config is available
This is needed with some shells to prevent "pkg-config: not found"
errors from being displayed.
2014-09-09 17:08:26 +02:00
Miroslav Lichvar
584bf9382b Fix compiler warnings on NetBSD 2014-09-09 11:48:09 +02:00
Miroslav Lichvar
0168b405a3 examples: add NetworkManager dispatcher script 2014-09-04 17:43:27 +02:00
Miroslav Lichvar
b5e0d76337 examples: add systemd services 2014-09-04 17:30:36 +02:00
Miroslav Lichvar
c924fba4fa examples: add logrotate configuration 2014-09-04 17:28:32 +02:00
Miroslav Lichvar
8ec43a39af Move chrony.spec to examples 2014-09-04 17:25:56 +02:00
Miroslav Lichvar
9f16445464 sys: fix typo in prctl() error message 2014-08-25 17:25:14 +02:00
Miroslav Lichvar
1a795b04ee util: fix compiler warning with 32-bit time_t 2014-08-21 14:06:46 +02:00
Miroslav Lichvar
b862f3e64d Update NEWS 2014-08-21 10:06:09 +02:00
Miroslav Lichvar
4e66b5ce8a ntp: don't stop online burst when sending fails
Don't stop online burst for unreachable sources until sending succeeds.
This is mainly useful with iburst when chronyd is started before the
network is configured.
2014-08-20 16:54:26 +02:00
Miroslav Lichvar
d446950c6a ntp: don't adjust polling interval when sending fails 2014-08-20 16:54:26 +02:00
Miroslav Lichvar
e3c77f9b4b ntp: return with status from functions sending packets 2014-08-20 16:54:26 +02:00
Miroslav Lichvar
090ec985f3 doc: clarify description of -s option 2014-08-20 16:54:26 +02:00
Miroslav Lichvar
e63bd490b0 sched: improve time jump detection
To detect forward time jumps, use a timestamp made before calling
select() instead of the first timeout in the queue. Also, if the timeout
value is modified by select() (e.g. on Linux) use it to get a more
accurate estimate of the elapsed time.
2014-08-20 16:54:26 +02:00
Miroslav Lichvar
badf97d4ba ntp: restart timer when poll interval changes on reset 2014-08-20 16:54:26 +02:00
Miroslav Lichvar
ba283e6b6e ntp: add function to restart transmit timer 2014-08-20 16:54:26 +02:00
Miroslav Lichvar
0bdac2c7b3 sched: make sure scheduler parameter change handler is first
This is needed to allow other handlers to add new timers.
2014-08-20 16:54:26 +02:00
Miroslav Lichvar
58b211d707 local: use common function to invoke parameter change handlers
This was missing in commit b69b648d.
2014-08-19 11:30:32 +02:00
Miroslav Lichvar
068ce237af reference: always update driftfile on exit
This is useful with the new fallback function of the -s option to
restore the system time at which chronyd was previously stopped.
2014-08-19 10:46:35 +02:00
Miroslav Lichvar
a5e9e5d0df rtc: set clock to mtime of driftfile when RTC preinit fails
When the RTC preinit function fails, set the system clock to the time of
the last modification of the driftfile if it's in the future. This makes
the -s option somewhat useful on systems where RTC is not supported or
missing.

This is similar to the functionality implemented in the fake-hwclock
script.
2014-08-19 10:46:35 +02:00
Miroslav Lichvar
e0af8069c1 rtc: don't try to open rtcfile when not set 2014-08-19 10:46:35 +02:00
Miroslav Lichvar
696b05d6e6 rtc: use fscanf() to read coefficients 2014-08-19 10:46:35 +02:00
Miroslav Lichvar
7e1a699616 rtc: return status from preinit function 2014-08-19 10:46:35 +02:00
Miroslav Lichvar
716d73d982 rtc: use LCL functions to read and step system clock 2014-08-19 10:46:35 +02:00
Miroslav Lichvar
38ac081114 rtc: improve accuracy of preinit step 2014-08-19 10:46:35 +02:00
Miroslav Lichvar
5fce101f85 rtc: minor cleanup in RTC_Linux_TimePreInit() 2014-08-19 10:46:35 +02:00
Miroslav Lichvar
c6e064200d rtc: move preinit call to RTC_Initialise() 2014-08-19 10:46:32 +02:00
Miroslav Lichvar
c52e9085d1 rtc: cleanup in error messages 2014-08-18 17:21:26 +02:00
Miroslav Lichvar
d0fb17d70c test: add 115-cmdmontime 2014-08-18 16:06:28 +02:00
Miroslav Lichvar
713153b610 util: update functions converting cmdmon timestamps 2014-08-18 16:06:28 +02:00
Miroslav Lichvar
09d039fba6 cmdmon: convert LOGON timestamp only with LOGON message
Avoid always calling UTI_TimevalNetworkToHost() and make the code more
readable.
2014-08-18 16:06:28 +02:00
Miroslav Lichvar
07f7f28058 sched: check that added file descriptor fits in fd_set 2014-08-15 16:52:37 +02:00
Miroslav Lichvar
a2b40f527d sched: use FD_SETSIZE if defined 2014-08-15 16:51:15 +02:00
Miroslav Lichvar
6d8ffeefd6 test: add 114-presend 2014-08-15 16:51:15 +02:00
Miroslav Lichvar
9ce25bab04 ntp: add debug message for received packet 2014-08-15 16:51:10 +02:00
Miroslav Lichvar
cd5105b1db ntp: use NTP instead of echo for presend
Switch to NTP for presend as the echo service (RFC 862) is rarely
enabled. When presend is active, send an NTP client packet to the
server/peer and ignore the reply.

This also fixes presend with separate client sockets. The destination
port can't be changed on connected sockets, so the echo packet was sent
to the NTP port instead of the echo port.
2014-08-15 16:49:45 +02:00
Miroslav Lichvar
ff4abc69c3 Check for truncated source address when receiving packets 2014-08-15 16:44:43 +02:00
Miroslav Lichvar
192f74f0a1 test: fix check in run script 2014-08-15 11:18:44 +02:00
Miroslav Lichvar
be203d9af0 test: add 008-ntpera 2014-08-15 11:18:44 +02:00
Miroslav Lichvar
f8af299321 test: allow tests to be skipped 2014-08-15 11:18:44 +02:00
Miroslav Lichvar
474b2af1a6 util: add support for other NTP eras
NTP timestamps use only 32 bits to count seconds and the current NTP era
ends in 2036. Add support for converting NTP timestamps from other NTP
eras on systems with 64-bit time_t.

The earliest assumed NTP time is set by the configure script (by default
to 50 years before the date of the build) and earlier NTP timestamps
underflow to the following NTP era.
2014-08-15 11:18:40 +02:00
Miroslav Lichvar
cb88cea3c4 ntp: move packet size asserts to ntp_core 2014-08-15 10:58:52 +02:00
Miroslav Lichvar
fc2892fbb0 util: fix printing of timestamps when time_t is longer than long 2014-08-15 10:58:44 +02:00
Miroslav Lichvar
36b25cbd2b configure: check for 64-bit time_t 2014-08-15 10:58:44 +02:00
Miroslav Lichvar
d18c071849 ntp: use one socket with random port when acquisitionport is 0 2014-08-15 10:58:44 +02:00
Miroslav Lichvar
61b629fdad conf: return port numbers as int 2014-08-15 10:58:44 +02:00
Miroslav Lichvar
29647c8280 cmdmon: allow binding to address that doesn't exist yet 2014-08-15 10:58:44 +02:00
Miroslav Lichvar
97b15cb3ae ntp: allow binding to address that doesn't exist yet 2014-08-15 10:58:43 +02:00
Miroslav Lichvar
f725921dfb ntp: remove disabled code in prepare_socket() 2014-08-15 10:58:43 +02:00
Miroslav Lichvar
a4b4d0c0d8 ntp: bind socket only when port or address was specified
This removes an unnecessary system call when getting new connected
client socket.
2014-08-15 10:58:43 +02:00
Miroslav Lichvar
f59ade7f80 ntp: remove socket reconnecting
As new client socket is now created for each request, there is no need
to reconnect the socket. This is a partial revert of commit 43cca04c.
2014-08-15 10:58:43 +02:00
Miroslav Lichvar
a9b9e7befe ntp: create new socket for each client request
Create a new connected client socket before each request and close it
when a valid reply is received.

This is useful when the network configuration is changed and the client
socket should be reconnected, but the old bound address remains valid
and sendmsg() doesn't return with an error.
2014-08-15 10:58:43 +02:00
Miroslav Lichvar
ead9394a31 Regenerate getdate.c 2014-08-15 10:58:43 +02:00
Miroslav Lichvar
80129fa9ab makefile: regenerate getdate.c when missing 2014-08-14 14:51:24 +02:00
Joachim Wiedorn
18796a3c18 doc: fix small typo 2014-08-13 10:59:13 +02:00
Miroslav Lichvar
f632b6d4cb configure: remove ncurses_lib from first readline test 2014-08-13 10:59:13 +02:00
Miroslav Lichvar
7799e14770 test: increase default time rms limit
This is improves testing reliability with new default corrtimeratio.
2014-08-06 15:46:32 +02:00
Miroslav Lichvar
20aab86e12 test: require latest clknetsim 2014-08-06 15:26:35 +02:00
Miroslav Lichvar
b7766478a6 ntp: close socket when duplicating fails 2014-08-06 15:25:58 +02:00
Miroslav Lichvar
3d57b7a44d refclock: fix compiler warning in SOCK error message 2014-08-05 17:13:08 +02:00
Miroslav Lichvar
51a2b436f4 logging: move exit call from LOG_Message to LOG_FATAL 2014-08-05 15:15:15 +02:00
Miroslav Lichvar
88015081f2 ntp: shorten setsockopt error messages 2014-08-05 12:57:36 +02:00
Miroslav Lichvar
20cc1f6550 ntp: move debug message after sendmsg()
This should reduce the delay before sending the packet when debugging is
enabled.
2014-08-05 12:57:36 +02:00
Miroslav Lichvar
43cca04c33 ntp: reconnect client sockets
With separate client sockets, allow the initial connect() to fail (e.g.
when the network is not reachable yet) and try to connect later when
sending the packet.

Also, reconnect the socket when the local address has changed.
2014-08-05 12:57:36 +02:00
Miroslav Lichvar
17d944c333 doc: mention linuxcaps support in FAQ 2014-07-29 18:10:40 +02:00
Miroslav Lichvar
6789b5165c doc: update FAQ 2014-07-01 14:49:00 +02:00
Miroslav Lichvar
d631d7e81f doc: use iburst option in examples 2014-07-01 12:56:23 +02:00
Miroslav Lichvar
c6245dc616 doc: update NEWS 2014-06-30 17:31:39 +02:00
Miroslav Lichvar
4b36799ce1 doc: update README 2014-06-30 17:20:06 +02:00
Miroslav Lichvar
d26bb9b4eb doc: update initstepslew description 2014-06-30 17:19:40 +02:00
Miroslav Lichvar
698404b02f doc: update FAQ 2014-06-30 16:45:32 +02:00
Miroslav Lichvar
d46d7ad947 Update configuration examples 2014-06-30 14:20:32 +02:00
Miroslav Lichvar
7c6630905d sched: exit with fatal message when there is nothing to do
With cmdport 0 and port 0, it's now possible that there is no descriptor
watched or timer running, i.e. chronyd doing nothing and only waiting to
be terminated. Replace the assertion with LOG_FATAL to exit properly.
2014-06-30 12:54:04 +02:00
Miroslav Lichvar
129aa587c6 cmdmon: don't create socket when cmdport is 0 2014-06-30 12:40:18 +02:00
Miroslav Lichvar
cc1c6c94e3 makefile: remove faq.php rule 2014-06-27 17:26:54 +02:00
Miroslav Lichvar
41266cbaa0 make_release: generate FAQ from chrony.txt 2014-06-27 16:20:10 +02:00
Miroslav Lichvar
fbfd261da6 make_release: generate INSTALL from chrony.txt 2014-06-27 16:20:10 +02:00
Miroslav Lichvar
71602b8ee6 make_release: add testing mode 2014-06-27 16:06:49 +02:00
Miroslav Lichvar
14cae239f6 doc: include faq.txt in main document 2014-06-27 16:06:49 +02:00
Miroslav Lichvar
2e9e309a0d doc: update installation chapter 2014-06-27 13:25:14 +02:00
Miroslav Lichvar
3fba33d5f5 doc: drop porting guide
Most of the information provided in this section looks obsolete.
Comments in the source code should be a better source.
2014-06-27 12:17:03 +02:00
Miroslav Lichvar
77a7162361 util: print timevals for debug messages as numbers 2014-06-27 11:42:22 +02:00
Miroslav Lichvar
75efa5174c Convert disabled log messages to debug or remove them 2014-06-27 10:17:35 +02:00
Miroslav Lichvar
c62afbe77b cmdmon: remove disabled code 2014-06-26 17:19:45 +02:00
Miroslav Lichvar
a6f0688f46 keys: fix determine_hash_delay() declaration 2014-06-26 17:12:32 +02:00
Miroslav Lichvar
5762d33e38 test: require latest clknetsim revision 2014-06-25 17:35:59 +02:00
Miroslav Lichvar
9c6d1c214f ntp: don't set address for sendmsg() with connected sockets 2014-06-25 15:36:14 +02:00
58 changed files with 1681 additions and 1717 deletions

96
INSTALL
View File

@@ -1,96 +0,0 @@
The software is distributed as source code which has to be compiled.
PARTS OF THE SOFTWARE ARE HIGHLY SYSTEM-SPECIFIC AND NON-PORTABLE.
UNLESS YOU ARE RUNNING A SUPPORTED SYSTEM, BE PREPARED FOR SOME
PROGRAMMING!
After unpacking the source code, change directory into it, and type
./configure
This is a shell script that automatically determines the system type.
There is a single optional parameter, --prefix which indicates the
directory tree where the software should be installed. For example,
./configure --prefix=/opt/free
will install the chronyd daemon into /opt/free/sbin and the chronyc
control program into /opt/free/bin. The default value for the prefix
is /usr/local.
The configure script assumes you want to use gcc as your compiler.
If you want to use a different compiler, you can configure this way:
CC=cc CFLAGS=-O ./configure --prefix=/opt/free
for Bourne-family shells, or
setenv CC cc
setenv CFLAGS -O
./configure --prefix=/opt/free
for C-family shells.
If the software cannot (yet) be built on your system, an error message
will be shown. Otherwise, `Makefile' will be generated.
If editline or readline library is available, chronyc will be built
with line editing support. If you don't want this, specify the
--disable-readline flag to configure. Please refer to the chrony.txt
file for more information.
If a 'timepps.h' header is available (e.g. from the LinuxPPS project
(http://linuxpps.org/)), chronyd will be built with PPS API reference
clock driver. If the header is installed in a location that isn't
normally searched by the compiler, you can add it to the searched
locations by setting 'CPPFLAGS' variable to '-I/path/to/timepps'.
Now type
make
to build the programs.
If you want to build the manual in plain text, HTML and info versions, type
make docs
Once the programs have been successfully compiled, they need to be
installed in their target locations. This step normally needs to be
performed by the superuser, and requires the following command to be
entered.
make install
This will install the binaries, plain text manual and manpages.
To install the HTML and info versions of the manual as well, enter the command
make install-docs
If you want chrony to appear in the top level info directory listing, you need
to run the install-info command manually after this step. install-info takes 2
arguments. The first is the path to the chrony.info file you have just
installed. This will be the argument you gave to --prefix when you configured
(/usr/local by default), with /share/info/chrony.info on the end. The second
argument is the location of the file called 'dir'. This will typically be
/usr/share/info/dir. So the typical command line would be
install-info /usr/local/share/info/chrony.info /usr/share/info/dir
Now that the software is successfully installed, the next step is to
set up a configuration file. The contents of this depend on the
network environment in which the computer operates. Typical scenarios
are described in the manual. The simplest case is for a computer with
a permanent Internet connection - suppose you want to use public NTP
servers from the pool.ntp.org project as your time reference. You would
create an /etc/chrony.conf file containing
server 0.pool.ntp.org
server 1.pool.ntp.org
server 2.pool.ntp.org
driftfile /var/lib/chrony/drift
and then run /usr/local/sbin/chronyd.

View File

@@ -85,7 +85,10 @@ clean :
-rm -f *.o *.s chronyc chronyd core *~ chrony.info chrony.html chrony.txt
-rm -rf .deps
getdate.c : ;
getdate.c :
bison -o getdate.c getdate.y
# This can be used to force regeneration of getdate.c
getdate :
bison -o getdate.c getdate.y
@@ -154,10 +157,6 @@ chrony.html : chrony.texi
chrony.info : chrony.texi
makeinfo chrony.texi
# This is only relevant if you're maintaining the website!
faq.php : faq.txt faqgen.pl
perl faqgen.pl < faq.txt > faq.php
.deps:
@mkdir .deps

27
NEWS
View File

@@ -1,3 +1,27 @@
New in version 1.31
===================
Enhancements
------------
* Support operation in other NTP eras (next era begins in 2036),
NTP time is mapped to [-50, +86] years around build date by default
* Restore time from driftfile with -s when RTC is missing/unsupported
* Close connected client sockets when not waiting for reply
* Use one client socket with random port when acquisitionport is 0
* Use NTP packets instead of UDP echo for presend
* Don't adjust polling interval when sending fails
* Allow binding to addresses that don't exist yet
* Ignore measurements around leap second
* Improve detection of unexpected time jumps
* Include example of logrotate configuration, systemd services and
NetworkManager dispatcher script
Bug fixes
---------
* Reconnect client sockets for each request to follow changes
in network configuration automatically
* Restart timer when polling interval is changed on reset
New in version 1.30
===================
@@ -17,7 +41,7 @@ Enhancements
* Try to detect unexpected forward time jumps and reset state
* Exit with non-zero code when maxchange limit is reached
* Improve makestep to not start and stop slew unnecessarily
* Change default corrtimeratio to 3.0 to improve frequency error
* Change default corrtimeratio to 3.0 to improve frequency accuracy
* Announce leap second only on last day of June and December
* Use separate connected client sockets for each NTP server
* Remove separate NTP implementation used for initstepslew
@@ -26,6 +50,7 @@ Enhancements
* Print warning when source is added with unknown key
* Take leap second in PPS refclock from locked source
* Make reading of RTC for initial trim more reliable
* Don't create cmdmon sockets when cmdport is 0
* Add configure option to set default user to drop root privileges
* Add configure option to compile with debug messages
* Print debug messages when -d is used more than once

6
README
View File

@@ -2,6 +2,7 @@ This is the README for chrony.
What is chrony?
===============
Chrony is a pair of programs for maintaining the accuracy of computer
clocks.
@@ -61,7 +62,7 @@ Chrony can be successfully built and run on
Any other system will require a porting exercise. You would need to
start from one of the existing system-specific drivers and look into
the quirks of certain system calls and the kernel on your target
system. (This is described in the manual).
system.
How do I set it up?
===================
@@ -94,8 +95,7 @@ by sending mail with the subject "subscribe" to
chrony-announce-request@chrony.tuxfamily.org
These messages will be copied to chrony-users (see below). New versions
are announced also on Freshmeat (http://freshmeat.net/).
These messages will be copied to chrony-users (see below).
How can I get support for chrony?
and where can I discuss new features, possible bugs etc?

View File

@@ -22,16 +22,19 @@ as a minimum
However, you will probably want to include some of the other directives
described in detail in the documentation supplied with the distribution
(\fIchrony.txt\fR and \fIchrony.texi\fR). The following directives will be
particularly useful : `driftfile', `commandkey', `keyfile'. The smallest
useful configuration file would look something like
(\fIchrony.txt\fR and \fIchrony.texi\fR). The following directives may be
particularly useful : `driftfile', `generatecommandkey', `keyfile', `makestep'.
Also, the `iburst' server option is useful to speed up the initial
synchronization. The smallest useful configuration file would look something
like
server a.b.c
server d.e.f
server g.h.i
server a.b.c iburst
server d.e.f iburst
server g.h.i iburst
keyfile @SYSCONFDIR@/chrony.keys
commandkey 1
generatecommandkey
driftfile @CHRONYVARDIR@/drift
makestep 10 3
.SH "SEE ALSO"

View File

@@ -35,7 +35,7 @@ Copyright @copyright{} 2009-2014 Miroslav Lichvar
* Installation:: How to compile and install the software
* Typical scenarios:: How to configure the software for some common cases
* Usage reference:: Reference manual
* Porting guide:: Hints to help with porting the software
* FAQ:: Answers to some common questions about chrony
* GPL:: The GNU General Public License
@end menu
@c }}}
@@ -353,7 +353,7 @@ the directory tree where the software should be installed. For example,
@end example
will install the @code{chronyd} daemon into /opt/free/sbin and the
chronyc control program into /opt/free/bin. The default value for the
@code{chronyc} control program into /opt/free/bin. The default value for the
prefix is /usr/local.
The configure script assumes you want to use gcc as your compiler.
@@ -381,7 +381,7 @@ editing support. If you don't want this, specify the --disable-readline flag
to configure. Please refer to @pxref{line editing support} for more information.
If a @file{timepps.h} header is available (e.g. from the
@uref{http://linuxpps.org/, LinuxPPS project}), chronyd will be built with PPS API
@uref{http://linuxpps.org/, LinuxPPS project}), @code{chronyd} will be built with PPS API
reference clock driver. If the header is installed in a location that isn't
normally searched by the compiler, you can add it to the searched locations by
setting @code{CPPFLAGS} variable to @code{-I/path/to/timepps}.
@@ -431,9 +431,19 @@ install-info /usr/local/share/info/chrony.info /usr/share/info/dir
@end example
Now that the software is successfully installed, the next step is to
set up a configuration file. The contents of this depend on the
network environment in which the computer operates. Typical scenarios
are described in the following section of the document.
set up a configuration file. The default location of the file
is @file{@SYSCONFDIR@/chrony.conf}. Suppose you want to use public NTP
servers from the pool.ntp.org project as your time reference. A
minimal useful configuration file could be
@example
server 0.pool.ntp.org iburst
server 1.pool.ntp.org iburst
server 2.pool.ntp.org iburst
makestep 10 3
@end example
Then, @code{chronyd} can be run.
@c }}}
@menu
* line editing support:: If libraries are in a non-standard place
@@ -526,8 +536,8 @@ the files to the intended final locations.
@node Typical scenarios
@chapter Typical operating scenarios
@menu
* Computers on the net:: Your computer is permanently on the Internet (or on
a private network with NTP servers)
* Computers on the net:: Your computer is on the Internet most of the time
(or on a private network with NTP servers)
* Infrequent connection:: You connect to the Internet sometimes (e.g. via a modem)
* Isolated networks:: You have an isolated network with no reference clocks
* Dial-up home PCs:: Additional considerations if you turn your computer off
@@ -539,9 +549,9 @@ the files to the intended final locations.
@node Computers on the net
@section Computers connected to the internet
In this section we discuss how to configure chrony for computers that
have permanent connections to the internet (or to any network
containing true NTP servers which ultimately derive their time from a
reference clock).
are connected to the Internet (or to any network containing true NTP
servers which ultimately derive their time from a reference clock)
permanently or most of the time.
To operate in this mode, you will need to know the names of the NTP
server machines you wish to use. You may be able to find names of
@@ -576,17 +586,17 @@ server g.h.i
@end example
However, you will probably want to include some of the other directives
described later. The following directives will be particularly useful :
@code{driftfile}, @code{commandkey}, @code{keyfile}. The smallest
useful configuration file would look something like
described later. The @code{driftfile} and @code{makestep} directives may be
particularly useful. Also, the @code{iburst} server option is useful to speed
up the initial synchronization. The smallest useful configuration file would
look something like
@example
server a.b.c
server d.e.f
server g.h.i
keyfile @SYSCONFDIR@/chrony.keys
commandkey 1
server a.b.c iburst
server d.e.f iburst
server g.h.i iburst
driftfile @CHRONYVARDIR@/drift
makestep 10 3
@end example
@c }}}
@c {{{ S:Infrequent connection
@@ -639,21 +649,11 @@ in an offline state, and that they should not be contacted until @code{chronyd}
receives notification that the link to the internet is present.
In order to notify @code{chronyd} of the presence of the link, you will need to
be able to log in to it with the program chronyc. To do this, @code{chronyd}
needs to be configured with an administrator password. To set up an
administrator password, you can create a file @file{@SYSCONFDIR@/chrony.keys}
containing a single line
@example
1 ALongAndRandomPassword
@end example
and add the following line to @file{@SYSCONFDIR@/chrony.conf} (the order of the
lines does not matter)
@example
commandkey 1
@end example
be able to log in to it with the program @code{chronyc}. To do this,
@code{chronyd} needs to be configured with an administrator password. The
password is read from a file specified by the @code{keyfile} directive. The
@code{generatecommandkey} directive can be used to generate a random password
automatically on the first @code{chronyd} start.
The smallest useful configuration file would look something like
@@ -662,8 +662,9 @@ server a.b.c offline
server d.e.f offline
server g.h.i offline
keyfile @SYSCONFDIR@/chrony.keys
commandkey 1
generatecommandkey
driftfile @CHRONYVARDIR@/drift
makestep 10 3
@end example
The next section describes how to tell @code{chronyd} when the internet link
@@ -728,7 +729,7 @@ master's address is 192.168.169.170)
@example
driftfile @CHRONYVARDIR@/drift
commandkey 25
generatecommandkey
keyfile @SYSCONFDIR@/chrony.keys
initstepslew 10 client1 client3 client6
local stratum 8
@@ -745,7 +746,7 @@ driftfile @CHRONYVARDIR@/drift
logdir /var/log/chrony
log measurements statistics tracking
keyfile @SYSCONFDIR@/chrony.keys
commandkey 24
generatecommandkey
local stratum 10
initstepslew 20 master
allow 192.168.169.170
@@ -872,14 +873,15 @@ For the @file{@SYSCONFDIR@/chrony.conf} file, the following can be used as an
example.
@example
server 0.pool.ntp.org minpoll 5 maxpoll 10 maxdelay 0.4 offline
server 1.pool.ntp.org minpoll 5 maxpoll 10 maxdelay 0.4 offline
server 2.pool.ntp.org minpoll 5 maxpoll 10 maxdelay 0.4 offline
server 0.pool.ntp.org maxdelay 0.4 offline
server 1.pool.ntp.org maxdelay 0.4 offline
server 2.pool.ntp.org maxdelay 0.4 offline
logdir /var/log/chrony
log statistics measurements tracking
driftfile @CHRONYVARDIR@/drift
keyfile @SYSCONFDIR@/chrony.keys
commandkey 25
generatecommandkey
makestep 10 3
maxupdateskew 100.0
dumponexit
dumpdir @CHRONYVARDIR@
@@ -1005,7 +1007,7 @@ used.
When this option is used, the @code{initstepslew} directive and the
@code{makestep} directive used with a positive limit will be ignored.
This option is useful when restarting @code{chronyd} and can be used
in conjuction with the `-r' option.
in conjunction with the `-r' option.
@item -s
This option will set the system clock from the computer's real-time
@@ -1016,18 +1018,20 @@ Support for real-time clocks is limited at present - the criteria are
described in the section on the @code{rtcfile} directive (@pxref{rtcfile
directive}).
If @code{chronyd} cannot support the real time clock on your computer,
this option cannot be used and a warning message will be logged to the
syslog.
If used in conjunction with the `-r' flag, @code{chronyd} will attempt
to preserve the old samples after setting the system clock from the real
time clock. This can be used to allow @code{chronyd} to perform long
time clock (RTC). This can be used to allow @code{chronyd} to perform long
term averaging of the gain or loss rate across system reboots, and is
useful for dial-up systems that are shut down when not in use. For this
to work well, it relies on @code{chronyd} having been able to determine
accurate statistics for the difference between the real time clock and
accurate statistics for the difference between the RTC and
system clock last time the computer was on.
If @code{chronyd} doesn't support the RTC on your computer or there is no RTC
installed, the system clock will be set with this option forward to the time of
the last modification of the drift file (specified by the @code{driftfile}
directive) to restore the system time at which @code{chronyd} was previously
stopped.
@item -u <user>
This option sets the name of the user to which will @code{chronyd} switch to
drop root privileges if compiled with Linux capabilities support (default
@@ -1110,7 +1114,8 @@ specified with a command line option.
Each command in the configuration file is placed on a separate line.
The following sections describe each of the commands in turn. The
directives can occur in any order in the file.
directives can occur in any order in the file and they are not
case-sensitive.
The configuration commands can also be specified directly on the
@code{chronyd} command line, each argument is parsed as a line and
@@ -1197,7 +1202,8 @@ By default, @code{chronyd} uses a separate client socket for each configured
server and their source port is chosen arbitrarily by the operating system.
However, you can use the @code{acquisitionport} directive to explicitly specify
a port and use only one socket (per IPv4/IPv6 address family) for all
configured servers. This may be useful for getting through firewalls.
configured servers. This may be useful for getting through firewalls. If set
to 0, the source port of the socket will be chosen arbitrarily.
It may be set to the same port as used by the NTP server (@pxref{port
directive}) to use only one socket for all NTP packets.
@@ -1438,7 +1444,8 @@ There is also a @code{cmddeny all} directive with similar behaviour to the
The @code{cmdport} directive allows the port that is used for run-time
command and monitoring (via the program @code{chronyc}) to be altered
from its default (323/udp).
from its default (323/udp). If set to 0, @code{chronyd} will not open the
port, this is useful to disable the @code{chronyc} access completely.
An example shows the syntax
@@ -1687,7 +1694,7 @@ include @SYSCONFDIR@/chrony/local.conf
@c {{{ initstepslew
@node initstepslew directive
@subsection initstepslew
In normal operation, @code{chronyd} always slews the time when it needs to
In normal operation, @code{chronyd} slews the time when it needs to
adjust the system clock. For example, to correct a system clock which
is 1 second slow, @code{chronyd} slightly increases the amount by which the
system clock is advanced on each clock interrupt, until the error is
@@ -1719,8 +1726,7 @@ servers as arguments. A maximum of 8 will be used. Each of the servers
is rapidly polled several times, and a majority voting mechanism used to
find the most likely range of system clock error that is present. A
step (or slew) is applied to the system clock to correct this error.
@code{chronyd} then enters its normal operating mode (where only slews are
used).
@code{chronyd} then enters its normal operating mode.
An example of use of the command is
@@ -1741,6 +1747,15 @@ below), the master can be set up with an @code{initstepslew} directive
which references some or all of the slaves. Then, if the master machine
has to be rebooted, the slaves can be relied on to 'flywheel' the time
for the master.
The @code{initstepslew} directive is functionally similar to a
combination of the @code{makestep} and @code{server} directives with
the @code{iburst} option. The main difference is that the
@code{initstepslew} servers are used only before normal operation
begins and that the foreground @code{chronyd} process waits for
@code{initstepslew} to finish before exiting. This is useful to
prevent programs started in the boot sequence after @code{chronyd}
from reading the clock before it's stepped.
@c }}}
@c {{{ keyfile
@node keyfile directive
@@ -2824,18 +2839,18 @@ of the machines.
In order to avoid this problem, the @code{presend} option may be used.
It takes a single integer argument, which is the smallest polling
interval for which a pair of packets will be exchanged between the
client and the server prior to the actual measurement being initiated by
the client. For example, with the following option included in a
interval for which an extra pair of NTP packets will be exchanged
between the client and the server prior to the actual measurement.
For example, with the following option included in a
@code{server} directive :
@example
presend 9
@end example
when the polling interval is 512 seconds or more, a UDP echo datagram
will be sent to the server a short time (currently 4 seconds) before the
NTP client mode datagram.
when the polling interval is 512 seconds or more, an extra NTP client
packet will be sent to the server a short time (currently 4 seconds)
before making the actual measurement.
@item key
The NTP protocol supports the inclusion of checksums in the packets, to
@@ -4478,120 +4493,315 @@ command is issued.
@c }}}
@c }}}
@c }}}
@c {{{ apx: porting guide
@node Porting guide
@appendix Porting guide
@c {{{ section top
This appendix discusses issues that have arisen in writing the
system-specific parts of the existing ports. This will provide useful
information for those attempting to write ports to other systems.
@c {{{ Ch:FAQ
@node FAQ
@chapter Frequently asked questions
@c {{{ Chapter top
@menu
* System driver files:: What needs to go in a driver file for a
particular type of system
* Quirks of particular systems:: Problem areas that have been found on ports
already written.
* Administrative issues::
* Chrony compared to other programs::
* Configuration issues::
* Computer is not synchronising::
* Issues with chronyc::
* Real-time clock issues::
* Microsoft Windows::
* NTP-specific issues::
* Linux-specific issues::
* Solaris-specific issues::
@end menu
@c }}}
@c {{{ S:system driver files
@node System driver files
@section System driver files
The system specific parts of the software are contained in files with
names like @code{sys_linux.c}.
@c {{{ S:Administrative issues
@node Administrative issues
@section Administrative issues
The following functions are required in a system driver file:
@subsection Where can I get chrony source code?
Tarballs are available via the @code{Download} link on the chrony web site.
For the current development from the developers' version control system see the
@code{Git} link on the web site.
@enumerate
@item
A function to read the current frequency
@item
A function to set the current frequency
@item
A function to slew the system time by a specified delta
@item
A function to step the system time by a specified delta
@item
A function to work out the error at a particular time between the
system's clock and @code{chronyd's} estimate of real time. (This is required
because some systems have to track real time by making the system time
follow it in a 'sawtooth' fashion).
@end enumerate
@subsection Are there any packaged versions of chrony?
We are aware of packages for Arch, Debian, Fedora, Gentoo, Mandriva, Slackware,
Ubuntu, FreeBSD and NetBSD. We are not involved with how these are built or
distributed.
The @dfn{frequency} is the rate at which the system gains or loses time,
measured relative to the system when running uncompensated.
@subsection Where is the home page?
It is currently at
@uref{http://chrony.tuxfamily.org, http://chrony.tuxfamily.org}.
@subsection Is there a mailing list?
Yes, it's currently at @email{chrony-users@@chrony.tuxfamily.org}. There is a
low-volume list called chrony-announce which is just for announcements of new
releases or similar matters of high importance. You can join the lists by
sending a message with the subject subscribe to
@email{chrony-users-request@@chrony.tuxfamily.org} or
@email{chrony-announce-request@@chrony.tuxfamily.org} respectively.
For those who want to contribute to the development of chrony, there is a
developers' mailing list. You can subscribe by sending mail with the subject
subscribe to @email{chrony-dev-request@@chrony.tuxfamily.org}.
@subsection What licence is applied to chrony?
Starting from version 1.15, chrony is licensed under the GNU General Public
License, Version 2. Versions prior to 1.15 were licensed under a custom
BSD-like license.
@c }}}
@c {{{ system quirks
@node Quirks of particular systems
@section Quirks of particular systems
@c {{{ section top
These sections describe quirks in each system type that needed to be
investigated to port the software to each system type.
@c {{{ S:Chrony compared to other programs
@node Chrony compared to other programs
@section Chrony compared to other programs
@subsection How does chrony compare to ntpd?
Chrony can usually synchronise the system clock faster and with better time
accuracy, but it doesn't implement all NTP features, e.g. broadcast/multicast
mode, or authentication based on public-key cryptography. For a more detailed
comparison, see section @code{Comparison with ntpd} in the manual.
If your computer connects to the 'net only for few minutes at a time, you turn
your Linux computer off or suspend it frequently, the clock is not very stable
(e.g. it is a virtual machine), or you want to use NTP on an isolated network
with no hardware clocks in sight, chrony will probably work much better for
you.
The original reason chrony was written was that ntpd (called xntpd at the
time) could not to do anything sensible on a PC which was connected to
the 'net only for about 5 minutes once or twice a day, mainly to
upload/download email and news. The requirements were
@itemize @bullet
@item slew the time to correct it when going online and NTP servers become
visible
@item determine the rate at which the computer gains or loses time and use this
information to keep it reasonably correct between connects to the 'net. This
has to be done using a method that does not care about the intermittent
availability of the references or the fact the computer is turned off between
groups of measurements.
@item maintain the time across reboots, by working out the error and drift rate
of the computer's real-time clock and using this information to set the system
clock correctly at boot up.
@end itemize
Also, when working with isolated networks with no true time references at all
ntpd was found to give no help with managing the local clock's gain/loss rate
on the NTP master node (which was set from watch). Some automated support was
added to chrony to deal with this.
@menu
* Linux porting quirks::
* Solaris 2.5 porting quirks::
* SunOS 4.1.4 porting quirks::
@end menu
@c }}}
@c {{{ linux
@node Linux porting quirks
@subsection Linux
The following quirks have been found in developing the Linux port.
@c {{{ S:Configuration issues
@node Configuration issues
@section Configuration issues
@enumerate 1
@item
In order to avoid floating point arithmetic, the kernel uses shifting
and adding to approximate a scaling of 100/128. This approximation
implies that the frequency set via the @code{adjtimex()} system call is
not the frequency that is actually obtained. The method of
approximation varies between kernel versions and must be determined by
examining the kernel source. An inverse factor must be included in the
driver to compensate.
@item
In some kernel versions, an @code{adjtimex()} system call with the flags
bits all zeroed will return the amount of offset still to be corrected.
In others (e.g. the 2.0 series beyond 2.0.32), the offset must be
changed in order to get the old offset returned (similar to
@code{adjtime()} on other systems).
@subsection I have several computers on a LAN. Should be all clients of an external server?
The best configuration is usually to make one computer the master, with the
others as clients of it. Add a @code{local} directive to the master's
chrony.conf file. This configuration will be better because
@itemize @bullet
@item the load on the external connection is less
@item the load on the external NTP server(s) is less
@item if your external connection goes down, the computers on the LAN will
maintain a common time with each other.
@end itemize
@subsection Must I specify servers by IP address if DNS is not available on chronyd start?
No. Starting from version 1.25, @code{chronyd} will keep trying to resolve the
hostnames specified in the @code{server} and @code{peer} directives in
increasing intervals until it succeeds. The @code{online} command can be
issued from @code{chronyc} to try to resolve them immediately.
@subsection How can I make chronyd more secure?
If you don't need to serve time to NTP clients, you can add @code{port 0} to
the @file{chrony.conf} file to disable the NTP server/peer sockets and prevent
NTP requests from reaching @code{chronyd}.
If you don't need to use @code{chronyc} remotely, you can add the following
directives to the configuration file to bind the command sockets to the
loopback interface
@example
bindcmdaddress 127.0.0.1
bindcmdaddress ::1
@end example
If you don't need to use @code{chronyc} at all, you can disable the command
sockets by adding @code{cmdport 0} to the configuration file.
On Linux, if @code{chronyd} is compiled with support for Linux capabilities
(available in the libcap library), you can specify an unprivileged user with
the `-u' option or @code{user} directive in the @file{chrony.conf} file to drop
root privileges after start. The configure option @code{--with-user} can be
used to drop the privileges by default.
@subsection How can I improve the accuracy of the system clock with NTP sources?
Select NTP servers that are well synchronised, stable and close to your network.
It's better to use more than one server, three or four is usually recommended as
the minimum, so @code{chronyd} can detect falsetickers and combine measurements
from multiple sources.
There are also useful options which can be set in the @code{server} directive,
they are @code{minpoll}, @code{maxpoll}, @code{polltarget}, @code{maxdelay},
@code{maxdelayratio} and @code{maxdelaydevratio}.
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 suitable for public NTP servers, which normally don't allow
too frequent polling, but if you run your own NTP servers or have permission to
poll the servers frequently, setting the options for shorter polling intervals
may significantly improve the accuracy of the system clock.
The optimal polling interval depends on many factors, this includes the ratio
between the wander of the clock and the network jitter (sometimes expressed in
NTP documents as the Allan intercept), the temperature sensitivity of the
crystal oscillator and the maximum rate of change of the temperature. An
example of the directive for a server located in the same LAN could be
@example
server ntp.local minpoll 2 maxpoll 4 polltarget 30
@end example
The maxdelay options are useful to ignore measurements with larger delay (e.g.
due to congestion in the network) and improve the stability of the
synchronisation. The @code{maxdelaydevratio} option could be added to the
previous example
@example
server ntp.local minpoll 2 maxpoll 4 polltarget 30 maxdelaydevratio 2
@end example
@end enumerate
@c }}}
@c {{{ solaris 2.5
@node Solaris 2.5 porting quirks
@subsection Solaris 2.5
@c {{{ S:Computer is not synchronising
@node Computer is not synchronising
@section Computer is not synchronising
The following quirks have been found in developing the Solaris port.
This is the most common problem. There are a number of reasons, see the
following questions.
@enumerate 1
@item
The @code{adjtime()} system call with a zero argument does not cancel an
adjustment that is in progress - it just reports the remaining
adjustment.
@item
The @code{settimeofday()} system call only observes the seconds part of
the argument - any fractional seconds part is lost.
second.
@item
The kernel variable @code{dosynctodr} has to be set to zero, otherwise
the system clock is periodically reset to the real-time clock.
@end enumerate
@subsection Behind a firewall?
If there is a firewall between you and the NTP server you're trying to use,
the packets may be blocked. Try using a tool like wireshark or tcpdump to see
if you're getting responses from the server. If you have an external modem,
see if the receive light blinks straight after the transmit light (when the
link is quiet apart from the NTP traffic.) Try adding @code{log measurements}
to the @file{chrony.conf} file and look in the measurements.log file after
chrony has been running for a short period. See if any measurements appear.
@subsection Do you have a non-permanent (i.e. intermittent) Internet connection?
Check that you're using chronyc's @code{online} and @code{offline} commands
appropriately. Again, check in measurements.log to see if you're getting any
data back from the server.
@subsection In measurements.log, do the '7' and '8' flag columns always show zero?
Do you have a @code{local stratum X} directive in the @file{chrony.conf} file? If X
is lower than the stratum of the server you're trying to use, this situation
will arise. You should always make X quite high (e.g. 10) in this directive.
@c }}}
@c {{{ sunos 4.1.4
@node SunOS 4.1.4 porting quirks
@subsection SunOS 4.1.4
The following quirks have been found in developing the SunOS port.
@c {{{ S:Issues with chronyc
@node Issues with chronyc
@section Issues with chronyc
@enumerate 1
@item
The @code{adjtime()} system call truncates its argument to a multiple of
the system's @code{tickadj} variable. (@code{chronyd} sets that to 100,
giving a 1 part in 100 slewing capability for correcting offsets.)
@item
The kernel variable @code{dosynctodr} has to be set to zero, otherwise
the system clock is periodically reset to the real-time clock.
@end enumerate
@subsection I keep getting the error @code{506 Cannot talk to daemon}
Make sure that the @file{chrony.conf} file (on the computer where
@code{chronyd} is running) has a @code{cmdallow} entry for the computer you are
running @code{chronyc} on. This isn't necessary for localhost.
Perhaps @code{chronyd} is not running. Try using the ps command (e.g. on
Linux, 'ps -auxw') to see if it's running. Or try 'netstat -a' and see if the
ports 123/udp and 323/udp are listening. If @code{chronyd} is not running, you
may have a problem with the way you are trying to start it (e.g. at boot time).
Perhaps you have a firewall set up in a way that blocks packets on port
323/udp. You need to amend the firewall configuration in this case.
@subsection Is the chronyc<->chronyd protocol documented anywhere?
Only by the source code :-) See cmdmon.c (@code{chronyd} side) and client.c
(@code{chronyc} side).
@c }}}
@c {{{ S:Real-time clock issues
@node Real-time clock issues
@section Real-time clock issues
@subsection What is the real-time clock (RTC)?
This is the clock which keeps the time even when your computer is turned off.
It works with 1 second resolution. @code{chronyd} can monitor the rate at
which the real-time clock gains or loses time, and compensate for it when you
set the system time from it at the next reboot. See the documentation for
details.
@subsection I want to use chronyd's real-time clock support. Must I disable hwclock?
The hwclock program is often set-up by default in the boot and shutdown scripts
with many Linux installations. If you want to use chronyd's real-time clock
support, the important thing is to disable hwclock in the shutdown procedure.
If you don't, it will over-write the RTC with a new value, unknown to
@code{chronyd}. At the next reboot, @code{chronyd} will compensate this (wrong)
time with its estimate of how far the RTC has drifted whilst the power was off,
giving a meaningless initial system time.
There is no need to remove hwclock from the boot process, as long as
@code{chronyd} is started after it has run.
@subsection I just keep getting the '513 RTC driver not running' message
For the real time clock support to work, you need the following three things
@itemize @bullet
@item a kernel that is supported (e.g. 2.2 onwards)
@item enhanced RTC support compiled into the kernel
@item an @code{rtcfile} directive in your chrony.conf file
@end itemize
@c }}}
@c {{{ S:Microsoft Windows
@node Microsoft Windows
@section Microsoft Windows
@subsection Does chrony support Windows?
No. The @code{chronyc} program (the command-line client used for configuring
@code{chronyd} while it is running) has been successfully built and run under
Cygwin in the past. @code{chronyd} is not portable, because part of it is very
system-dependent. It needs adapting to work with Windows' equivalent of the
adjtimex() call, and it needs to be made to work as an NT service.
@subsection Are there any plans to support Windows?
We have no plans to do this. Anyone is welcome to pick this work up and
contribute it back to the project.
@c }}}
@c {{{ S:NTP-specific issues
@node NTP-specific issues
@section NTP-specific issues
@subsection Can chrony be driven from broadcast NTP servers?
No, this NTP mode is not implemented yet.
@subsection Can chronyd transmit broadcast NTP packets (e.g. to synchronise other computers on a private LAN)?
Yes. Starting from version 1.17, chrony has this capability.
@subsection Can chrony keep the system clock a fixed offset away from real time?
This is not possible as the program currently stands.
@subsection What happens if the network connection is dropped without using chronyc's 'offline' command first?
In this case @code{chronyd} will keep trying to access the server(s) that it
thinks are online. Eventually it will decide that they are unreachable and no
longer consider itself synchronised to them. If you have other computers on
your LAN accessing the computer that is affected this way, they too will become
'unsynchronised', unless you have the 'local' directive set up on the master
computer.
The 'auto_offline' option to the 'server' entry in the chrony.conf file may be
useful to avoid this situation.
@c }}}
@c {{{ S:Linux-specific issues
@node Linux-specific issues
@section Linux-specific issues
@subsection I get "Could not open /dev/rtc, Device or resource busy" in my syslog file
Some other program running on the system may be using the device.
@c }}}
@c {{{ S:Solaris-specific issues
@node Solaris-specific issues
@section Solaris-specific issues
@subsection On Solaris 2.8, I get an error message about not being able to open kvm to change dosynctodr
(The dosynctodr variable controls whether Solaris couples the equivalent of its
BIOS clock into its system clock at regular intervals). The Solaris port of
chrony was developed in the Solaris 2.5 era. Some aspect of the Solaris kernel
has changed which prevents the same technique working. We no longer have root
access to any Solaris machines to work on this, and we are reliant on somebody
developing the patch and testing it.
@c }}}
@c }}}
@c {{{ apx:GNU General Public License

View File

@@ -76,7 +76,7 @@ should not be used.
.B \-R
When this option is used, the \fIinitstepslew\fR directive and the
\fImakestep\fR directive used with a positive limit will be ignored. This
option is useful when restarting \fBchronyd\fR and can be used in conjuction
option is useful when restarting \fBchronyd\fR and can be used in conjunction
with the \fB-r\fR option.
.TP
.B \-s
@@ -88,19 +88,20 @@ Support for real-time clocks is limited at present - the criteria
are described in the section on the \fIrtcfile\fR directive in the
documentation supplied with the distribution.
If \fBchronyd\fR cannot support the real time clock on your computer,
this option cannot be used and a warning message will be logged to
the syslog.
If used in conjunction with the \fB-r\fR flag, \fBchronyd\fR will attempt
to preserve the old samples after setting the system clock from
the real time clock. This can be used to allow \fBchronyd\fR to
the real time clock (RTC). This can be used to allow \fBchronyd\fR to
perform long term averaging of the gain or loss rate across system
reboots, and is useful for dial-up systems that are shut down when
not in use. For this to work well, it relies on \fBchronyd\fR having
been able to determine accurate statistics for the difference
between the real time clock and system clock last time the
computer was on.
between the RTC and system clock last time the computer was on.
If \fBchronyd\fR doesn't support the RTC on your computer or there is no RTC
installed, the system clock will be set with this option forward to the time of
the last modification of the drift file (specified by the \fIdriftfile\fR
directive) to restore the system time at which \fBchronyd\fR was previously
stopped.
.TP
\fB\-u\fR \fIuser\fR
This option sets the name of the user to which will \fBchronyd\fR switch to

View File

@@ -2616,7 +2616,7 @@ authenticate_from_config(const char *filename)
in = fopen(filename, "r");
if (!in) {
fprintf(stderr, "Could not open file %s\n", filename);
fprintf(stderr, "Could not open file %s : %s\n", filename, strerror(errno));
return 0;
}
@@ -2641,7 +2641,7 @@ authenticate_from_config(const char *filename)
in = fopen(keyfile, "r");
if (!in) {
fprintf(stderr, "Could not open keyfile %s\n", keyfile);
fprintf(stderr, "Could not open keyfile %s : %s\n", keyfile, strerror(errno));
return 0;
}

110
cmdmon.c
View File

@@ -171,22 +171,19 @@ static ADF_AuthTable access_auth_table;
/* ================================================== */
/* Forward prototypes */
static int prepare_socket(int family);
static void read_from_cmd_socket(void *anything);
/* ================================================== */
static int
prepare_socket(int family)
prepare_socket(int family, int port_number)
{
int port_number, sock_fd;
int sock_fd;
socklen_t my_addr_len;
union sockaddr_in46 my_addr;
IPAddr bind_address;
int on_off = 1;
port_number = CNF_GetCommandPort();
sock_fd = socket(family, SOCK_DGRAM, 0);
if (sock_fd < 0) {
LOG(LOGS_ERR, LOGF_CmdMon, "Could not open %s command socket : %s",
@@ -202,6 +199,14 @@ prepare_socket(int family)
LOG(LOGS_ERR, LOGF_CmdMon, "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");
}
#endif
#ifdef HAVE_IPV6
if (family == AF_INET6) {
#ifdef IPV6_V6ONLY
@@ -265,7 +270,7 @@ prepare_socket(int family)
void
CAM_Initialise(int family)
{
int i;
int i, port_number;
assert(!initialised);
initialised = 1;
@@ -293,18 +298,20 @@ CAM_Initialise(int family)
free_replies = NULL;
kept_replies.next = NULL;
if (family == IPADDR_UNSPEC || family == IPADDR_INET4)
sock_fd4 = prepare_socket(AF_INET);
port_number = CNF_GetCommandPort();
if (port_number && (family == IPADDR_UNSPEC || family == IPADDR_INET4))
sock_fd4 = prepare_socket(AF_INET, port_number);
else
sock_fd4 = -1;
#ifdef HAVE_IPV6
if (family == IPADDR_UNSPEC || family == IPADDR_INET6)
sock_fd6 = prepare_socket(AF_INET6);
if (port_number && (family == IPADDR_UNSPEC || family == IPADDR_INET6))
sock_fd6 = prepare_socket(AF_INET6, port_number);
else
sock_fd6 = -1;
#endif
if (sock_fd4 < 0
if (port_number && sock_fd4 < 0
#ifdef HAVE_IPV6
&& sock_fd6 < 0
#endif
@@ -667,46 +674,6 @@ token_acknowledged(unsigned long token, struct timeval *now)
/* ================================================== */
#if 0
/* These two routines are not legal if the program is operating as a daemon, since
stderr is no longer open */
static void
print_command_packet(CMD_Request *pkt, int length)
{
unsigned char *x;
int i;
x = (unsigned char *) pkt;
for (i=0; i<length; i++) {
fprintf(stderr, "%02x ", x[i]);
if (i%16 == 15) {
fprintf(stderr, "\n");
}
}
fprintf(stderr, "\n");
}
/* ================================================== */
static void
print_reply_packet(CMD_Reply *pkt)
{
unsigned char *x;
int i;
x = (unsigned char *) pkt;
for (i=0; i<sizeof(CMD_Reply); i++) {
fprintf(stderr, "%02x ", x[i]);
if (i%16 == 15) {
fprintf(stderr, "\n");
}
}
fprintf(stderr, "\n");
}
#endif
/* ================================================== */
static void
transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to, int auth_len)
{
@@ -1629,20 +1596,6 @@ handle_reselect(CMD_Request *rx_message, CMD_Reply *tx_message)
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
#if 0
/* ================================================== */
static void
handle_(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
}
#endif
/* ================================================== */
/* Read a packet and process it */
@@ -1691,6 +1644,9 @@ read_from_cmd_socket(void *anything)
return;
}
if (from_length > sizeof (where_from))
LOG_FATAL(LOGF_CmdMon, "Truncated source address");
read_length = status;
LCL_ReadRawTime(&now);
@@ -1887,20 +1843,22 @@ read_from_cmd_socket(void *anything)
}
valid_ts = 0;
issue_token = 0;
if (auth_ok) {
struct timeval ts;
UTI_TimevalNetworkToHost(&rx_message.data.logon.ts, &ts);
if ((utoken_ok && token_ok) ||
((ntohl(rx_message.utoken) == SPECIAL_UTOKEN) &&
(rx_command == REQ_LOGON) &&
(valid_ts = ts_is_unique_and_not_stale(&ts, &now))))
if (utoken_ok && token_ok) {
issue_token = 1;
else
issue_token = 0;
} else {
issue_token = 0;
} else if (rx_command == REQ_LOGON &&
ntohl(rx_message.utoken) == SPECIAL_UTOKEN) {
struct timeval ts;
UTI_TimevalNetworkToHost(&rx_message.data.logon.ts, &ts);
valid_ts = ts_is_unique_and_not_stale(&ts, &now);
if (valid_ts) {
issue_token = 1;
}
}
}
authenticated = auth_ok & utoken_ok & token_ok;

View File

@@ -204,7 +204,7 @@ CPS_NormalizeLine(char *line)
/* Remove white-space at beginning and replace white-spaces with space char */
for (p = q = line; *p; p++) {
if (isspace(*p)) {
if (isspace((unsigned char)*p)) {
if (!space)
*q++ = ' ';
space = 1;
@@ -234,15 +234,15 @@ CPS_SplitWord(char *line)
char *p = line, *q = line;
/* Skip white-space before the word */
while (*q && isspace(*q))
while (*q && isspace((unsigned char)*q))
q++;
/* Move the word to the beginning */
while (*q && !isspace(*q))
while (*q && !isspace((unsigned char)*q))
*p++ = *q++;
/* Find the next word */
while (*q && isspace(*q))
while (*q && isspace((unsigned char)*q))
q++;
*p = '\0';

6
conf.c
View File

@@ -79,7 +79,7 @@ static void parse_tempcomp(char *);
static int restarted = 0;
static int generate_command_key = 0;
static char *rtc_device = "/dev/rtc";
static int acquisition_port = 0; /* 0 means let kernel choose port */
static int acquisition_port = -1;
static int ntp_port = 123;
static char *keys_file = NULL;
static char *drift_file = NULL;
@@ -1212,7 +1212,7 @@ CNF_AddBroadcasts(void)
/* ================================================== */
unsigned short
int
CNF_GetNTPPort(void)
{
return ntp_port;
@@ -1220,7 +1220,7 @@ CNF_GetNTPPort(void)
/* ================================================== */
unsigned short
int
CNF_GetAcquisitionPort(void)
{
return acquisition_port;

4
conf.h
View File

@@ -42,8 +42,8 @@ extern void CNF_AddSources(void);
extern void CNF_AddBroadcasts(void);
extern void CNF_AddRefclocks(void);
extern unsigned short CNF_GetAcquisitionPort(void);
extern unsigned short CNF_GetNTPPort(void);
extern int CNF_GetAcquisitionPort(void);
extern int CNF_GetNTPPort(void);
extern char *CNF_GetDriftFile(void);
extern char *CNF_GetLogDir(void);
extern char *CNF_GetDumpDir(void);

55
configure vendored
View File

@@ -114,6 +114,8 @@ For better control, use the options below.
--disable-linuxcaps Disable Linux capabilities support
--disable-asyncdns Disable asynchronous name resolving
--disable-forcednsretry Don't retry on permanent DNS error
--with-ntp-era=SECONDS Specify earliest assumed NTP time in seconds
since 1970-01-01 [50*365 days ago]
--with-user=USER Specify default chronyd user [root]
--with-sendmail=PATH Path to sendmail binary [/usr/lib/sendmail]
--enable-debug Enable debugging support
@@ -158,6 +160,13 @@ add_def () {
fi
}
#}}}
#{{{ pkg_config
pkg_config () {
type pkg-config > /dev/null 2> /dev/null || return 1
pkg-config $@ 2> /dev/null
}
#}}}
# ======================================================================
@@ -194,6 +203,7 @@ try_setsched=0
try_lockmem=0
feat_asyncdns=1
feat_forcednsretry=1
ntp_era_split=""
default_user="root"
mail_program="/usr/lib/sendmail"
@@ -275,6 +285,9 @@ do
--disable-forcednsretry)
feat_forcednsretry=0
;;
--with-ntp-era=* )
ntp_era_split=`echo $option | sed -e 's/^.*=//;'`
;;
--with-user=* )
default_user=`echo $option | sed -e 's/^.*=//;'`
;;
@@ -376,6 +389,40 @@ case $SYSTEM in
;;
esac
if test_code '64-bit time_t' 'time.h' '' '' '
char x[sizeof(time_t) > 4 ? 1 : -1] = {0};
return x[0];'
then
add_def HAVE_LONG_TIME_T 1
if [ "x$ntp_era_split" != "x" ]; then
split_seconds=$ntp_era_split
split_days=0
else
split_seconds=`date '+%s'`
if [ "x$split_seconds" = "" ]; then
echo "Could not get current time, --with-ntp-era option is needed"
exit 1
fi
split_days=$((50 * 365))
fi
add_def NTP_ERA_SPLIT "(${split_seconds}LL - $split_days * 24 * 3600)"
date_format='+%Y-%m-%dT%H:%M:%SZ'
# Print the full NTP interval if a suitable date is found
if [ "x`date -u -d '1970-01-01 UTC 9 days ago 5 seconds 3 seconds' \
$date_format 2> /dev/null`" = "x1969-12-23T00:00:08Z" ]
then
time1="`date -u -d "1970-01-01 UTC $split_days days ago $split_seconds seconds" \
$date_format`"
time2="`date -u -d "1970-01-01 UTC $split_days days ago $split_seconds seconds 4294967296 seconds" \
$date_format`"
echo "NTP time mapped to $time1/$time2"
fi
fi
MATHCODE='return (int) pow(2.0, log(sqrt((double)argc)));'
if test_code 'math' 'math.h' '' '' "$MATHCODE"; then
LIBS=""
@@ -535,12 +582,12 @@ if [ $feat_readline = "1" ]; then
if [ "x$READLINE_LINK" = "x" ] && [ $try_readline = "1" ]; then
if test_code readline 'stdio.h readline/readline.h readline/history.h' \
"$readline_inc" "$readline_lib $ncurses_lib -lreadline" \
"$readline_inc" "$readline_lib -lreadline" \
'add_history(readline("prompt"));'
then
add_def FEAT_READLINE
READLINE_COMPILE="$readline_inc"
READLINE_LINK="$readline_lib $ncurses_lib -lreadline"
READLINE_LINK="$readline_lib -lreadline"
fi
fi
@@ -564,8 +611,8 @@ HASH_COMPILE=""
HASH_LINK=""
if [ $try_nss = "1" ]; then
test_cflags="`pkg-config --cflags nss 2> /dev/null`"
test_link="`pkg-config --libs-only-L nss 2> /dev/null` -lfreebl3"
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' \
"$test_cflags" "$test_link" \
'NSSLOWHASH_Begin(NSSLOWHASH_NewContext(NSSLOW_Init(), HASH_AlgSHA512));'

View File

@@ -0,0 +1,17 @@
[Unit]
Description=Wait for chrony to synchronize system clock
After=chronyd.service
Requires=chronyd.service
Before=time-sync.target
Wants=time-sync.target
[Service]
Type=oneshot
# Wait up to ~10 minutes for chronyd to synchronize and the remaining
# clock correction to be less than 0.1 seconds
ExecStart=/usr/bin/chronyc waitsync 60 0.1
RemainAfterExit=yes
StandardOutput=null
[Install]
WantedBy=multi-user.target

View File

@@ -106,6 +106,9 @@ keyfile /etc/chrony.keys
commandkey 1
# With this directive a random password will be generated automatically.
generatecommandkey
# chronyd can save the measurement history for the servers to files when
# it it exits. This is useful in 2 situations:
#

View File

@@ -0,0 +1,8 @@
/var/log/chrony/*.log {
missingok
nocreate
sharedscripts
postrotate
/usr/bin/chronyc -a cyclelogs > /dev/null 2>&1 || true
endscript
}

View File

@@ -0,0 +1,17 @@
#!/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.
export LC_ALL=C
if [ "$2" = "up" ]; then
/sbin/ip route list dev "$1" | grep -q '^default' &&
/usr/bin/chronyc -a online > /dev/null 2>&1
fi
if [ "$2" = "down" ]; then
/sbin/ip route list | grep -q '^default' ||
/usr/bin/chronyc -a offline > /dev/null 2>&1
fi
exit 0

13
examples/chronyd.service Normal file
View File

@@ -0,0 +1,13 @@
[Unit]
Description=NTP client/server
After=ntpdate.service sntp.service ntpd.service
Conflicts=ntpd.service systemd-timesyncd.service
[Service]
Type=forking
PIDFile=/var/run/chronyd.pid
EnvironmentFile=-/etc/sysconfig/chronyd
ExecStart=/usr/sbin/chronyd $OPTIONS
[Install]
WantedBy=multi-user.target

268
faq.txt
View File

@@ -1,268 +0,0 @@
@@PROLOGUE
<html>
<head>
<title>Frequently asked questions</title>
<meta name="description" content="Chrony FAQ (frequently asked questions)">
<meta name="keywords" content="chrony,network time protocol,NTP,RFC 1305,dial-up connection,real time clock,RTC,Linux,FAQ,frequently asked questns">
<?php
$root = ".";
include "$root/styles.php";
?>
</head>
<body>
<?php
include 'main_banner.php';
include 'header.php';
?>
<?php pretty_h1("Introduction") ?>
<p>
This is a set of questions and answers to common problems and issues.
<p>
As we receive more emails about the software, we will add new questions
to this page.
<hr>
<p>
The developers can be reached via the chrony-dev mailing list. See
<a href="#question_1.4">question 1.4.</a> for details.
<hr>
<br clear=all>
@@ENDPROLOGUE
S: Administrative issues
Q: Where can I get chrony source code?
Tarballs are available via the <b>Download</b> link on the Chrony
Web site. For the current development from the developers' version control
system see the <b>Git</b> link on the Web site.
Q: Are there any packaged versions of chrony?
We are aware of packages for Debian, Fedora, Gentoo, Mandriva, Slackware,
and Ubuntu. We are not involved with how these are built or distributed.
Q: Where is the home page?
It is currently at <a href="http://chrony.tuxfamily.org/">http://chrony.tuxfamily.org/</a>.
Q: Is there a mailing list?
Yes, it's currently at chrony-users@chrony.tuxfamily.org. There is a low-volume
list called chrony-announce which is just for announcements of new releases or
similar matters of high importance. You can join the lists by sending a
message with the subject subscribe to <a href="mailto:chrony-users-request@chrony.tuxfamily.org">chrony-users-request@chrony.tuxfamily.org</a> or
<a href="mailto:chrony-announce-request@chrony.tuxfamily.org">chrony-announce-request@chrony.tuxfamily.org</a> respectively.
For those who want to contribute to the development of chrony, there is a
developers' mailing list. You can subscribe by sending mail with the
subject subscribe to
<a href="mailto:chrony-dev-request@chrony.tuxfamily.org">chrony-dev-request@chrony.tuxfamily.org</a>.
Q: What licence is applied to chrony?
Starting from version 1.15, chrony is licensed under the GNU General Public
License, Version 2. Versions prior to 1.15 were licensed under a custom BSD-like
license.
S: Chrony compared to other programs
Q: How does chrony compare to xntpd?
If your computer is permenently connected, or connected for long periods (that
is, for the several hours it takes xntpd to settle down), or you need to
support hardware reference clocks to your computer, then xntpd will work fine.
Apart from not supporting hardware clocks, chrony will work fine too.
If your computer connects to the 'net for 5 minutes once a day (or something
like that), or you turn your Linux computer off when you're not using
it, or you want to use NTP on an isolated network with no hardware clocks in
sight, chrony will work much better for you.
The reason I wrote chrony was that I could not get xntpd to do
anything sensible on my PC at home, which is connected to the 'net for
about 5 minutes once or twice a day, mainly to upload/download email
and news. Nowadays it is also turned off for 22-23 hours a day, when
not in use. I wanted a program which would :
- slew the time to correct it when I go online and NTP servers become visible
- determine the rate at which the computer gains or loses time and use this
information to keep it reasonably correct between connects to the 'net. This
has to be done using a method that does not care about the intermittent
availability of the references or the fact the computer is turned off between
groups of measurements..
- maintain the time across reboots, by working out the error and drift rate of
the computer's real-time clock and using this information to set the system
clock correctly at boot up. (In the last few months, it became impossible for
me to leave my computer powered permanently.)
Also, when working with isolated networks with no true time references
at all, I found xntpd gave me no help with managing the local clock's
gain/loss rate on the NTP master node (which I set from my watch). I
added some automated support in chrony to deal with this.
S: Selection of NTP servers
Q: I have several computers on a LAN. Should I make one the master, or make them all clients of an external server?
I think the best configuration is to make one computer the master, with the
others as clients of it. Add a 'local' directive to the master's chrony.conf
file. This configuration will be better because
* the load on the external connection is less
* the load on the external NTP server(s) is less
* if your external connection goes down, the computers on the LAN will maintain
a common time with each other.
S: My computer is not synchronising.
This is the most common problem. There are a number of reasons, see the
following questions.
Q: Behind a firewall?
If there is a firewall between you and the NTP server you're trying to use,
the packets may be blocked. Try using a tool like etherfind or tcpdump to see
if you're getting responses from the server. If you have an external modem,
see if the receive light blinks straight after the transmit light (when the
link is quiet apart from the NTP traffic.) Try adding 'log measurements' to
the chrony.conf file and look in the measurements.log file after chrony has
been running for a short period. See if any measurements appear.
Most people run chronyd on the firewall itself, to avoid all issues of UDP
packet forwarding and/or masquerading.
Q: Do you have a non-permanant (i.e. intermittent) Internet connection?
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.
Q: In measurements.log, do the '7' and '8' flag columns always show zero?
Do you have a 'local stratum X' directive in the chrony.conf file? If X is
lower than the stratum of the server you're trying to use, this situation will
arise. You should always make X quite high (e.g. 10) in this directive.
S: Issues with chronyc
Q: I keep getting the error '506 Cannot talk to daemon'.
Make sure that the chrony.conf file (on the computer where chronyd is running)
has a 'cmdallow' entry for the computer you are running chronyc on. This
isn't necessary for localhost.
Perhaps chronyd is not running. Try using the ps command (e.g. on Linux, 'ps
-auxw') to see if it's running. Or try 'netstat -a' and see if the ports
123/udp and 323/udp are listening. If chronyd is not running, you may have a
problem with the way you are trying to start it (e.g. at boot time).
Perhaps you have a firewall set up in a way that blocks packets on port
323/udp. You need to amend the firewall configuration in this case.
Q: Is the chronyc&lt;-&gt;chronyd protocol documented anywhere?
Only by the source code :-) See cmdmon.c (chronyd side) and client.c (chronyc
side).
S: Real-time clock issues.
Q: What is the real-time clock (RTC)?
This is the clock which keeps the time even when your computer is turned off.
It works with 1 second resolution. chronyd can monitor the rate at which the
real-time clock gains or loses time, and compensate for it when you set the
system time from it at the next reboot. See the documentation for details.
Q: I want to use chronyd's real-time clock support. Must I disable hwclock?
The hwclock program is often set-up by default in the boot and shutdown scripts
with many Linux installations. If you want to use chronyd's real-time clock
support, the important thing is to disable hwclock in the <b>shutdown</b>
procedure. If you don't, it will over-write the RTC with a new value, unknown
to chronyd. At the next reboot, chronyd will compensate this (wrong) time with
its estimate of how far the RTC has drifted whilst the power was off, giving a
meaningless initial system time.
There is no need to remove hwclock from the boot process, as long as chronyd is
started after it has run.
Q: I just keep getting the '513 RTC driver not running' message
For the real time clock support to work, you need the following three things:
* a kernel that is supported (e.g. 2.2 onwards)
* enhanced RTC support compiled into the kernel
* an 'rtcfile' directive in your chrony.conf file.
S: Microsoft Windows
Q: Does chrony support Windows?
No. The chronyc program (the command-line client used for configuring
chronyd while it is running) has been successfully built and run under Cygwin
in the past. chronyd is not portable, because part of it is very
system-dependent. It needs adapting to work with Windows' equivalent of the
adjtimex() call, and it needs to be made to work as an NT service.
Q: Are there any plans to support Windows?
We have no plans to do this. Anyone is welcome to pick this work up and
contribute it back to the project.
Q: What alternative NTP clients are there for Windows?
Some of the names we've seen mentioned are
- Automachron
- NetTime (nettime.sourceforge.net)
S: NTP-specific issues
Q: Can chrony be driven from broadcast NTP servers?
No. I remember looking at how they worked when I was first writing chrony.
Since the 'target market' then was dial-up systems, broadcast packets were not
relevant so I didn't bother working out how to deal with the complexities of
doing the delay estimation.
I no longer have root access to a LAN environment to develop and test broadcast
server support. Neither have I the time to work on this. I would be very
happy to accept a patch from anyone who can develop, test and debug the
necessary changes!
Q: Can chronyd transmit broadcast NTP packets (e.g. to synchronise other computers on a private LAN)?
Yes. Starting from version 1.17, chrony has this capability.
Q: Can chrony keep the system clock a fixed offset away from real time?
I have not experimented much, but I don't believe this would be possible as
the program currently stands.
Q: What happens if the network connection is dropped without using chronyc's 'offline' command first?
In this case chronyd will keep trying to access the server(s) that it thinks
are online. Eventually it will decide that they are unreachable and no longer
consider itself synchronised to them. If you have other computers on your LAN
accessing the computer that is affected this way, they too will become
'unsynchronised', unless you have the 'local' directive set up on the master
computer.
The 'auto_offline' option to the 'server' entry in the chrony.conf file may be
useful to avoid this situation.
S: Development
Q: Can I get the source via git from anywhere?
Yes. See the Git link at <a
href="http://chrony.tuxfamily.org/">http://chrony.tuxfamily.org</a> for
information.
S: Linux-specific issues
Q: Why does the source code include kernel header files?
The program needs to see the definitions of structures used to interact with
the real time clock (via /dev/rtc) and with the adjtimex() system call. Sadly
this has led to a number of compilation problems with newer kernels which have
been increasingly hard to fix in a way that makes the code compilable on all
Linux kernel versions. Hopefully
the situation will not deteriorate further with future kernel versions.
Q: I get "Could not open /dev/rtc, Device or resource busy" in my syslog file.
Check that you haven't accidentally got two copies of chronyd running (perhaps
defined in different start-up scripts.)
S: Solaris-specific issues
Q: On Solaris 2.8, I get an error message about not being able to open kvm to change dosynctodr.
(The dosynctodr variable controls whether Solaris couples the equivalent of its
BIOS clock into its system clock at regular intervals). The Solaris port of
chrony was developed in the Solaris 2.5 era. Some aspect of the Solaris kernel
has changed which prevents the same technique working. I no longer have root
access to any Solaris machines to work on this, and am reliant on somebody
developing the patch and testing it. A good starting point would be to see if
xntpd has been modified to work for Solaris 2.8.
@@EPILOGUE
<hr>
Back to
<a href="mailto:rc@rc0.org.uk?subject=chrony">the author</a>'s
<a href="http://www.rc0.org.uk/">main page</a>
</body>
</html>
@@ENDEPILOGUE

140
faqgen.pl
View File

@@ -1,140 +0,0 @@
#!/usr/bin/env perl
# $Header
# Copyright 2001 Richard P. Curnow
# LICENCE
# A script to generate an HTML FAQ page from a text input file. The input is assumed to consist of the following:
# Lines starting with 'S:'. These introduce sections.
# Lines starting with 'Q:'. These are the topics of questions.
# Body text (either as an introduction to the sections, or as answers to the questions.
# The body text is set as pre-formatted.
$| = 1;
@prologue = ();
@epilogue = ();
@sections=(); # section titles
@sect_text=(); # introductory text in sections
@questions=(); # questions in sections
@answers=(); # answers to questions
$sn = -1;
$had_q = 0;
#{{{ Parse input
while (<>) {
if (m/\@\@PROLOG/o) {
while (<>) {
last if (m/^\@\@ENDPROLOG/);
push (@prologue, $_);
}
} elsif (m/\@\@EPILOG/o) {
while (<>) {
last if (m/^\@\@ENDEPILOG/);
push (@epilogue, $_);
}
} elsif (m/^[sS]:[ \t]*(.*)$/) {
chomp;
$qn = -1;
++$sn;
$sections[$sn] = &guard($1);
$sect_text[$sn] = "";
$questions[$sn] = [ ];
$answers[$sn] = [ ];
$had_q = 0;
} elsif (/^[qQ]:[ \t]*(.*)$/) {
chomp;
die unless ($sn >= 0);
++$qn;
$questions[$sn]->[$qn] = &guard($1);
$had_q = 1;
} else {
if ($had_q) {
if ($qn >= 0) {
$answers[$sn]->[$qn] .= $_;
}
} else {
if ($sect_text[$sn] ne "" || $_ !~ /^\s*$/) {
$sect_text[$sn] .= $_;
}
}
}
}
#}}}
# Emit file header
if ($#prologue >= 0) {
print @prologue;
} else {
print <<EOF;
<html>
<head>
<title>
Chrony Frequently Asked Questions
</title>
</head>
<body>
<font face=\"arial,helvetica\" size=+4><b>Table of contents</b></font>
EOF
}
# Emit table of contents
print "<ul>\n";
for $sn (0 .. $#sections) {
print "<b><li> <a href=\"#section_".($sn+1)."\">".($sn+1).".</a> ".$sections[$sn]."</b>\n";
print " <ul>\n";
for $qn (0 .. $#{$questions[$sn]}) {
$sq = ($sn+1).".".($qn+1);
print " <li> <a href=\"#question_".$sq."\">".$sq.".</a> ".$questions[$sn]->[$qn]."\n";
#print " <li> ".$sq.". ".$questions[$sn]->[$qn]."\n";
}
print " </ul>\n";
}
print "</ul>\n";
# Emit main sections
for $sn (0 .. $#sections) {
print "<hr>\n";
print "<a name=section_".($sn+1).">\n";
#print "<b><font size=+2 face=\"arial,helvetica\">".($sn+1).". ".$sections[$sn]."</font></b>\n";
print "<?php pretty_h2(\"".($sn+1).". ".$sections[$sn]."\"); ?>\n";
if ($sect_text[$sn] ne "") {
print "<pre>\n";
print $sect_text[$sn];
print "</pre>\n";
}
for $qn (0 .. $#{$questions[$sn]}) {
$sq = ($sn+1).".".($qn+1);
print "<p>\n";
print "<a name=question_".$sq.">\n";
print "<font size=+1 face=\"arial,helvetica\">".$sq.". ".$questions[$sn]->[$qn]."</font>\n";
print "<pre>\n";
print $answers[$sn]->[$qn];
print "</pre>\n";
}
}
# Print footer
if ($#epilogue >= 0) {
print @epilogue;
} else {
print <<EOF;
</body>
</html>
EOF
}
#{{{ sub guard {
sub guard {
# Hide wierd tags etc
my ($x) = @_;
return $x;
}
#}}}

864
getdate.c

File diff suppressed because it is too large Load Diff

View File

@@ -711,7 +711,7 @@ LookupWord (buff)
/* Make it lowercase. */
for (p = buff; *p; p++)
if (ISUPPER ((unsigned char) *p))
*p = tolower (*p);
*p = tolower ((unsigned char) *p);
if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0)
{

12
keys.c
View File

@@ -142,7 +142,7 @@ KEY_Finalise(void)
/* ================================================== */
static int
determine_hash_delay(int key_id)
determine_hash_delay(unsigned long key_id)
{
NTP_Packet pkt;
struct timeval before, after;
@@ -162,12 +162,12 @@ determine_hash_delay(int key_id)
}
}
#if 0
LOG(LOGS_INFO, LOGF_Keys, "authentication delay for key %lu: %d useconds", key_id, min_usecs);
#endif
/* Add on a bit extra to allow for copying, conversions etc */
return min_usecs + (min_usecs >> 4);
min_usecs += min_usecs >> 4;
DEBUG_LOG(LOGF_Keys, "authentication delay for key %lu: %ld useconds", key_id, min_usecs);
return min_usecs;
}
/* ================================================== */

15
local.c
View File

@@ -252,6 +252,14 @@ void LCL_RemoveParameterChangeHandler(LCL_ParameterChangeHandler handler, void *
/* ================================================== */
int
LCL_IsFirstParameterChangeHandler(LCL_ParameterChangeHandler handler)
{
return change_list.next->handler == handler;
}
/* ================================================== */
static void
invoke_parameter_change_handlers(struct timeval *raw, struct timeval *cooked,
double dfreq, double doffset,
@@ -493,7 +501,6 @@ LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked,
void
LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
{
ChangeListEntry *ptr;
struct timeval raw, cooked;
double old_freq_ppm;
@@ -519,11 +526,7 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
(*drv_accrue_offset)(doffset, corr_rate);
/* Dispatch to all handlers */
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
(ptr->handler)(&raw, &cooked, dfreq, doffset, 0, ptr->anything);
}
invoke_parameter_change_handlers(&raw, &cooked, dfreq, doffset, LCL_ChangeAdjust);
}
/* ================================================== */

View File

@@ -92,6 +92,9 @@ extern void LCL_AddParameterChangeHandler(LCL_ParameterChangeHandler handler, vo
/* Remove a handler */
extern void LCL_RemoveParameterChangeHandler(LCL_ParameterChangeHandler, void *anything);
/* Check if a handler is invoked first when dispatching */
extern int LCL_IsFirstParameterChangeHandler(LCL_ParameterChangeHandler handler);
/* Function type for handlers to be called back when an indeterminate
offset is introduced into the local time. This situation occurs
when the frequency must be adjusted to effect a clock slew and

View File

@@ -187,9 +187,6 @@ void LOG_Message(LOG_Severity severity, LOG_Facility facility,
log_message(1, severity, buf);
}
}
exit(1);
break;
default:
assert(0);

View File

@@ -29,6 +29,8 @@
#ifndef GOT_LOGGING_H
#define GOT_LOGGING_H
#include "sysincl.h"
/* Flag indicating whether debug messages are logged */
extern int log_debug_enabled;
@@ -49,7 +51,11 @@ extern int log_debug_enabled;
LOG_Message(LOGS_DEBUG, facility, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__); \
} while (0)
#define LOG(severity, facility, ...) LOG_Message(severity, facility, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__)
#define LOG_FATAL(facility, ...) LOG_Message(LOGS_FATAL, facility, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__)
#define LOG_FATAL(facility, ...) \
do { \
LOG_Message(LOGS_FATAL, facility, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__); \
exit(1); \
} while (0)
/* Definition of severity */
typedef enum {

6
main.c
View File

@@ -452,16 +452,12 @@ int main
* be done *AFTER* the daemon-creation fork() */
write_lockfile();
if (do_init_rtc) {
RTC_TimePreInit();
}
LCL_Initialise();
SCH_Initialise();
SYS_Initialise();
NIO_Initialise(address_family);
CAM_Initialise(address_family);
RTC_Initialise();
RTC_Initialise(do_init_rtc);
SRC_Initialise();
RCL_Initialise();
KEY_Initialise();

View File

@@ -9,6 +9,7 @@ if [ $# -ne 1 ]; then
fi
version=$1
tag=$version
subdir=chrony-${version}
mandate=$(date +'%B %Y')
@@ -21,18 +22,22 @@ fi
[ -d RELEASES ] || mkdir RELEASES
git tag -s $version || exit 1
rm -rf RELEASES/$subdir
git archive --format=tar --prefix=RELEASES/${subdir}/ $version | \
if [ $version != test ]; then
git tag -s $tag || exit 1
else
tag=HEAD
fi
git archive --format=tar --prefix=RELEASES/${subdir}/ $tag | \
tar xf - || exit 1
cd RELEASES/$subdir || exit 1
echo $version > version.txt
sed -e "s%@@VERSION@@%${version}%" < chrony.spec.sample > chrony.spec
sed -i -e "s%@@VERSION@@%${version}%" examples/chrony.spec
for m in chrony.1 chronyc.1.in chrony.conf.5.in chronyd.8.in; do
sed -e "s%@VERSION@%${version}%;s%@MAN_DATE@%${mandate}%" \
@@ -45,10 +50,29 @@ mv chrony.txt chrony.txt_
make distclean
mv chrony.txt_ chrony.txt
rm -f config.h config.log faqgen.pl make_release chrony.spec.sample .gitignore
awk '/^[1-9] Installation$/{p=1}
/^[1-9]\.. Support for line editing/{exit}; p' chrony.txt | \
tail -n +4 > INSTALL
if [ $(wc -l < INSTALL) -gt 100 -o $(wc -l < INSTALL) -lt 85 ]; then
echo "INSTALL generated incorrectly?"
exit 3
fi
awk '/^[1-9] Frequently asked questions$/{p=1}
/^Appendix A GNU General Public License$/{exit}; p' chrony.txt | \
tail -n +4 | sed 's/^[1-9]\.\([1-9]\)/\1/' | sed 's/^----/--/' | \
sed 's/^====/==/' > FAQ
if [ $(wc -l < FAQ) -gt 400 -o $(wc -l < FAQ) -lt 200 ]; then
echo "FAQ generated incorrectly?"
exit 3
fi
rm -f config.h config.log make_release .gitignore
cd ..
tar cv --owner root --group root $subdir | gzip -9 > ${subdir}.tar.gz
gpg -b -a -o ${subdir}-tar-gz-asc.txt ${subdir}.tar.gz
[ $version != test ] && \
gpg -b -a -o ${subdir}-tar-gz-asc.txt ${subdir}.tar.gz

View File

@@ -85,8 +85,8 @@ struct NCR_Instance_Record {
received packets) */
int presend_minpoll; /* If the current polling interval is
at least this, an echo datagram
will be send some time before every
at least this, an extra client packet
will be send some time before normal
transmit. This ensures that both
us and the server/peer have an ARP
entry for each other ready, which
@@ -191,7 +191,7 @@ struct NCR_Instance_Record {
#define IBURST_GOOD_SAMPLES 4
#define IBURST_TOTAL_SAMPLES SOURCE_REACH_BITS
/* Time to wait after sending echo to 'warm up' link */
/* Time to wait after sending packet to 'warm up' link */
#define WARM_UP_DELAY 4.0
/* The NTP protocol version that we support */
@@ -229,12 +229,79 @@ static ADF_AuthTable access_auth_table;
/* Forward prototypes */
static void transmit_timeout(void *arg);
static double get_transmit_delay(NCR_Instance inst, int on_tx, double last_tx);
/* ================================================== */
static void
do_size_checks(void)
{
/* Assertions to check the sizes of certain data types
and the positions of certain record fields */
/* Check that certain invariants are true */
assert(sizeof(NTP_int32) == 4);
assert(sizeof(NTP_int64) == 8);
/* Check offsets of all fields in the NTP packet format */
assert(offsetof(NTP_Packet, lvm) == 0);
assert(offsetof(NTP_Packet, stratum) == 1);
assert(offsetof(NTP_Packet, poll) == 2);
assert(offsetof(NTP_Packet, precision) == 3);
assert(offsetof(NTP_Packet, root_delay) == 4);
assert(offsetof(NTP_Packet, root_dispersion) == 8);
assert(offsetof(NTP_Packet, reference_id) == 12);
assert(offsetof(NTP_Packet, reference_ts) == 16);
assert(offsetof(NTP_Packet, originate_ts) == 24);
assert(offsetof(NTP_Packet, receive_ts) == 32);
assert(offsetof(NTP_Packet, transmit_ts) == 40);
}
/* ================================================== */
static void
do_time_checks(void)
{
struct timeval now;
time_t warning_advance = 3600 * 24 * 365 * 10; /* 10 years */
#ifdef HAVE_LONG_TIME_T
/* Check that time before NTP_ERA_SPLIT underflows correctly */
struct timeval tv1 = {NTP_ERA_SPLIT, 1}, tv2 = {NTP_ERA_SPLIT - 1, 1};
NTP_int64 ntv1, ntv2;
int r;
UTI_TimevalToInt64(&tv1, &ntv1, 0);
UTI_TimevalToInt64(&tv2, &ntv2, 0);
UTI_Int64ToTimeval(&ntv1, &tv1);
UTI_Int64ToTimeval(&ntv2, &tv2);
r = tv1.tv_sec == NTP_ERA_SPLIT &&
tv1.tv_sec + (1ULL << 32) - 1 == tv2.tv_sec;
assert(r);
LCL_ReadRawTime(&now);
if (tv2.tv_sec - now.tv_sec < warning_advance)
LOG(LOGS_WARN, LOGF_NtpCore, "Assumed NTP time ends at %s!",
UTI_TimeToLogForm(tv2.tv_sec));
#else
LCL_ReadRawTime(&now);
if (now.tv_sec > 0x7fffffff - warning_advance)
LOG(LOGS_WARN, LOGF_NtpCore, "System time ends at %s!",
UTI_TimeToLogForm(0x7fffffff));
#endif
}
/* ================================================== */
void
NCR_Initialise(void)
{
do_size_checks();
do_time_checks();
logfileid = CNF_GetLogMeasurements() ? LOG_FileOpen("measurements",
" Date (UTC) Time IP Address L St 1234 abc 5678 LP RP Score Offset Peer del. Peer disp. Root del. Root disp.")
: -1;
@@ -254,7 +321,7 @@ NCR_Finalise(void)
/* ================================================== */
static void
start_initial_timeout(NCR_Instance inst)
restart_timeout(NCR_Instance inst, double delay)
{
/* Check if we can transmit */
if (inst->tx_suspended) {
@@ -267,24 +334,36 @@ start_initial_timeout(NCR_Instance inst)
SCH_RemoveTimeout(inst->timeout_id);
/* Start new timer for transmission */
inst->timeout_id = SCH_AddTimeoutInClass(INITIAL_DELAY, SAMPLING_SEPARATION,
inst->timeout_id = SCH_AddTimeoutInClass(delay, SAMPLING_SEPARATION,
SAMPLING_RANDOMNESS,
SCH_NtpSamplingClass,
transmit_timeout, (void *)inst);
inst->timer_running = 1;
}
/* ================================================== */
static void
start_initial_timeout(NCR_Instance inst)
{
if (!inst->timer_running) {
/* This will be the first transmission after mode change */
inst->timer_running = 1;
/* Mark source active */
SRC_SetActive(inst->source);
}
/* Open client socket */
if (inst->mode == MODE_CLIENT) {
assert(inst->local_addr.sock_fd == INVALID_SOCK_FD);
inst->local_addr.sock_fd = NIO_GetClientSocket(&inst->remote_addr);
}
restart_timeout(inst, INITIAL_DELAY);
}
/* ================================================== */
static void
close_client_socket(NCR_Instance inst)
{
if (inst->mode == MODE_CLIENT && inst->local_addr.sock_fd != INVALID_SOCK_FD) {
NIO_CloseClientSocket(inst->local_addr.sock_fd);
inst->local_addr.sock_fd = INVALID_SOCK_FD;
}
}
@@ -305,11 +384,7 @@ take_offline(NCR_Instance inst)
/* And inactive */
SRC_UnsetActive(inst->source);
/* Close client socket */
if (inst->mode == MODE_CLIENT && inst->local_addr.sock_fd != INVALID_SOCK_FD) {
NIO_CloseClientSocket(inst->local_addr.sock_fd);
inst->local_addr.sock_fd = INVALID_SOCK_FD;
}
close_client_socket(inst);
NCR_ResetInstance(inst);
}
@@ -328,7 +403,7 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
switch (type) {
case NTP_SERVER:
/* Client socket will be obtained when timer is started */
/* Client socket will be obtained when sending request */
result->local_addr.sock_fd = INVALID_SOCK_FD;
result->mode = MODE_CLIENT;
break;
@@ -377,6 +452,7 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
result->timeout_id = 0;
result->tx_suspended = 1;
result->opmode = params->online ? MD_ONLINE : MD_OFFLINE;
result->local_poll = result->minpoll;
NCR_ResetInstance(result);
@@ -423,7 +499,6 @@ NCR_ResetInstance(NCR_Instance instance)
instance->tx_count = 0;
instance->presend_done = 0;
instance->local_poll = instance->minpoll;
instance->poll_score = 0.0;
instance->remote_poll = 0;
instance->remote_stratum = 0;
@@ -436,6 +511,14 @@ NCR_ResetInstance(NCR_Instance instance)
instance->local_tx.tv_usec = 0;
instance->local_ntp_tx.hi = 0;
instance->local_ntp_tx.lo = 0;
if (instance->local_poll != instance->minpoll) {
instance->local_poll = instance->minpoll;
/* The timer was set with a longer poll interval, restart it */
if (instance->timer_running)
restart_timeout(instance, get_transmit_delay(instance, 0, 0.0));
}
}
/* ================================================== */
@@ -598,7 +681,7 @@ get_transmit_delay(NCR_Instance inst, int on_tx, double last_tx)
/* ================================================== */
static void
static int
transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
int my_poll, /* The log2 of the local poll interval */
int version, /* The NTP version to be set in the packet */
@@ -620,7 +703,7 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
)
{
NTP_Packet message;
int leap;
int leap, ret;
struct timeval local_transmit;
/* Parameters read from reference module */
@@ -704,17 +787,17 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
(unsigned char *)&message.auth_data, sizeof (message.auth_data));
if (auth_len > 0) {
message.auth_keyid = htonl(key_id);
NIO_SendAuthenticatedPacket(&message, where_to, from,
ret = NIO_SendAuthenticatedPacket(&message, where_to, from,
sizeof (message.auth_keyid) + auth_len);
} else {
DEBUG_LOG(LOGF_NtpCore,
"Could not generate auth data with key %lu to send packet",
key_id);
return;
return 0;
}
} else {
UTI_TimevalToInt64(&local_transmit, &message.transmit_ts, ts_fuzz);
NIO_SendNormalPacket(&message, where_to, from);
ret = NIO_SendNormalPacket(&message, where_to, from);
}
if (local_tx) {
@@ -725,6 +808,7 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
*local_ntp_tx = message.transmit_ts;
}
return ret;
}
/* ================================================== */
@@ -734,7 +818,7 @@ static void
transmit_timeout(void *arg)
{
NCR_Instance inst = (NCR_Instance) arg;
double timeout_delay;
int sent;
inst->timer_running = 0;
@@ -758,8 +842,15 @@ transmit_timeout(void *arg)
DEBUG_LOG(LOGF_NtpCore, "Transmit timeout for [%s:%d]",
UTI_IPToString(&inst->remote_addr.ip_addr), inst->remote_addr.port);
/* Open new client socket */
if (inst->mode == MODE_CLIENT) {
close_client_socket(inst);
assert(inst->local_addr.sock_fd == INVALID_SOCK_FD);
inst->local_addr.sock_fd = NIO_GetClientSocket(&inst->remote_addr);
}
/* Check whether we need to 'warm up' the link to the other end by
sending an echo exchange to ensure both ends' ARP caches are
sending an NTP exchange to ensure both ends' ARP caches are
primed. On loaded systems this might also help ensure that bits
of the program are paged in properly before we start. */
@@ -767,33 +858,42 @@ transmit_timeout(void *arg)
(inst->presend_minpoll <= inst->local_poll) &&
!inst->presend_done) {
/* Send */
NIO_SendEcho(&inst->remote_addr, &inst->local_addr);
/* Send a client packet, don't store the local tx values
as the reply will be ignored */
transmit_packet(MODE_CLIENT, inst->local_poll, NTP_VERSION, 0, 0,
&inst->remote_orig, &inst->local_rx, NULL, NULL,
&inst->remote_addr, &inst->local_addr);
inst->presend_done = 1;
/* Requeue timeout */
inst->timer_running = 1;
inst->timeout_id = SCH_AddTimeoutInClass(WARM_UP_DELAY, SAMPLING_SEPARATION,
SAMPLING_RANDOMNESS,
SCH_NtpSamplingClass,
transmit_timeout, (void *)inst);
restart_timeout(inst, WARM_UP_DELAY);
return;
}
inst->presend_done = 0; /* Reset for next time */
sent = transmit_packet(inst->mode, inst->local_poll,
NTP_VERSION,
inst->do_auth, inst->auth_key_id,
&inst->remote_orig,
&inst->local_rx, &inst->local_tx, &inst->local_ntp_tx,
&inst->remote_addr,
&inst->local_addr);
++inst->tx_count;
/* If the source loses connectivity, back off the sampling rate to reduce
wasted sampling. If it's the source to which we are currently locked,
back off slower. */
/* If the source loses connectivity and our packets are still being sent,
back off the sampling rate to reduce the network traffic. If it's the
source to which we are currently locked, back off slowly. */
if (inst->tx_count >= 2) {
/* Implies we have missed at least one transmission */
adjust_poll(inst, SRC_IsSyncPeer(inst->source) ? 0.1 : 0.25);
if (sent) {
adjust_poll(inst, SRC_IsSyncPeer(inst->source) ? 0.1 : 0.25);
}
SRC_UpdateReachability(inst->source, 0);
@@ -802,16 +902,12 @@ transmit_timeout(void *arg)
}
}
transmit_packet(inst->mode, inst->local_poll,
NTP_VERSION,
inst->do_auth, inst->auth_key_id,
&inst->remote_orig,
&inst->local_rx, &inst->local_tx, &inst->local_ntp_tx,
&inst->remote_addr,
&inst->local_addr);
switch (inst->opmode) {
case MD_BURST_WAS_ONLINE:
/* When not reachable, don't stop online burst until sending succeeds */
if (!sent && !SRC_IsReachable(inst->source))
break;
/* Fall through */
case MD_BURST_WAS_OFFLINE:
--inst->burst_total_samples_to_go;
break;
@@ -820,12 +916,7 @@ transmit_timeout(void *arg)
}
/* Restart timer for this message */
timeout_delay = get_transmit_delay(inst, 1, 0.0);
inst->timer_running = 1;
inst->timeout_id = SCH_AddTimeoutInClass(timeout_delay, SAMPLING_SEPARATION,
SAMPLING_RANDOMNESS,
SCH_NtpSamplingClass,
transmit_timeout, (void *)inst);
restart_timeout(inst, get_transmit_delay(inst, 1, 0.0));
}
@@ -1257,6 +1348,10 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
adjust_poll(inst, 0.1);
}
/* If in client mode, no more packets are expected to be coming from the
server and the socket can be closed */
close_client_socket(inst);
requeue_transmit = 1;
}
@@ -1271,11 +1366,7 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
/* Get rid of old timeout and start a new one */
assert(inst->timer_running);
SCH_RemoveTimeout(inst->timeout_id);
inst->timeout_id = SCH_AddTimeoutInClass(delay_time, SAMPLING_SEPARATION,
SAMPLING_RANDOMNESS,
SCH_NtpSamplingClass,
transmit_timeout, (void *)inst);
restart_timeout(inst, delay_time);
}
/* Do measurement logging */
@@ -1418,6 +1509,9 @@ NCR_ProcessKnown
break;
case MODE_SERVER:
/* Ignore presend reply */
if (inst->presend_done)
break;
switch(inst->mode) {
case MODE_ACTIVE:

278
ntp_io.c
View File

@@ -71,33 +71,6 @@ static void read_from_socket(void *anything);
/* ================================================== */
static void
do_size_checks(void)
{
/* Assertions to check the sizes of certain data types
and the positions of certain record fields */
/* Check that certain invariants are true */
assert(sizeof(NTP_int32) == 4);
assert(sizeof(NTP_int64) == 8);
/* Check offsets of all fields in the NTP packet format */
assert(offsetof(NTP_Packet, lvm) == 0);
assert(offsetof(NTP_Packet, stratum) == 1);
assert(offsetof(NTP_Packet, poll) == 2);
assert(offsetof(NTP_Packet, precision) == 3);
assert(offsetof(NTP_Packet, root_delay) == 4);
assert(offsetof(NTP_Packet, root_dispersion) == 8);
assert(offsetof(NTP_Packet, reference_id) == 12);
assert(offsetof(NTP_Packet, reference_ts) == 16);
assert(offsetof(NTP_Packet, originate_ts) == 24);
assert(offsetof(NTP_Packet, receive_ts) == 32);
assert(offsetof(NTP_Packet, transmit_ts) == 40);
}
/* ================================================== */
static int
prepare_socket(int family, int port_number, int client_only)
{
@@ -109,11 +82,7 @@ prepare_socket(int family, int port_number, int client_only)
/* Open Internet domain UDP socket for NTP message transmissions */
#if 0
sock_fd = socket(family, SOCK_DGRAM, IPPROTO_UDP);
#else
sock_fd = socket(family, SOCK_DGRAM, 0);
#endif
if (sock_fd < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not open %s NTP socket : %s",
@@ -124,6 +93,54 @@ prepare_socket(int family, int port_number, int client_only)
/* Close on exec */
UTI_FdSetCloexec(sock_fd);
/* Prepare local address */
memset(&my_addr, 0, sizeof (my_addr));
my_addr_len = 0;
switch (family) {
case AF_INET:
if (!client_only)
CNF_GetBindAddress(IPADDR_INET4, &bind_address);
else
CNF_GetBindAcquisitionAddress(IPADDR_INET4, &bind_address);
if (bind_address.family == IPADDR_INET4)
my_addr.in4.sin_addr.s_addr = htonl(bind_address.addr.in4);
else if (port_number)
my_addr.in4.sin_addr.s_addr = htonl(INADDR_ANY);
else
break;
my_addr.in4.sin_family = family;
my_addr.in4.sin_port = htons(port_number);
my_addr_len = sizeof (my_addr.in4);
break;
#ifdef HAVE_IPV6
case AF_INET6:
if (!client_only)
CNF_GetBindAddress(IPADDR_INET6, &bind_address);
else
CNF_GetBindAcquisitionAddress(IPADDR_INET6, &bind_address);
if (bind_address.family == IPADDR_INET6)
memcpy(my_addr.in6.sin6_addr.s6_addr, bind_address.addr.in6,
sizeof (my_addr.in6.sin6_addr.s6_addr));
else if (port_number)
my_addr.in6.sin6_addr = in6addr_any;
else
break;
my_addr.in6.sin6_family = family;
my_addr.in6.sin6_port = htons(port_number);
my_addr_len = sizeof (my_addr.in6);
break;
#endif
default:
assert(0);
}
/* 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) {
@@ -146,12 +163,20 @@ prepare_socket(int family, int port_number, int client_only)
}
#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 free bind socket option");
}
#endif
if (family == AF_INET) {
#ifdef IP_PKTINFO
/* We want the local IP info on server sockets */
if (!client_only &&
setsockopt(sock_fd, IPPROTO_IP, IP_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not request packet info using socket option");
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set packet info socket option");
/* Don't quit - we might survive anyway */
}
#endif
@@ -161,70 +186,26 @@ 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 request IPV6_V6ONLY socket option");
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set IPV6_V6ONLY socket option");
}
#endif
if (!client_only) {
#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 request IPv6 packet info socket option");
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set IPv6 packet info socket option");
}
#elif defined(IPV6_PKTINFO)
if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not request IPv6 packet info socket option");
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set IPv6 packet info socket option");
}
#endif
}
}
#endif
/* Bind the port */
memset(&my_addr, 0, sizeof (my_addr));
switch (family) {
case AF_INET:
my_addr_len = sizeof (my_addr.in4);
my_addr.in4.sin_family = family;
my_addr.in4.sin_port = htons(port_number);
if (!client_only)
CNF_GetBindAddress(IPADDR_INET4, &bind_address);
else
CNF_GetBindAcquisitionAddress(IPADDR_INET4, &bind_address);
if (bind_address.family == IPADDR_INET4)
my_addr.in4.sin_addr.s_addr = htonl(bind_address.addr.in4);
else
my_addr.in4.sin_addr.s_addr = htonl(INADDR_ANY);
break;
#ifdef HAVE_IPV6
case AF_INET6:
my_addr_len = sizeof (my_addr.in6);
my_addr.in6.sin6_family = family;
my_addr.in6.sin6_port = htons(port_number);
if (!client_only)
CNF_GetBindAddress(IPADDR_INET6, &bind_address);
else
CNF_GetBindAcquisitionAddress(IPADDR_INET6, &bind_address);
if (bind_address.family == IPADDR_INET6)
memcpy(my_addr.in6.sin6_addr.s6_addr, bind_address.addr.in6,
sizeof (my_addr.in6.sin6_addr.s6_addr));
else
my_addr.in6.sin6_addr = in6addr_any;
break;
#endif
default:
assert(0);
}
#if 0
LOG(LOGS_INFO, LOGF_NtpIO, "Initialising, socket fd=%d", sock_fd);
#endif
if (bind(sock_fd, &my_addr.u, my_addr_len) < 0) {
/* Bind the socket if a port or address was specified */
if (my_addr_len > 0 && bind(sock_fd, &my_addr.u, my_addr_len) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not bind %s NTP socket : %s",
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
close(sock_fd);
@@ -234,20 +215,28 @@ prepare_socket(int family, int port_number, int client_only)
/* Register handler for read events on the socket */
SCH_AddInputFileHandler(sock_fd, read_from_socket, (void *)(long)sock_fd);
#if 0
if (fcntl(sock_fd, F_SETFL, O_NONBLOCK | O_NDELAY) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not make socket non-blocking");
}
if (ioctl(sock_fd, I_SETSIG, S_INPUT) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not enable signal");
}
#endif
return sock_fd;
}
/* ================================================== */
static int
prepare_separate_client_socket(int family)
{
switch (family) {
case IPADDR_INET4:
return prepare_socket(AF_INET, 0, 1);
#ifdef HAVE_IPV6
case IPADDR_INET6:
return prepare_socket(AF_INET6, 0, 1);
#endif
default:
return INVALID_SOCK_FD;
}
}
/* ================================================== */
static int
connect_socket(int sock_fd, NTP_Remote_Address *remote_addr)
{
@@ -277,7 +266,7 @@ connect_socket(int sock_fd, NTP_Remote_Address *remote_addr)
}
if (connect(sock_fd, &addr.u, addr_len) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not connect NTP socket to %s:%d : %s",
DEBUG_LOG(LOGF_NtpIO, "Could not connect NTP socket to %s:%d : %s",
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
strerror(errno));
return 0;
@@ -299,7 +288,6 @@ close_socket(int sock_fd)
}
/* ================================================== */
void
NIO_Initialise(int family)
{
@@ -308,13 +296,13 @@ NIO_Initialise(int family)
assert(!initialised);
initialised = 1;
do_size_checks();
server_port = CNF_GetNTPPort();
client_port = CNF_GetAcquisitionPort();
/* Use separate connected sockets if client port is not set */
separate_client_sockets = client_port == 0;
/* Use separate connected sockets if client port is negative */
separate_client_sockets = client_port < 0;
if (client_port < 0)
client_port = 0;
server_sock_fd4 = INVALID_SOCK_FD;
client_sock_fd4 = INVALID_SOCK_FD;
@@ -383,20 +371,7 @@ int
NIO_GetClientSocket(NTP_Remote_Address *remote_addr)
{
if (separate_client_sockets) {
int sock_fd;
switch (remote_addr->ip_addr.family) {
case IPADDR_INET4:
sock_fd = prepare_socket(AF_INET, 0, 1);
break;
#ifdef HAVE_IPV6
case IPADDR_INET6:
sock_fd = prepare_socket(AF_INET6, 0, 1);
break;
#endif
default:
sock_fd = INVALID_SOCK_FD;
}
int sock_fd = prepare_separate_client_socket(remote_addr->ip_addr.family);
if (sock_fd == INVALID_SOCK_FD)
return INVALID_SOCK_FD;
@@ -506,6 +481,9 @@ read_from_socket(void *anything)
reponse on a subsequent recvfrom). */
if (status > 0) {
if (msg.msg_namelen > sizeof (where_from))
LOG_FATAL(LOGF_NtpIO, "Truncated source address");
switch (where_from.u.sa_family) {
case AF_INET:
remote_addr.ip_addr.family = IPADDR_INET4;
@@ -559,6 +537,13 @@ read_from_socket(void *anything)
#endif
}
if (status > 0) {
DEBUG_LOG(LOGF_NtpIO, "Received %d bytes from %s:%d to %s fd %d",
status,
UTI_IPToString(&remote_addr.ip_addr), remote_addr.port,
UTI_IPToString(&local_addr.ip_addr), local_addr.sock_fd);
}
if (status >= NTP_NORMAL_PACKET_SIZE && status <= sizeof(NTP_Packet)) {
NSR_ProcessReceive((NTP_Packet *) &message.ntp_pkt, &now, now_err,
@@ -575,7 +560,7 @@ read_from_socket(void *anything)
/* ================================================== */
/* Send a packet to given address */
static void
static int
send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr)
{
union sockaddr_in46 remote;
@@ -583,12 +568,21 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr, NTP_Lo
struct iovec iov;
char cmsgbuf[256];
int cmsglen;
socklen_t addrlen;
socklen_t addrlen = 0;
assert(initialised);
if (local_addr->sock_fd == INVALID_SOCK_FD) {
DEBUG_LOG(LOGF_NtpIO, "No socket to send to %s:%d",
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port);
return 0;
}
switch (remote_addr->ip_addr.family) {
case IPADDR_INET4:
/* Don't set address with connected socket */
if (local_addr->sock_fd != server_sock_fd4 && separate_client_sockets)
break;
memset(&remote.in4, 0, sizeof (remote.in4));
addrlen = sizeof (remote.in4);
remote.in4.sin_family = AF_INET;
@@ -597,6 +591,9 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr, NTP_Lo
break;
#ifdef HAVE_IPV6
case IPADDR_INET6:
/* Don't set address with connected socket */
if (local_addr->sock_fd != server_sock_fd6 && separate_client_sockets)
break;
memset(&remote.in6, 0, sizeof (remote.in6));
addrlen = sizeof (remote.in6);
remote.in6.sin6_family = AF_INET6;
@@ -606,19 +603,19 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr, NTP_Lo
break;
#endif
default:
return;
return 0;
}
if (local_addr->sock_fd == INVALID_SOCK_FD) {
DEBUG_LOG(LOGF_NtpIO, "No socket to send to %s:%d",
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port);
return;
if (addrlen) {
msg.msg_name = &remote.u;
msg.msg_namelen = addrlen;
} else {
msg.msg_name = NULL;
msg.msg_namelen = 0;
}
iov.iov_base = packet;
iov.iov_len = packetlen;
msg.msg_name = &remote.u;
msg.msg_namelen = addrlen;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = cmsgbuf;
@@ -663,53 +660,40 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr, NTP_Lo
}
#endif
#if 0
LOG(LOGS_INFO, LOGF_NtpIO, "sending to %s:%d from %s",
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port, UTI_IPToString(&remote_addr->local_ip_addr));
#endif
msg.msg_controllen = cmsglen;
/* This is apparently required on some systems */
if (!cmsglen)
msg.msg_control = NULL;
if (sendmsg(local_addr->sock_fd, &msg, 0) < 0) {
DEBUG_LOG(LOGF_NtpIO, "Could not send to %s:%d : %s",
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port, strerror(errno));
DEBUG_LOG(LOGF_NtpIO, "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 to %s:%d from %s fd %d",
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
UTI_IPToString(&local_addr->ip_addr), local_addr->sock_fd);
return 1;
}
/* ================================================== */
/* Send an unauthenticated packet to a given address */
void
int
NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr)
{
send_packet((void *) packet, NTP_NORMAL_PACKET_SIZE, remote_addr, local_addr);
return send_packet((void *) packet, NTP_NORMAL_PACKET_SIZE, remote_addr, local_addr);
}
/* ================================================== */
/* Send an authenticated packet to a given address */
void
int
NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int auth_len)
{
send_packet((void *) packet, NTP_NORMAL_PACKET_SIZE + auth_len, remote_addr, local_addr);
}
/* ================================================== */
/* We ought to use getservbyname, but I can't really see this changing */
#define ECHO_PORT 7
void
NIO_SendEcho(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr)
{
unsigned long magic_message = 0xbe7ab1e7UL;
NTP_Remote_Address addr;
addr = *remote_addr;
addr.port = ECHO_PORT;
send_packet((void *) &magic_message, sizeof(unsigned long), &addr, local_addr);
return send_packet((void *) packet, NTP_NORMAL_PACKET_SIZE + auth_len, remote_addr, local_addr);
}

View File

@@ -51,12 +51,9 @@ extern void NIO_CloseClientSocket(int sock_fd);
extern int NIO_IsServerSocket(int sock_fd);
/* Function to transmit a packet */
extern void NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr);
extern int NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr);
/* Function to transmit an authenticated packet */
extern void NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int auth_len);
/* Function to send a datagram to a remote machine's UDP echo port. */
extern void NIO_SendEcho(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr);
extern int NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int auth_len);
#endif /* GOT_NTP_IO_H */

View File

@@ -200,10 +200,6 @@ NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParam
assert(initialised);
#if 0
LOG(LOGS_INFO, LOGF_NtpSources, "IP=%s port=%d", UTI_IPToString(&remote_addr->ip_addr), remote_addr->port);
#endif
/* Find empty bin & check that we don't have the address already */
find_slot(remote_addr, &slot, &found);
if (found) {
@@ -457,12 +453,6 @@ NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP
assert(initialised);
#if 0
LOG(LOGS_INFO, LOGF_NtpSources, "from (%s,%d) at %s",
UTI_IPToString(&remote_addr->ip_addr),
remote_addr->port, UTI_TimevalToString(now));
#endif
find_slot(remote_addr, &slot, &found);
if (found == 2) { /* Must match IP address AND port number */
NCR_ProcessKnown(message, now, now_err, records[slot].data,
@@ -486,11 +476,6 @@ slew_sources(struct timeval *raw,
for (i=0; i<N_RECORDS; i++) {
if (records[i].remote_addr) {
#if 0
LOG(LOGS_INFO, LOGF_Sources, "IP=%s dfreq=%f doff=%f",
UTI_IPToString(&records[i].remote_addr->ip_addr), dfreq, doffset);
#endif
if (change_type == LCL_ChangeUnknownStep) {
NCR_ResetInstance(records[i].data);
} else {
@@ -498,7 +483,6 @@ slew_sources(struct timeval *raw,
}
}
}
}
/* ================================================== */

View File

@@ -908,20 +908,13 @@ static void
filter_slew_samples(struct MedianFilter *filter, struct timeval *when, double dfreq, double doffset)
{
int i;
double delta_time, prev_offset;
double delta_time;
struct timeval *sample;
for (i = 0; i < filter->used; i++) {
sample = &filter->samples[i].sample_time;
UTI_AdjustTimeval(sample, when, sample, &delta_time, dfreq, doffset);
prev_offset = filter->samples[i].offset;
filter->samples[i].offset -= delta_time;
#if 0
LOG(LOGS_INFO, LOGF_Refclock, "i=%d old_off=%.9f new_off=%.9f",
i, prev_offset, filter->samples[i].offset);
#else
(void)prev_offset;
#endif
}
}

View File

@@ -64,7 +64,7 @@ static void read_sample(void *anything)
if (s != sizeof (sample)) {
LOG(LOGS_WARN, LOGF_Refclock, "Unexpected length of SOCK sample : %d != %ld",
s, sizeof (sample));
s, (long)sizeof (sample));
return;
}

View File

@@ -267,7 +267,7 @@ REF_Finalise(void)
LCL_SetLeap(0);
}
if (drift_file && drift_file_age > 0.0) {
if (drift_file) {
update_drift_file(LCL_ReadAbsoluteFrequency(), our_skew);
}
@@ -426,10 +426,8 @@ update_fb_drifts(double freq_ppm, double update_interval)
(freq_ppm - fb_drifts[i].freq);
}
#if 0
LOG(LOGS_INFO, LOGF_Reference, "Fallback drift %d updated: %f ppm %f seconds",
DEBUG_LOG(LOGF_Reference, "Fallback drift %d updated: %f ppm %f seconds",
i + fb_drift_min, fb_drifts[i].freq, fb_drifts[i].secs);
#endif
}
}
@@ -476,18 +474,14 @@ schedule_fb_drift(struct timeval *now)
if (c > next_fb_drift) {
LCL_SetAbsoluteFrequency(fb_drifts[c - fb_drift_min].freq);
next_fb_drift = c;
#if 0
LOG(LOGS_INFO, LOGF_Reference, "Fallback drift %d set", c);
#endif
DEBUG_LOG(LOGF_Reference, "Fallback drift %d set", c);
}
if (i <= fb_drift_max) {
next_fb_drift = i;
UTI_AddDoubleToTimeval(now, secs - unsynchronised, &when);
fb_drift_timeout_id = SCH_AddTimeout(&when, fb_drift_timeout, NULL);
#if 0
LOG(LOGS_INFO, LOGF_Reference, "Fallback drift %d scheduled", i);
#endif
DEBUG_LOG(LOGF_Reference, "Fallback drift %d scheduled", i);
}
}
@@ -686,7 +680,7 @@ update_leap_status(NTP_Leap leap, time_t now)
}
}
if (leap_sec != our_leap_sec) {
if (leap_sec != our_leap_sec && !REF_IsLeapSecondClose()) {
LCL_SetLeap(leap_sec);
our_leap_sec = leap_sec;
}
@@ -1127,9 +1121,6 @@ void
REF_ModifyMaxupdateskew(double new_max_update_skew)
{
max_update_skew = new_max_update_skew * 1.0e-6;
#if 0
LOG(LOGS_INFO, LOGF_Reference, "New max update skew = %.3fppm", new_max_update_skew);
#endif
}
/* ================================================== */
@@ -1159,6 +1150,31 @@ REF_IsLocalActive(void)
/* ================================================== */
#define LEAP_SECOND_CLOSE 5
int REF_IsLeapSecondClose(void)
{
struct timeval now, now_raw;
time_t t;
if (!our_leap_sec)
return 0;
SCH_GetLastEventTime(&now, NULL, &now_raw);
t = now.tv_sec > 0 ? now.tv_sec : -now.tv_sec;
if ((t + LEAP_SECOND_CLOSE) % (24 * 3600) < 2 * LEAP_SECOND_CLOSE)
return 1;
t = now_raw.tv_sec > 0 ? now_raw.tv_sec : -now_raw.tv_sec;
if ((t + LEAP_SECOND_CLOSE) % (24 * 3600) < 2 * LEAP_SECOND_CLOSE)
return 1;
return 0;
}
/* ================================================== */
void
REF_GetTrackingReport(RPT_TrackingReport *rep)
{

View File

@@ -161,6 +161,10 @@ extern void REF_EnableLocal(int stratum);
extern void REF_DisableLocal(void);
extern int REF_IsLocalActive(void);
/* Check if current raw or cooked time is close to a leap second
and is better to discard any measurements */
extern int REF_IsLeapSecondClose(void);
extern void REF_GetTrackingReport(RPT_TrackingReport *rep);
#endif /* GOT_REFERENCE_H */

View File

@@ -570,11 +570,6 @@ RGR_FindBestRobustRegression
b = X / V;
a = my - b*mx;
#if 0
printf("my=%20.12f mx=%20.12f a=%20.12f b=%20.12f\n", my, mx, a, b);
#endif
s2 = 0.0;
for (i=start; i<n; i++) {
resid = y[i] - a - b * x[i];

74
rtc.c
View File

@@ -28,6 +28,7 @@
#include "sysincl.h"
#include "rtc.h"
#include "local.h"
#include "logging.h"
#include "conf.h"
@@ -42,7 +43,7 @@ static int driver_initialised = 0;
static struct {
int (*init)(void);
void (*fini)(void);
void (*time_pre_init)(void);
int (*time_pre_init)(void);
void (*time_init)(void (*after_hook)(void*), void *anything);
void (*start_measurements)(void);
int (*write_parameters)(void);
@@ -71,13 +72,51 @@ static struct {
#endif
};
/* ================================================== */
/* Set the system clock to the time of last modification of driftfile
if it's in the future */
static void
fallback_time_init(void)
{
struct timeval now;
struct stat buf;
char *drift_file;
drift_file = CNF_GetDriftFile();
if (!drift_file)
return;
if (stat(drift_file, &buf))
return;
LCL_ReadCookedTime(&now, NULL);
if (now.tv_sec < buf.st_mtime) {
LCL_ApplyStepOffset(now.tv_sec - buf.st_mtime);
LOG(LOGS_INFO, LOGF_Rtc,
"System clock set from driftfile %s", drift_file);
}
}
/* ================================================== */
void
RTC_Initialise(void)
RTC_Initialise(int initial_set)
{
char *file_name;
int ok;
/* Do an initial read of the RTC and set the system time to it. This
is analogous to what /sbin/hwclock -s would do on Linux. If that fails
or RTC is not supported, set the clock to the time of the last
modification of driftfile, so we at least get closer to the truth. */
if (initial_set) {
if (!driver.time_pre_init || !driver.time_pre_init()) {
fallback_time_init();
}
}
driver_initialised = 0;
/* This is how we tell whether the user wants to load the RTC
driver, if he is on a machine where it is an option. */
@@ -90,23 +129,11 @@ RTC_Initialise(void)
if (driver.init) {
if ((driver.init)()) {
ok = 1;
} else {
ok = 0;
driver_initialised = 1;
}
} else {
ok = 0;
LOG(LOGS_ERR, LOGF_Rtc, "RTC not supported on this operating system");
}
if (ok) {
driver_initialised = 1;
} else {
driver_initialised = 0;
LOG(LOGS_ERR, LOGF_Rtc, "Real time clock not supported on this operating system");
}
} else {
driver_initialised = 0;
}
}
@@ -137,23 +164,10 @@ RTC_TimeInit(void (*after_hook)(void *), void *anything)
if (driver_initialised) {
(driver.time_init)(after_hook, anything);
} else {
LOG(LOGS_ERR, LOGF_Rtc, "Can't initialise from real time clock, driver not loaded");
(after_hook)(anything);
}
}
/* ================================================== */
/* Do an initial read of the RTC and set the system time to it. This
is analogous to what /sbin/hwclock -s would do on Linux. */
void
RTC_TimePreInit(void)
{
if (driver.time_pre_init) {
(driver.time_pre_init)();
}
}
/* ================================================== */
/* Start the RTC measurement process */

3
rtc.h
View File

@@ -28,9 +28,8 @@
#include "reports.h"
extern void RTC_Initialise(void);
extern void RTC_Initialise(int initial_set);
extern void RTC_Finalise(void);
extern void RTC_TimePreInit(void);
extern void RTC_TimeInit(void (*after_hook)(void *), void *anything);
extern void RTC_StartMeasurements(void);
extern int RTC_GetReport(RPT_RTC_Report *report);

View File

@@ -431,7 +431,6 @@ static void
read_coefs_from_file(void)
{
FILE *in;
char line[256];
if (!tried_to_load_coefs) {
@@ -439,26 +438,17 @@ read_coefs_from_file(void)
tried_to_load_coefs = 1;
in = fopen(coefs_file_name, "r");
if (in) {
if (fgets(line, sizeof(line), in)) {
if (sscanf(line, "%d%ld%lf%lf",
&valid_coefs_from_file,
&file_ref_time,
&file_ref_offset,
&file_rate_ppm) == 4) {
} else {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not parse coefficients line from RTC file %s",
coefs_file_name);
}
if (coefs_file_name && (in = fopen(coefs_file_name, "r"))) {
if (fscanf(in, "%d%ld%lf%lf",
&valid_coefs_from_file,
&file_ref_time,
&file_ref_offset,
&file_rate_ppm) == 4) {
} else {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not read first line from RTC file %s",
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not read coefficients from RTC file %s",
coefs_file_name);
}
fclose(in);
} else {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not open RTC file %s for reading",
coefs_file_name);
}
}
}
@@ -550,7 +540,8 @@ RTC_Linux_Initialise(void)
fd = open (CNF_GetRtcDevice(), O_RDWR);
if (fd < 0) {
LOG(LOGS_ERR, LOGF_RtcLinux, "Could not open %s, %s", CNF_GetRtcDevice(), strerror(errno));
LOG(LOGS_ERR, LOGF_RtcLinux, "Could not open RTC device %s : %s",
CNF_GetRtcDevice(), strerror(errno));
return 0;
}
@@ -975,15 +966,14 @@ RTC_Linux_WriteParameters(void)
etc in this case, since we have fewer requirements regarding the
RTC behaviour than we do for the rest of the module. */
void
int
RTC_Linux_TimePreInit(void)
{
int fd, status;
struct rtc_time rtc_raw, rtc_raw_retry;
struct tm rtc_tm;
time_t rtc_t, estimated_correct_rtc_t;
long interval;
double accumulated_error = 0.0;
time_t rtc_t;
double accumulated_error, sys_offset;
struct timeval new_sys_time, old_sys_time;
coefs_file_name = CNF_GetRtcFile();
@@ -994,7 +984,7 @@ RTC_Linux_TimePreInit(void)
fd = open(CNF_GetRtcDevice(), O_RDONLY);
if (fd < 0) {
return; /* Can't open it, and won't be able to later */
return 0; /* Can't open it, and won't be able to later */
}
/* Retry reading the rtc until both read attempts give the same sec value.
@@ -1007,6 +997,11 @@ RTC_Linux_TimePreInit(void)
}
} while (status >= 0 && rtc_raw.tm_sec != rtc_raw_retry.tm_sec);
/* Read system clock */
LCL_ReadCookedTime(&old_sys_time, NULL);
close(fd);
if (status >= 0) {
/* Convert to seconds since 1970 */
rtc_tm.tm_sec = rtc_raw.tm_sec;
@@ -1023,37 +1018,35 @@ RTC_Linux_TimePreInit(void)
/* Work out approximatation to correct time (to about the
nearest second) */
if (valid_coefs_from_file) {
interval = rtc_t - file_ref_time;
accumulated_error = file_ref_offset + (double)(interval) * 1.0e-6 * file_rate_ppm;
/* Correct time */
estimated_correct_rtc_t = rtc_t - (long)(0.5 + accumulated_error);
accumulated_error = file_ref_offset +
(rtc_t - file_ref_time) * 1.0e-6 * file_rate_ppm;
} else {
estimated_correct_rtc_t = rtc_t - (long)(0.5 + accumulated_error);
accumulated_error = 0.0;
}
new_sys_time.tv_sec = estimated_correct_rtc_t;
new_sys_time.tv_usec = 0;
/* Correct time */
new_sys_time.tv_sec = rtc_t;
/* Average error in the RTC reading */
new_sys_time.tv_usec = 500000;
UTI_AddDoubleToTimeval(&new_sys_time, -accumulated_error, &new_sys_time);
UTI_DiffTimevalsToDouble(&sys_offset, &old_sys_time, &new_sys_time);
/* Set system time only if the step is larger than 1 second */
if (!(gettimeofday(&old_sys_time, NULL) < 0) &&
(old_sys_time.tv_sec - new_sys_time.tv_sec > 1 ||
old_sys_time.tv_sec - new_sys_time.tv_sec < -1)) {
if (fabs(sys_offset) >= 1.0) {
LOG(LOGS_INFO, LOGF_RtcLinux, "Set system time, error in RTC = %f",
accumulated_error);
/* Tough luck if this fails */
if (settimeofday(&new_sys_time, NULL) < 0) {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not settimeofday");
}
LCL_ApplyStepOffset(sys_offset);
}
} else {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not convert RTC reading to seconds since 1/1/1970");
return 0;
}
}
close(fd);
return 1;
}
/* ================================================== */

View File

@@ -30,7 +30,7 @@
extern int RTC_Linux_Initialise(void);
extern void RTC_Linux_Finalise(void);
extern void RTC_Linux_TimePreInit(void);
extern int RTC_Linux_TimePreInit(void);
extern void RTC_Linux_TimeInit(void (*after_hook)(void *), void *anything);
extern void RTC_Linux_StartMeasurements(void);

78
sched.c
View File

@@ -57,18 +57,18 @@ static unsigned int n_read_fds;
/* One more than the highest file descriptor that is registered */
static unsigned int one_highest_fd;
/* This assumes that fd_set is implemented as a fixed size array of
bits, possibly embedded inside a record. It might therefore
somewhat non-portable. */
#define FD_SET_SIZE (sizeof(fd_set) * 8)
#ifndef FD_SETSIZE
/* If FD_SETSIZE is not defined, assume that fd_set is implemented
as a fixed size array of bits, possibly embedded inside a record */
#define FD_SETSIZE (sizeof(fd_set) * 8)
#endif
typedef struct {
SCH_FileHandler handler;
SCH_ArbitraryArgument arg;
} FileHandlerEntry;
static FileHandlerEntry file_handlers[FD_SET_SIZE];
static FileHandlerEntry file_handlers[FD_SETSIZE];
/* Timestamp when last select() returned */
static struct timeval last_select_ts, last_select_ts_raw;
@@ -169,6 +169,9 @@ SCH_AddInputFileHandler
assert(initialised);
if (fd >= FD_SETSIZE)
LOG_FATAL(LOGF_Scheduler, "Too many file descriptors");
/* Don't want to allow the same fd to register a handler more than
once without deleting a previous association - this suggests
a bug somewhere else in the program. */
@@ -511,6 +514,10 @@ handle_slew(struct timeval *raw,
int i;
if (change_type != LCL_ChangeAdjust) {
/* Make sure this handler is invoked first in order to not shift new timers
added from other handlers */
assert(LCL_IsFirstParameterChangeHandler(handle_slew));
/* If a step change occurs, just shift all raw time stamps by the offset */
for (ptr = timer_queue.next; ptr != &timer_queue; ptr = ptr->next) {
@@ -532,28 +539,49 @@ handle_slew(struct timeval *raw,
#define JUMP_DETECT_THRESHOLD 10
static int
check_current_time(struct timeval *raw, int timeout)
check_current_time(struct timeval *prev_raw, struct timeval *raw, int timeout,
struct timeval *orig_select_tv,
struct timeval *rem_select_tv)
{
double diff;
struct timeval elapsed_min, elapsed_max;
double step, elapsed;
if (last_select_ts_raw.tv_sec > raw->tv_sec + JUMP_DETECT_THRESHOLD) {
/* Get an estimate of the time spent waiting in the select() call. On some
systems (e.g. Linux) the timeout timeval is modified to return the
remaining time, use that information. */
if (timeout) {
elapsed_max = elapsed_min = *orig_select_tv;
} else if (rem_select_tv && rem_select_tv->tv_sec >= 0 &&
rem_select_tv->tv_sec <= orig_select_tv->tv_sec &&
(rem_select_tv->tv_sec != orig_select_tv->tv_sec ||
rem_select_tv->tv_usec != orig_select_tv->tv_usec)) {
UTI_DiffTimevals(&elapsed_min, orig_select_tv, rem_select_tv);
elapsed_max = elapsed_min;
} else {
if (rem_select_tv)
elapsed_max = *orig_select_tv;
else
UTI_DiffTimevals(&elapsed_max, raw, prev_raw);
elapsed_min.tv_sec = 0;
elapsed_min.tv_usec = 0;
}
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!");
} else if (n_timer_queue_entries > 0 &&
timer_queue.next->tv.tv_sec + JUMP_DETECT_THRESHOLD < raw->tv_sec) {
} 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!");
} else {
return 1;
}
if (timeout) {
assert(n_timer_queue_entries > 0);
UTI_DiffTimevalsToDouble(&diff, &timer_queue.next->tv, raw);
} else {
UTI_DiffTimevalsToDouble(&diff, &last_select_ts_raw, raw);
}
UTI_DiffTimevalsToDouble(&step, &last_select_ts_raw, raw);
UTI_TimevalToDouble(&elapsed_min, &elapsed);
step += elapsed;
/* Cooked time may no longer be valid after dispatching the handlers */
LCL_NotifyExternalTimeStep(raw, raw, diff, fabs(diff));
LCL_NotifyExternalTimeStep(raw, raw, step, fabs(step));
return 0;
}
@@ -565,8 +593,8 @@ SCH_MainLoop(void)
{
fd_set rd;
int status, errsv;
struct timeval tv, *ptv;
struct timeval now, cooked;
struct timeval tv, saved_tv, *ptv;
struct timeval now, saved_now, cooked;
double err;
assert(initialised);
@@ -574,6 +602,7 @@ SCH_MainLoop(void)
while (!need_to_exit) {
/* Dispatch timeouts and fill now with current raw time */
dispatch_timeouts(&now);
saved_now = now;
/* The timeout handlers may request quit */
if (need_to_exit)
@@ -585,14 +614,19 @@ SCH_MainLoop(void)
UTI_DiffTimevals(&tv, &(timer_queue.next->tv), &now);
ptv = &tv;
assert(tv.tv_sec > 0 || tv.tv_usec > 0);
saved_tv = tv;
} else {
ptv = NULL;
/* This is needed to fix a compiler warning */
saved_tv.tv_sec = 0;
}
/* if there are no file descriptors being waited on and no
timeout set, this is clearly ridiculous, so stop the run */
assert(ptv || n_read_fds);
if (!ptv && !n_read_fds) {
LOG_FATAL(LOGF_Scheduler, "Nothing to do");
}
/* Copy current set of read file descriptors */
memcpy((void *) &rd, (void *) &read_fds, sizeof(fd_set));
@@ -604,7 +638,7 @@ SCH_MainLoop(void)
LCL_CookTime(&now, &cooked, &err);
/* Check if the time didn't jump unexpectedly */
if (!check_current_time(&now, status == 0)) {
if (!check_current_time(&saved_now, &now, status == 0, &saved_tv, ptv)) {
/* Cook the time again after handling the step */
LCL_CookTime(&now, &cooked, &err);
}

View File

@@ -312,6 +312,11 @@ void SRC_AccumulateSample
DEBUG_LOG(LOGF_Sources, "ip=[%s] t=%s ofs=%f del=%f disp=%f str=%d",
source_to_string(inst), UTI_TimevalToString(sample_time), -offset, root_delay, root_dispersion, stratum);
if (REF_IsLeapSecondClose()) {
LOG(LOGS_INFO, LOGF_Sources, "Dropping sample around leap second");
return;
}
/* WE HAVE TO NEGATE OFFSET IN THIS CALL, IT IS HERE THAT THE SENSE OF OFFSET
IS FLIPPED */
SST_AccumulateSample(inst->stats, sample_time, -offset, peer_delay, peer_dispersion, root_delay, root_dispersion, stratum);
@@ -610,13 +615,6 @@ SRC_SelectSource(SRC_Instance updated_inst)
&(si->variance),
&(si->select_ok));
#if 0
LOG(LOGS_INFO, LOGF_Sources, "%s dist=%f lo=%f hi=%f",
source_to_string(sources[i]),
si->root_distance,
si->lo_limit, si->hi_limit);
#endif
if (si->select_ok) {
++n_sel_sources;
@@ -655,10 +653,8 @@ SRC_SelectSource(SRC_Instance updated_inst)
}
}
#if 0
LOG(LOGS_INFO, LOGF_Sources, "badstat_sources=%d sel_sources=%d badstat_reach=%x sel_reach=%x",
DEBUG_LOG(LOGF_Sources, "badstat_sources=%d sel_sources=%d badstat_reach=%x sel_reach=%x",
n_badstats_sources, n_sel_sources, max_badstat_reach, max_sel_reach);
#endif
/* Wait for the next call if we have no source selected and there is
a source with bad stats (has less than 3 samples) with reachability
@@ -672,10 +668,6 @@ SRC_SelectSource(SRC_Instance updated_inst)
return;
}
#if 0
LOG(LOGS_INFO, LOGF_Sources, "n_endpoints=%d", n_endpoints);
#endif
/* Now sort the endpoint list */
if (n_endpoints > 0) {
@@ -709,10 +701,6 @@ SRC_SelectSource(SRC_Instance updated_inst)
best_lo = best_hi = 0.0;
for (i=0; i<n_endpoints; i++) {
#if 0
LOG(LOGS_INFO, LOGF_Sources, "i=%d t=%f tag=%d addr=%s", i, sort_list[i].offset, sort_list[i].tag,
source_to_string(sources[sort_list[i].index]));
#endif
switch(sort_list[i].tag) {
case LOW:
depth++;
@@ -736,11 +724,6 @@ SRC_SelectSource(SRC_Instance updated_inst)
}
}
#if 0
LOG(LOGS_INFO, LOGF_Sources, "best_depth=%d best_lo=%f best_hi=%f",
best_depth, best_lo, best_hi);
#endif
if (best_depth <= n_sel_sources/2) {
/* Could not even get half the reachable sources to agree -
clearly we can't synchronise.
@@ -783,14 +766,8 @@ SRC_SelectSource(SRC_Instance updated_inst)
(sources[i]->sel_info.hi_limit <= best_hi))) {
sel_sources[n_sel_sources++] = i;
#if 0
LOG(LOGS_INFO, LOGF_Sources, "i=%d addr=%s is valid", i, source_to_string(sources[i]));
#endif
} else {
sources[i]->status = SRC_FALSETICKER;
#if 0
LOG(LOGS_INFO, LOGF_Sources, "i=%d addr=%s is a falseticker", i, source_to_string(sources[i]));
#endif
}
}
}
@@ -811,10 +788,6 @@ SRC_SelectSource(SRC_Instance updated_inst)
}
}
#if 0
LOG(LOGS_INFO, LOGF_Sources, "min_distance=%f", min_distance);
#endif
/* Now go through and prune any NTP sources that have excessive
variance */
for (i=0; i<n_sel_sources; i++) {
@@ -823,9 +796,6 @@ SRC_SelectSource(SRC_Instance updated_inst)
sqrt(sources[index]->sel_info.variance) > min_distance) {
sel_sources[i] = INVALID_SOURCE;
sources[index]->status = SRC_JITTERY;
#if 0
LOG(LOGS_INFO, LOGF_Sources, "i=%d addr=%s has too much variance", i, source_to_string(sources[i]));
#endif
}
}
#endif
@@ -884,10 +854,6 @@ SRC_SelectSource(SRC_Instance updated_inst)
if (stratum < min_stratum) min_stratum = stratum;
}
#if 0
LOG(LOGS_INFO, LOGF_Sources, "min_stratum=%d", min_stratum);
#endif
/* Update scores and find source with maximum score */
max_score_index = INVALID_SOURCE;
@@ -936,11 +902,9 @@ SRC_SelectSource(SRC_Instance updated_inst)
sources[i]->sel_score = 1.0 / distance;
}
#if 0
LOG(LOGS_INFO, LOGF_Sources, "select score=%f refid=%x match_refid=%x status=%d dist=%f",
DEBUG_LOG(LOGF_Sources, "select score=%f refid=%x match_refid=%x status=%d dist=%f",
sources[i]->sel_score, sources[i]->ref_id, updated_inst ? updated_inst->ref_id : 0,
sources[i]->status, distance);
#endif
if (max_score < sources[i]->sel_score) {
max_score = sources[i]->sel_score;
@@ -963,10 +927,6 @@ SRC_SelectSource(SRC_Instance updated_inst)
log_selection_message("Selected source %s",
source_to_string(sources[selected_source_index]));
#if 0
LOG(LOGS_INFO, LOGF_Sources, "new_sel_index=%d", selected_source_index);
#endif
/* New source has been selected, reset all scores */
for (i=0; i < n_sources; i++) {
sources[i]->sel_score = 1.0;
@@ -1212,6 +1172,14 @@ SRC_IsSyncPeer(SRC_Instance inst)
/* ================================================== */
int
SRC_IsReachable(SRC_Instance inst)
{
return inst->reachability != 0;
}
/* ================================================== */
int
SRC_ReadNumberOfSources(void)
{

View File

@@ -171,6 +171,7 @@ extern void SRC_DumpSources(void);
extern void SRC_ReloadSources(void);
extern int SRC_IsSyncPeer(SRC_Instance inst);
extern int SRC_IsReachable(SRC_Instance inst);
extern int SRC_ReadNumberOfSources(void);
extern int SRC_ActiveSources(void);
extern int SRC_ReportSource(int index, RPT_SourceReport *report, struct timeval *now);

View File

@@ -363,10 +363,6 @@ find_best_sample_index(SST_Stats inst, double *times_back)
assert(best_index >= 0);
inst->best_single_sample = best_index;
#if 0
LOG(LOGS_INFO, LOGF_SourceStats, "n=%d best_index=%d", n, best_index);
#endif
}
/* ================================================== */
@@ -500,9 +496,6 @@ SST_DoNewRegression(SST_Stats inst)
times_back_start = inst->runs_samples + best_start;
prune_register(inst, best_start);
} else {
#if 0
LOG(LOGS_INFO, LOGF_SourceStats, "too few points (%d) for regression", inst->n_samples);
#endif
inst->estimated_frequency = 0.0;
inst->skew = WORST_CASE_FREQ_BOUND;
times_back_start = 0;
@@ -734,9 +727,8 @@ SST_IsGoodSample(SST_Stats inst, double offset, double delay,
if (fabs(offset) - delay_increase > allowed_increase)
return 1;
#if 0
LOG(LOGS_INFO, LOGF_SourceStats, "bad sample: offset=%f delay=%f incr_delay=%f allowed=%f", offset, delay, allowed_increase, delay_increase);
#endif
DEBUG_LOG(LOGF_SourceStats, "Bad sample: offset=%f delay=%f incr_delay=%f allowed=%f",
offset, delay, allowed_increase, delay_increase);
return 0;
}

View File

@@ -271,11 +271,6 @@ get_version_specific_details(void)
if (!shift_hz) {
LOG_FATAL(LOGF_SysLinux, "Can't determine hz (txc.tick=%ld txc.freq=%ld (%.8f) txc.offset=%ld)",
tmx_params.tick, tmx_params.freq, tmx_params.dfreq, tmx_params.offset);
} else {
#if 0
LOG(LOGS_INFO, LOGF_SysLinux, "Initial txc.tick=%ld txc.freq=%ld (%.8f) txc.offset=%ld => hz=%d shift_hz=%d",
tmx_params.tick, tmx_params.freq, tmx_params.dfreq, tmx_params.offset, hz, shift_hz);
#endif
}
}
@@ -372,7 +367,7 @@ SYS_Linux_DropRoot(char *user)
}
if (prctl(PR_SET_KEEPCAPS, 1)) {
LOG_FATAL(LOGF_SysLinux, "prcap() failed");
LOG_FATAL(LOGF_SysLinux, "prctl() failed");
}
if (setgroups(0, NULL)) {
@@ -397,9 +392,7 @@ SYS_Linux_DropRoot(char *user)
cap_free(cap);
#if 0
LOG(LOGS_INFO, LOGF_SysLinux, "Privileges dropped to user %s", user);
#endif
DEBUG_LOG(LOGF_SysLinux, "Privileges dropped to user %s", user);
}
#endif
@@ -428,9 +421,8 @@ void SYS_Linux_SetScheduler(int SchedPriority)
LOG(LOGS_ERR, LOGF_SysLinux, "sched_setscheduler() failed");
}
else {
#if 0
LOG(LOGS_INFO, LOGF_SysLinux, "Enabled SCHED_FIFO with priority %d", sched.sched_priority);
#endif
DEBUG_LOG(LOGF_SysLinux, "Enabled SCHED_FIFO with priority %d",
sched.sched_priority);
}
}
}
@@ -454,9 +446,7 @@ void SYS_Linux_MemLockAll(int LockAll)
LOG(LOGS_ERR, LOGF_SysLinux, "mlockall() failed");
}
else {
#if 0
LOG(LOGS_INFO, LOGF_SysLinux, "Successfully locked into RAM");
#endif
DEBUG_LOG(LOGF_SysLinux, "Successfully locked into RAM");
}
}
}

View File

@@ -281,7 +281,6 @@ SYS_NetBSD_Initialise(void)
};
kvm_t *kt;
FILE *fp;
kt = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);
if (!kt) {

View File

@@ -409,11 +409,6 @@ set_dosynctodr(unsigned long on_off)
kvm_close(kt);
assert(read_back == on_off);
#if 0
LOG(LOGS_INFO, LOGF_SysSolaris, "Set value of dosynctodr to %d", on_off);
#endif
}
/* ================================================== */

View File

@@ -364,11 +364,6 @@ setup_kernel(unsigned long on_off)
}
kvm_close(kt);
#if 0
LOG(LOGS_INFO, LOGF_SysSunOS, "Set value of _dosynctodr to %d", on_off);
#endif
}
/* ================================================== */

View File

@@ -62,10 +62,10 @@
#include <syslog.h>
#include <time.h>
#if HAS_STDINT_H
#include <stdint.h>
#elif defined(HAS_INTTYPES_H)
#ifdef HAS_INTTYPES_H
#include <inttypes.h>
#elif HAS_STDINT_H
#include <stdint.h>
#else
/* Tough */
#endif

40
test/simulation/008-ntpera Executable file
View File

@@ -0,0 +1,40 @@
#!/bin/bash
. test.common
test_start "NTP eras"
# Assume NTP_ERA_SPLIT is between years 1960 and 1990
# Set date to 500 seconds before NTP second overflows, this should
# work correctly with both 32-bit and 64-bit time_t
export CLKNETSIM_START_DATE=$(date -d 'Feb 7 06:19:56 UTC 2036' +'%s')
run_test || test_fail
check_chronyd_exit || test_fail
check_source_selection || test_fail
check_packet_interval || test_fail
check_sync || test_fail
# The following tests need 64-bit time_t
grep -q 'HAVE_LONG_TIME_T 1' ../../config.h || test_skip
for year in 1990 2090; do
export CLKNETSIM_START_DATE=$(date -d "Jan 1 00:00:00 UTC $year" +'%s')
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 year in 1950 2130; do
export CLKNETSIM_START_DATE=$(date -d "Jan 1 00:00:00 UTC $year" +'%s')
run_test || test_fail
check_chronyd_exit || test_fail
check_source_selection || test_fail
check_packet_interval || test_fail
# This check is expected to fail
check_sync && test_fail
done
test_pass

22
test/simulation/114-presend Executable file
View File

@@ -0,0 +1,22 @@
#!/bin/bash
. test.common
test_start "presend option"
client_server_options="presend 6"
run_test || test_fail
check_chronyd_exit || test_fail
check_source_selection || test_fail
check_packet_interval || test_fail
check_sync || test_fail
base_delay=5
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

24
test/simulation/115-cmdmontime Executable file
View File

@@ -0,0 +1,24 @@
#!/bin/bash
. test.common
test_start "cmdmon timestamps"
# The following tests need 64-bit time_t
grep -q 'HAVE_LONG_TIME_T 1' ../../config.h || test_skip
limit=2
client_server_options="noselect"
client_conf="local stratum 1"
chronyc_start="0.5"
chronyc_conf="tracking"
for year in `seq 1850 100 2300`; do
date="Jan 1 00:00:00 $year"
export CLKNETSIM_START_DATE=$(date -d "$date UTC" +'%s')
run_test || test_fail
check_chronyd_exit || test_fail
check_chronyc_output "^.*Ref time \(UTC\).*$date.*$" || test_fail
done
test_pass

View File

@@ -2,19 +2,25 @@
. test.common
passed=() failed=()
passed=() failed=() skipped=()
[ $# -gt 0 ] && tests=($@) || tests=([0-9]*-*[^_])
for test in "${tests[@]}"; do
echo "$test ($[${#passed[@]} + ${#failed[@]} + 1]/${#tests[@]})"
./$test && passed=(${passed[@]} $test) || failed=(${failed[@]} $test)
./$test
case $? in
0) passed=(${passed[@]} $test);;
9) skipped=(${skipped[@]} $test);;
*) failed=(${failed[@]} $test);;
esac
echo
done
echo "SUMMARY:"
echo " TOTAL $[${#passed[@]} + ${#failed[@]}]"
echo " TOTAL $[${#passed[@]} + ${#failed[@]} + ${#skipped[@]}]"
echo " PASSED ${#passed[@]}"
echo " FAILED ${#failed[@]} (${failed[@]})"
echo " SKIPPED ${#skipped[@]} (${skipped[@]})"
[ ${#failed} -eq 0 ]
[ ${#failed[@]} -eq 0 ]

View File

@@ -18,7 +18,7 @@ export PATH=../../:$PATH
export CLKNETSIM_PATH=clknetsim
# Known working clknetsim revision
clknetsim_revision=326b619e36858c1f88240e17317595509e3d00de
clknetsim_revision=7ea71b32e0caec4d8da4cecc3499b5c87098e137
clknetsim_url=https://github.com/mlichvar/clknetsim/archive/$clknetsim_revision.tar.gz
# Only Linux is supported
@@ -74,7 +74,7 @@ default_chronyd_options=""
default_time_max_limit=1e-3
default_freq_max_limit=5e-4
default_time_rms_limit=2e-4
default_time_rms_limit=3e-4
default_freq_rms_limit=1e-5
default_min_sync_time=120
default_max_sync_time=210
@@ -101,6 +101,11 @@ test_fail() {
exit 1
}
test_skip() {
echo "SKIP"
exit 9
}
test_ok() {
pad_line
echo -e "\tOK"

76
util.c
View File

@@ -164,13 +164,6 @@ UTI_AverageDiffTimevals (struct timeval *earlier,
be backwards, or something wierd has happened. Maybe when we
change the frequency on Linux? */
/* This seems to be fairly benign, so don't bother logging it */
#if 0
LOG(LOGS_INFO, LOGF_Util, "Earlier=[%s] Later=[%s]",
UTI_TimevalToString(earlier), UTI_TimevalToString(later));
#endif
/* Assume the required behaviour is to treat it as zero */
*diff = 0.0;
}
@@ -214,12 +207,16 @@ static int pool_ptr = 0;
char *
UTI_TimevalToString(struct timeval *tv)
{
char buffer[64], *result;
struct tm stm;
stm = *gmtime((time_t *) &(tv->tv_sec));
strftime(buffer, sizeof(buffer), "%a %x %X", &stm);
char *result;
result = NEXT_BUFFER;
snprintf(result, BUFFER_LENGTH, "%s.%06ld", buffer, (unsigned long)(tv->tv_usec));
#ifdef HAVE_LONG_TIME_T
snprintf(result, BUFFER_LENGTH, "%"PRId64".%06lu",
(int64_t)tv->tv_sec, (unsigned long)tv->tv_usec);
#else
snprintf(result, BUFFER_LENGTH, "%ld.%06lu",
(long)tv->tv_sec, (unsigned long)tv->tv_usec);
#endif
return result;
}
@@ -501,16 +498,17 @@ void
UTI_TimevalToInt64(struct timeval *src,
NTP_int64 *dest, uint32_t fuzz)
{
unsigned long usec = src->tv_usec;
unsigned long sec = src->tv_sec;
uint32_t lo;
uint32_t lo, sec, usec;
sec = (uint32_t)src->tv_sec;
usec = (uint32_t)src->tv_usec;
/* Recognize zero as a special case - it always signifies
an 'unknown' value */
if (!usec && !sec) {
dest->hi = dest->lo = 0;
} else {
dest->hi = htonl(src->tv_sec + JAN_1970);
dest->hi = htonl(sec + JAN_1970);
/* This formula gives an error of about 0.1us worst case */
lo = 4295 * usec - (usec>>5) - (usec>>9);
@@ -528,13 +526,23 @@ void
UTI_Int64ToTimeval(NTP_int64 *src,
struct timeval *dest)
{
uint32_t ntp_sec, ntp_frac;
/* As yet, there is no need to check for zero - all processing that
has to detect that case is in the NTP layer */
dest->tv_sec = ntohl(src->hi) - JAN_1970;
ntp_sec = ntohl(src->hi);
ntp_frac = ntohl(src->lo);
#ifdef HAVE_LONG_TIME_T
dest->tv_sec = ntp_sec - (uint32_t)(NTP_ERA_SPLIT + JAN_1970) +
(time_t)NTP_ERA_SPLIT;
#else
dest->tv_sec = ntp_sec - JAN_1970;
#endif
/* Until I invent a slick way to do this, just do it the obvious way */
dest->tv_usec = (int)(0.5 + (double)(ntohl(src->lo)) / 4294.967296);
dest->tv_usec = (int)(0.5 + (double)(ntp_frac) / 4294.967296);
}
/* ================================================== */
@@ -542,21 +550,22 @@ UTI_Int64ToTimeval(NTP_int64 *src,
void
UTI_TimevalNetworkToHost(Timeval *src, struct timeval *dest)
{
uint32_t sec_low, sec_high;
uint32_t sec_low;
#ifdef HAVE_LONG_TIME_T
uint32_t sec_high;
#endif
dest->tv_usec = ntohl(src->tv_nsec) / 1000;
sec_high = ntohl(src->tv_sec_high);
sec_low = ntohl(src->tv_sec_low);
#ifdef HAVE_LONG_TIME_T
sec_high = ntohl(src->tv_sec_high);
if (sec_high == TV_NOHIGHSEC)
sec_high = 0;
/* get the missing bits from current time when received timestamp
is only 32-bit */
if (sizeof (time_t) > 4 && sec_high == TV_NOHIGHSEC) {
struct timeval now;
gettimeofday(&now, NULL);
sec_high = now.tv_sec >> 16 >> 16;
}
dest->tv_sec = (time_t)sec_high << 16 << 16 | sec_low;
dest->tv_sec = (uint64_t)sec_high << 32 | sec_low;
#else
dest->tv_sec = sec_low;
#endif
}
/* ================================================== */
@@ -565,10 +574,11 @@ void
UTI_TimevalHostToNetwork(struct timeval *src, Timeval *dest)
{
dest->tv_nsec = htonl(src->tv_usec * 1000);
if (sizeof (time_t) > 4)
dest->tv_sec_high = htonl(src->tv_sec >> 16 >> 16);
else
dest->tv_sec_high = htonl(TV_NOHIGHSEC);
#ifdef HAVE_LONG_TIME_T
dest->tv_sec_high = htonl((uint64_t)src->tv_sec >> 32);
#else
dest->tv_sec_high = htonl(TV_NOHIGHSEC);
#endif
dest->tv_sec_low = htonl(src->tv_sec);
}