mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-03 18:45:07 -05:00
Compare commits
95 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ebab36e859 | ||
|
|
3988a1e9a8 | ||
|
|
949ef3e1dc | ||
|
|
dd12303276 | ||
|
|
f1379a6574 | ||
|
|
ad58384760 | ||
|
|
0e786f5907 | ||
|
|
e1accce498 | ||
|
|
28db0fdde9 | ||
|
|
584bf9382b | ||
|
|
0168b405a3 | ||
|
|
b5e0d76337 | ||
|
|
c924fba4fa | ||
|
|
8ec43a39af | ||
|
|
9f16445464 | ||
|
|
1a795b04ee | ||
|
|
b862f3e64d | ||
|
|
4e66b5ce8a | ||
|
|
d446950c6a | ||
|
|
e3c77f9b4b | ||
|
|
090ec985f3 | ||
|
|
e63bd490b0 | ||
|
|
badf97d4ba | ||
|
|
ba283e6b6e | ||
|
|
0bdac2c7b3 | ||
|
|
58b211d707 | ||
|
|
068ce237af | ||
|
|
a5e9e5d0df | ||
|
|
e0af8069c1 | ||
|
|
696b05d6e6 | ||
|
|
7e1a699616 | ||
|
|
716d73d982 | ||
|
|
38ac081114 | ||
|
|
5fce101f85 | ||
|
|
c6e064200d | ||
|
|
c52e9085d1 | ||
|
|
d0fb17d70c | ||
|
|
713153b610 | ||
|
|
09d039fba6 | ||
|
|
07f7f28058 | ||
|
|
a2b40f527d | ||
|
|
6d8ffeefd6 | ||
|
|
9ce25bab04 | ||
|
|
cd5105b1db | ||
|
|
ff4abc69c3 | ||
|
|
192f74f0a1 | ||
|
|
be203d9af0 | ||
|
|
f8af299321 | ||
|
|
474b2af1a6 | ||
|
|
cb88cea3c4 | ||
|
|
fc2892fbb0 | ||
|
|
36b25cbd2b | ||
|
|
d18c071849 | ||
|
|
61b629fdad | ||
|
|
29647c8280 | ||
|
|
97b15cb3ae | ||
|
|
f725921dfb | ||
|
|
a4b4d0c0d8 | ||
|
|
f59ade7f80 | ||
|
|
a9b9e7befe | ||
|
|
ead9394a31 | ||
|
|
80129fa9ab | ||
|
|
18796a3c18 | ||
|
|
f632b6d4cb | ||
|
|
7799e14770 | ||
|
|
20aab86e12 | ||
|
|
b7766478a6 | ||
|
|
3d57b7a44d | ||
|
|
51a2b436f4 | ||
|
|
88015081f2 | ||
|
|
20cc1f6550 | ||
|
|
43cca04c33 | ||
|
|
17d944c333 | ||
|
|
6789b5165c | ||
|
|
d631d7e81f | ||
|
|
c6245dc616 | ||
|
|
4b36799ce1 | ||
|
|
d26bb9b4eb | ||
|
|
698404b02f | ||
|
|
d46d7ad947 | ||
|
|
7c6630905d | ||
|
|
129aa587c6 | ||
|
|
cc1c6c94e3 | ||
|
|
41266cbaa0 | ||
|
|
fbfd261da6 | ||
|
|
71602b8ee6 | ||
|
|
14cae239f6 | ||
|
|
2e9e309a0d | ||
|
|
3fba33d5f5 | ||
|
|
77a7162361 | ||
|
|
75efa5174c | ||
|
|
c62afbe77b | ||
|
|
a6f0688f46 | ||
|
|
5762d33e38 | ||
|
|
9c6d1c214f |
96
INSTALL
96
INSTALL
@@ -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.
|
||||
|
||||
|
||||
@@ -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
27
NEWS
@@ -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
6
README
@@ -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?
|
||||
|
||||
@@ -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"
|
||||
|
||||
522
chrony.texi.in
522
chrony.texi.in
@@ -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
|
||||
|
||||
17
chronyd.8.in
17
chronyd.8.in
@@ -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
|
||||
|
||||
4
client.c
4
client.c
@@ -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
110
cmdmon.c
@@ -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;
|
||||
|
||||
@@ -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
6
conf.c
@@ -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
4
conf.h
@@ -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
55
configure
vendored
@@ -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));'
|
||||
|
||||
17
examples/chrony-wait.service
Normal file
17
examples/chrony-wait.service
Normal 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
|
||||
@@ -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:
|
||||
#
|
||||
|
||||
8
examples/chrony.logrotate
Normal file
8
examples/chrony.logrotate
Normal file
@@ -0,0 +1,8 @@
|
||||
/var/log/chrony/*.log {
|
||||
missingok
|
||||
nocreate
|
||||
sharedscripts
|
||||
postrotate
|
||||
/usr/bin/chronyc -a cyclelogs > /dev/null 2>&1 || true
|
||||
endscript
|
||||
}
|
||||
17
examples/chrony.nm-dispatcher
Normal file
17
examples/chrony.nm-dispatcher
Normal 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
13
examples/chronyd.service
Normal 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
268
faq.txt
@@ -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<->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
140
faqgen.pl
@@ -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;
|
||||
}
|
||||
#}}}
|
||||
|
||||
|
||||
@@ -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
12
keys.c
@@ -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
15
local.c
@@ -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);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
3
local.h
3
local.h
@@ -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
|
||||
|
||||
@@ -187,9 +187,6 @@ void LOG_Message(LOG_Severity severity, LOG_Facility facility,
|
||||
log_message(1, severity, buf);
|
||||
}
|
||||
}
|
||||
|
||||
exit(1);
|
||||
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
|
||||
@@ -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
6
main.c
@@ -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();
|
||||
|
||||
38
make_release
38
make_release
@@ -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
|
||||
|
||||
206
ntp_core.c
206
ntp_core.c
@@ -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
278
ntp_io.c
@@ -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);
|
||||
}
|
||||
|
||||
7
ntp_io.h
7
ntp_io.h
@@ -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 */
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
44
reference.c
44
reference.c
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
74
rtc.c
@@ -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
3
rtc.h
@@ -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);
|
||||
|
||||
75
rtc_linux.c
75
rtc_linux.c
@@ -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;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -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
78
sched.c
@@ -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);
|
||||
}
|
||||
|
||||
62
sources.c
62
sources.c
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
20
sys_linux.c
20
sys_linux.c
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,7 +281,6 @@ SYS_NetBSD_Initialise(void)
|
||||
};
|
||||
|
||||
kvm_t *kt;
|
||||
FILE *fp;
|
||||
|
||||
kt = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);
|
||||
if (!kt) {
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -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
40
test/simulation/008-ntpera
Executable 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
22
test/simulation/114-presend
Executable 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
24
test/simulation/115-cmdmontime
Executable 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
|
||||
@@ -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 ]
|
||||
|
||||
@@ -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
76
util.c
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user