Compare commits

...

117 Commits

Author SHA1 Message Date
Miroslav Lichvar
711cda6aed Update NEWS 2012-02-28 13:11:56 +01:00
Miroslav Lichvar
0c738d84af Update copyright years 2012-02-28 13:11:56 +01:00
Miroslav Lichvar
be1e1dc441 Fix password handling in chronyc 2012-02-28 13:11:56 +01:00
Miroslav Lichvar
2a305d8e16 Fix compiler warnings 2012-02-27 16:08:21 +01:00
Miroslav Lichvar
15b6ab77ea Update configure help text 2012-02-27 15:45:27 +01:00
Miroslav Lichvar
6199822783 Test leap second timezone on start 2012-02-27 13:28:14 +01:00
Miroslav Lichvar
0b72b2940a Update documentation 2012-02-27 13:28:14 +01:00
Miroslav Lichvar
d4ce3f19c3 Reschedule fast slew timeout on offset change 2012-02-24 16:26:53 +01:00
Miroslav Lichvar
824e86a82f Add leap status to tracking log and report 2012-02-24 11:06:20 +01:00
Miroslav Lichvar
2a5c045c3d Add support for reading leap second data from tz database
leapsectz directive is used to set the name of the timezone in the
system tz database which chronyd can use to find out when will the next
leap second occur.  It will periodically check if dates Jun 30 23:59:60
and Dec 31 23:59:60 are valid in that timezone. This is mainly useful
with reference clocks which don't provide the leap second information.
It is not necessary to restart chronyd if the tz database is updated
with a new leap second at least 12 hours before the event.
2012-02-24 11:06:20 +01:00
Miroslav Lichvar
f7c65a4b88 Add maxchange directive
This directive sets the maximum allowed offset corrected on a clock
update.  The check is performed only after the specified number of
updates to allow a large initial adjustment of the system clock.  When
an offset larger than the specified maximum occurs, it will be ignored
for the specified number of times and then chronyd will give up
and exit (a negative value can be used to never exit).  In both cases
a message is sent to syslog.
2012-02-21 14:34:09 +01:00
Miroslav Lichvar
a8956f2f56 Move refclock slew and dispersion handler init 2012-02-14 18:13:15 +01:00
Miroslav Lichvar
91c9f84a01 Step system time in RTC preinit only with offsets over 1 second 2012-02-14 17:49:55 +01:00
Miroslav Lichvar
2be89bc6f2 Fix last commit 2012-02-14 14:47:57 +01:00
Miroslav Lichvar
d6c447a445 Better estimate RTC offset right after trim 2012-02-13 16:54:18 +01:00
Miroslav Lichvar
a60586eaad Return success on empty command 2012-02-10 18:30:11 +01:00
Miroslav Lichvar
d77356837a Support passwords encoded in HEX 2012-02-09 16:56:17 +01:00
Miroslav Lichvar
d6842301dd Update reported RMS offset quickly on start 2012-02-08 14:30:35 +01:00
Miroslav Lichvar
19b3c5be26 Extend tracking, sources and activity reports 2012-02-03 17:22:53 +01:00
Miroslav Lichvar
5fb5a89f02 Use +/- when logging skew on start 2012-02-03 17:22:52 +01:00
Miroslav Lichvar
9367e7b9af Fix logged offset in manual reference 2012-02-03 15:23:25 +01:00
Miroslav Lichvar
6673cadfa2 Check if struct in6_pktinfo is usable 2012-01-05 15:11:54 +01:00
Miroslav Lichvar
b485051b65 Fix reported number of runs to correspond to reported number of samples 2011-11-28 11:19:48 +01:00
Miroslav Lichvar
9a01ccc07f Add corrtimeratio directive
The corrtimeratio directive controls the ratio between the
duration in which the clock is slewed for an average correction
according to the source history and the interval in which the
corrections are done (usually the NTP polling interval).  Corrections
larger than the average take less time and smaller corrections take
more time, the amount of the correction and the correction time are
inversely proportional.

Increasing corrtimeratio makes the overall frequency error of
the system clock smaller, but increases the overall time error as
the corrections will take longer.

By default, the ratio is 1, which means the duration of an average
correction will be close to the update interval.
2011-11-15 18:25:49 +01:00
Miroslav Lichvar
1b8deaf354 Control offset correction rate in Linux driver
The kernel currently doesn't support a linear adjustment with
programmable rate, extend the use of the kernel PLL with locked
frequency instead.

Set the PLL time constant according to the correction time corresponding
to the correction rate and corrected offset.

On kernels with nano PLL adjtime() is no longer used.
2011-11-15 12:30:59 +01:00
Miroslav Lichvar
c7d0232bb1 Introduce offset correction rate
We want to correct the offset quickly, but we also want to keep the
frequency error caused by the correction itself low.

Define correction rate as the area of the region bounded by the graph of
offset corrected in time. Set the rate so that the time needed to correct
an offset equal to the current sourcestats stddev will be equal to the
update interval (assuming linear adjustment). The offset and the
time needed to make the correction are inversely proportional.

This is only a suggestion and it's up to the system driver how the
adjustment will be executed.
2011-11-15 12:27:44 +01:00
Miroslav Lichvar
79e5f2be13 Include clock steps in calculated reference update interval 2011-11-14 15:55:19 +01:00
Miroslav Lichvar
9ab181eb9c Document extended keyfile format and authhash command 2011-11-02 13:53:00 +01:00
Miroslav Lichvar
3cc6021e03 Add support for libtomcrypt 2011-11-02 13:53:00 +01:00
Miroslav Lichvar
375389fa1e Add support for NSS library
This adds support for the NSSLOWHASH API provided by the freebl3
library.
2011-11-02 13:53:00 +01:00
Miroslav Lichvar
777303f130 Add support for different authentication hashes
Allow different hash functions to be used in the NTP and cmdmon
protocols. This breaks the cmdmon protocol compatibility. Extended key
file format is used to specify the hash functions for chronyd and new
authhash command is added to chronyc. MD5 is the default and the only
function included in the chrony source code, other functions will be
available from libraries.
2011-11-02 13:53:00 +01:00
Miroslav Lichvar
6015f99d98 Fix writing rtc data when called soon after trimrtc 2011-09-14 18:03:01 +02:00
Miroslav Lichvar
78fc17c661 Use ADJ_OFFSET_SS_READ mode only with kernels 2.6.28 and later 2011-09-13 16:39:08 +02:00
Miroslav Lichvar
d42addf746 Add macro for maximum fastslew timeout 2011-09-01 18:08:45 +02:00
Miroslav Lichvar
f570eb76b3 Check for timepps.h also in sys directory 2011-09-01 17:06:54 +02:00
Miroslav Lichvar
cc3f5962b8 Merge NCR_Process functions 2011-09-01 16:25:13 +02:00
Miroslav Lichvar
6ab3d1daa3 Add support for ADJ_SETOFFSET mode
This adjtimex mode allows precise stepping of the system clock.
2011-09-01 15:31:11 +02:00
Miroslav Lichvar
b088b70f82 Check sample ordering on accumulation
If the newly accumulated sample is not newer than than the last one,
discard the source history and start from scratch. This can happen after
loading an invalid dump or when the system clock was stepped.
2011-08-31 18:36:10 +02:00
Miroslav Lichvar
fbbb6bbc00 Update gpsd SOCK example in documentation 2011-08-26 18:34:00 +02:00
Miroslav Lichvar
5c36342958 Use initial delay also for burst samples 2011-08-26 18:34:00 +02:00
Miroslav Lichvar
f1a0cacc5a Make scheduling loop detector less sensitive
It could be triggered by delayed name resolving as it adds multiple new
timeouts which can be called in the same dispatching if the DNS responses
are slower than initial delay and sampling separation.

Compare number of dispatched events also with current number of
timeouts.
2011-08-26 18:34:00 +02:00
Miroslav Lichvar
1d2a0856b4 Wait in foreground process until daemon is fully initialized
Exit when all sockets are ready and initstepslew command and rtc step
are completed. Also, in case of a fatal error, print the error message
and exit with a non-zero status.
2011-08-26 18:31:26 +02:00
Miroslav Lichvar
7fb50d9a3e Always use delayed name resolving for server and peer directives
This significantly reduces initialization time.
2011-08-26 14:22:10 +02:00
Miroslav Lichvar
919b5b5a7d Change working directory to / 2011-08-25 18:49:34 +02:00
Miroslav Lichvar
1e35b26826 Read config after opening syslog 2011-08-25 14:46:16 +02:00
Miroslav Lichvar
27b0b5824a Disable maxdelayratio test by default
Change default maxdelayratio from 16384.0 to 0.0. A value larger
than 1.0 is required to enable the test.
2011-08-12 15:38:05 +02:00
Miroslav Lichvar
1d72d22bc5 Match skew in ntp_core to sourcestats skew 2011-08-12 15:38:05 +02:00
Miroslav Lichvar
e0c9ed44f9 Limit skew used in NTP test4
With iburst and very jittery sources the source skew can reach very high
values which makes the NTP test4 fail even with relatively small delays.
Limit the skew to 2000 ppm to avoid getting state where a source is unable
to accept more than first three iburst samples.
2011-08-12 15:37:58 +02:00
Miroslav Lichvar
411f4da340 Fix creating logdir 2011-08-11 14:15:15 +02:00
Miroslav Lichvar
4fac84098e Update NEWS 2011-07-13 14:55:28 +02:00
Miroslav Lichvar
21b2063a6f Retry on permanent DNS error by default 2011-07-13 14:49:22 +02:00
Miroslav Lichvar
917c191650 Update NEWS 2011-06-24 13:45:16 +02:00
Miroslav Lichvar
2bfce03d29 Add configure option for sendmail path 2011-06-24 13:27:30 +02:00
Miroslav Lichvar
1cb8167be0 Generate version and date in man pages 2011-06-24 12:30:48 +02:00
Miroslav Lichvar
40d33cc64d Convert make_release to shell script 2011-06-24 12:27:54 +02:00
Miroslav Lichvar
95433e9639 Remove chrony.lsm 2011-06-23 17:49:18 +02:00
Miroslav Lichvar
bbe1a09e7e Step also cooked select timestamp in scheduler slew handler 2011-06-23 15:23:16 +02:00
Miroslav Lichvar
dce2366b3a Detect infinite loop in scheduler
If more timeouts were handled than there were in the timer queue on
start, assume some code is scheduling timeouts with negative delays and
abort. Make the actual limit higher in case the machine is temporarily
overloaded and dispatching the handlers takes more time than was delay
of a scheduled timeout.
2011-06-23 15:14:08 +02:00
Miroslav Lichvar
bab7ba22cf Add asserts for timeout delays 2011-06-23 13:42:04 +02:00
Miroslav Lichvar
d6a91057ae Add waitsync command 2011-06-23 12:13:51 +02:00
Miroslav Lichvar
c6e9065498 Fix current_total_tick calculation 2011-06-15 15:35:15 +02:00
Miroslav Lichvar
22fda21eae Don't call driver read_freq in LCL_ReadAbsoluteFrequency 2011-06-15 15:35:14 +02:00
Miroslav Lichvar
103a520aa6 Create logdir before making first tracking write 2011-06-15 15:35:14 +02:00
Miroslav Lichvar
86531a51a7 Don't update drift file on first reference update 2011-06-15 15:35:14 +02:00
Miroslav Lichvar
2b7e4d645f Don't reset kernel frequency on start without drift file 2011-06-15 15:35:00 +02:00
Miroslav Lichvar
a5f63180fc Don't use uninitialized values 2011-06-13 18:17:33 +02:00
Miroslav Lichvar
934d4e04b5 Validate leap status in refclock samples 2011-06-13 17:03:30 +02:00
Miroslav Lichvar
1b8547059a Set leap status by enum 2011-06-13 17:02:42 +02:00
Miroslav Lichvar
91279a0f28 Store reference IDs in uint32_t 2011-06-13 15:34:16 +02:00
Miroslav Lichvar
31ba3144c8 Don't limit refclock driver name to 4 chars 2011-06-13 13:49:46 +02:00
Miroslav Lichvar
0bf34725e3 Don't try to recover from our own time steps 2011-06-10 18:57:04 +02:00
Miroslav Lichvar
91749ebb2b Try to handle unexpected backward time jumps 2011-06-10 18:29:41 +02:00
Miroslav Lichvar
4ba3dd66ad Set version string in config.h 2011-06-09 14:32:22 +02:00
Miroslav Lichvar
d40696f7f3 Add .deps to .gitignore 2011-06-09 14:31:04 +02:00
Miroslav Lichvar
4a401a9e83 Make .deps order-only prerequisite 2011-06-09 13:56:45 +02:00
Miroslav Lichvar
6a2a837ede Remove kernel version check from rtc code
It should work with all currently supported kernels (>= 2.2.0).
2011-06-06 21:33:59 +02:00
Miroslav Lichvar
eca08a281c Determine hz and shift from sysconf(_SC_CLK_TCK) when available 2011-06-06 17:41:14 +02:00
Miroslav Lichvar
9fd8f76fa0 Log final version specific details 2011-06-06 17:12:31 +02:00
Miroslav Lichvar
50de930730 Drop support for old readonly adjtime 2011-06-06 17:12:31 +02:00
Miroslav Lichvar
da1097095c Drop support for pre 2.2 Linux kernels 2011-06-06 17:12:31 +02:00
Miroslav Lichvar
ec7d302a6c Support Linux 3.0 and later 2011-06-06 13:56:27 +02:00
Miroslav Lichvar
8cc7ebffa9 Accept packets with compatible NTP versions
All incoming NTP packets are now required to have version 2, 3 or 4.
2011-05-25 16:59:40 +02:00
Miroslav Lichvar
de4d14843f Set source IPv6 address on NTP reply
This is needed on systems with multiple IPv6 addresses to reply with
the same source address as the destination address of the NTP request.
2011-05-24 18:07:06 +02:00
Miroslav Lichvar
18605795a7 Merge CCWARNFLAGS with CFLAGS 2011-05-24 18:07:06 +02:00
Miroslav Lichvar
da2c8d9076 Use config.h 2011-05-24 18:07:06 +02:00
Miroslav Lichvar
3120f8adb6 Use object dependencies in Makefile 2011-05-24 18:06:49 +02:00
Miroslav Lichvar
2dcc16169b Update NEWS 2011-05-04 12:29:40 +02:00
Miroslav Lichvar
a8efd8c398 Update versions in man pages 2011-05-02 13:21:50 +02:00
Miroslav Lichvar
bb40f4aff4 Modify weight calculation again
Dividing the weights by variance or unweighted variance seems to have a
significant negative impact on response with normally distributed
network delays.

Divide by the difference between the mean and minimum distance instead.
It should be stable as there is no loop and the response seems to be a
good compromise between the original minimum distance weighting which
works well with normally distributed delays and the variance weighting
which works well with exponentially distributed delays.
2011-04-29 13:29:56 +02:00
Miroslav Lichvar
66c7ac4d24 Revert using unweighted variance in weight calculation
This reverts commit 165e6805ab.
2011-04-29 13:29:24 +02:00
Miroslav Lichvar
7f12919fea Increase smoothing factor in refclock variance 2011-04-20 12:41:05 +02:00
Miroslav Lichvar
55e0c6a0a1 Update NEWS 2011-04-18 12:59:06 +02:00
Miroslav Lichvar
20f306602b Add another chrony.conf example 2011-04-18 12:57:01 +02:00
Miroslav Lichvar
70735d8d79 Ignore extra samples in reported nruns 2011-04-18 12:36:02 +02:00
Miroslav Lichvar
165e6805ab In weight calculation use unweighted variance from last regression
This fixes a positive feedback where weights could reach inf.
Also change the SD_TO_DIST_RATIO constant to get close to the original
response.
2011-04-13 18:43:25 +02:00
Miroslav Lichvar
2a0c35646c Allow changing tick up to max_tick_bias 2011-04-12 16:40:22 +02:00
Miroslav Lichvar
28710e0449 Change default maxclockerror to 1 ppm 2011-04-11 17:54:01 +02:00
Miroslav Lichvar
c5587b60b2 Set reference time to last sample instead of time on update
This is done mainly to fix reported root dispersion to include max clock
error after selecting another source without new sample.
2011-04-11 17:52:04 +02:00
Miroslav Lichvar
bb95c39356 Update refclock documentation 2011-04-08 16:53:11 +02:00
Miroslav Lichvar
20a43409c6 Add new commands to protocol comment in candm.h 2011-04-07 18:35:02 +02:00
Miroslav Lichvar
4699f7ca0b Update client copyright message 2011-04-07 18:35:02 +02:00
Miroslav Lichvar
bc7586b3f4 Assert there are no unhandled commands in cmdmon 2011-04-07 18:34:47 +02:00
Miroslav Lichvar
8d3d45ea1a Add reselectdist command 2011-04-07 18:16:39 +02:00
Miroslav Lichvar
21ba1d3761 Don't add \n to chronyc command line arguments
This fixes parsing of some commands.
2011-04-07 16:17:58 +02:00
Miroslav Lichvar
e79584bb9e Revert marking offline sources as unreachable 2011-04-07 14:44:56 +02:00
Miroslav Lichvar
bca7819247 Don't crash when sources report is requested soon after start 2011-04-06 16:59:40 +02:00
Miroslav Lichvar
0ecabae2c3 Add include directive 2011-04-06 16:58:12 +02:00
Miroslav Lichvar
598c04eea2 Add configure option to force retry on DNS failure
This is apparently needed on system which keep nameservers specified
in /etc/resolv.conf even when there is no network connection. Should be
used with care as invalid names will be retried forever.
2011-04-05 18:14:05 +02:00
Miroslav Lichvar
faec23f6bd Don't update empty sourcestats on clock update 2011-04-05 16:32:50 +02:00
Miroslav Lichvar
896dad9224 Fix warnings produced by latest gcc 2011-02-15 18:55:34 +01:00
Miroslav Lichvar
680612cf09 Reduce Linux driver verbosity 2011-02-15 17:22:40 +01:00
Miroslav Lichvar
3fbd4bb15f Don't log error on opening driftfile
Log frequency and skew values read from the driftfile instead.
2011-02-15 16:56:30 +01:00
Miroslav Lichvar
cb9055072d Make starting log even in debug mode 2011-02-14 18:21:38 +01:00
Miroslav Lichvar
0fc9b555f1 Don't log in signal handler 2011-02-14 18:19:58 +01:00
Miroslav Lichvar
6ed58628f5 Don't use uninitialized memory when setting RTC time 2011-02-11 17:56:05 +01:00
Miroslav Lichvar
efff149988 Use system headers for Linux RTC support 2011-02-11 17:56:05 +01:00
Miroslav Lichvar
b02d4092f1 Fix compiler warnings in PPS configure test 2011-02-11 17:31:38 +01:00
79 changed files with 2748 additions and 1352 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
.deps
*.swp
*.o
Makefile

View File

@@ -29,30 +29,28 @@ INFODIR=@INFODIR@
DOCDIR=@DOCDIR@
CC = @CC@
CCWARNFLAGS = @CCWARNFLAGS@
OPTFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@ @SYSDEFS@ @EXTRA_DEFS@
CFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@
DESTDIR=
HASH_OBJ = @HASH_OBJ@
OBJS = util.o sched.o regress.o local.o \
sys.o main.o ntp_io.o ntp_core.o ntp_sources.o \
sources.o sourcestats.o reference.o \
logging.o conf.o cmdmon.o md5.o keys.o \
logging.o conf.o cmdmon.o keys.o \
nameserv.o acquire.o manual.o addrfilt.o \
cmdparse.o mkdirpp.o rtc.o pktlength.o clientlog.o \
broadcast.o refclock.o refclock_shm.o refclock_sock.o \
refclock_pps.o tempcomp.o
refclock_pps.o tempcomp.o $(HASH_OBJ)
EXTRA_OBJS=@EXTRA_OBJECTS@
CLI_OBJS = client.o md5.o nameserv.o getdate.o cmdparse.o \
pktlength.o util.o
CLI_OBJS = client.o nameserv.o getdate.o cmdparse.o \
pktlength.o util.o $(HASH_OBJ)
SRCS = $(patsubst %.o,%.c,$(OBJS))
EXTRA_SRCS = $(patsubst %.o,%.c,$(EXTRA_OBJS))
CLI_SRCS = $(patsubst %.o,%.c,$(CLI_OBJS))
ALL_OBJS = $(OBJS) $(EXTRA_OBJS) $(CLI_OBJS)
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
@@ -60,36 +58,29 @@ LIBS = @LIBS@
EXTRA_LIBS=@EXTRA_LIBS@
EXTRA_CLI_LIBS=@EXTRA_CLI_LIBS@
CFLAGS = $(CCWARNFLAGS) $(OPTFLAGS)
# Until we have a main procedure we can link, just build object files
# to test compilation
all : chronyd chronyc
chronyd : $(OBJS) $(EXTRA_OBJS)
$(CC) $(OPTFLAGS) -o chronyd $(OBJS) $(EXTRA_OBJS) $(LDFLAGS) $(LIBS) $(EXTRA_LIBS)
$(CC) $(CFLAGS) -o chronyd $(OBJS) $(EXTRA_OBJS) $(LDFLAGS) @HASH_LINK@ $(LIBS) $(EXTRA_LIBS)
chronyc : $(CLI_OBJS)
$(CC) $(OPTFLAGS) -o chronyc $(CLI_OBJS) $(LDFLAGS) @READLINE_LINK@ $(LIBS) $(EXTRA_CLI_LIBS)
conf.o : conf.c
$(CC) $(CFLAGS) $(CPPFLAGS) -DDEFAULT_CONF_DIR=\"$(SYSCONFDIR)\" -c $<
$(CC) $(CFLAGS) -o chronyc $(CLI_OBJS) $(LDFLAGS) @READLINE_LINK@ @HASH_LINK@ $(LIBS) $(EXTRA_CLI_LIBS)
client.o : client.c
$(CC) $(CFLAGS) $(CPPFLAGS) @READLINE_COMPILE@ -c $<
.depend :
gcc -MM $(SRCS) $(EXTRA_SRCS) > .depend
$(HASH_OBJ) : $(patsubst %.o,%.c,$(HASH_OBJ))
$(CC) $(CFLAGS) $(CPPFLAGS) @HASH_COMPILE@ -c $<
distclean :
-rm -f *.o *.s chronyc chronyd core options.h Makefile *~
distclean : clean
-rm -f Makefile
clean :
-rm -f *.o *.s chronyc chronyd core *~
version.h : version.txt
./mkversion
-rm -rf .deps
getdate.c : ;
getdate :
@@ -133,8 +124,6 @@ install: chronyd chronyc
%.s : %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -S $<
main.o logging.o client.o : version.h
# makeinfo v4 required to generate plain text and html
MAKEINFO:=makeinfo
@@ -163,3 +152,10 @@ chrony.info : chrony.texi
faq.php : faq.txt faqgen.pl
perl faqgen.pl < faq.txt > faq.php
.deps:
@mkdir .deps
.deps/%.d: %.c | .deps
@$(CC) -MM $(CPPFLAGS) -MT '$(<:%.c=%.o) $@' $< -o $@
-include $(ALL_OBJS:%.o=.deps/%.d)

33
NEWS
View File

@@ -1,3 +1,30 @@
New in version 1.27
===================
* Support for stronger keys via NSS or libtomcrypt library
* Support reading leap second data from tz database
* Support for precise clock stepping on Linux
* Make offset corrections smoother on Linux
* Add corrtimeratio and maxchange directives
* Extend tracking, sources and activity reports
* Wait in foreground process until daemon is fully initialized
* Fix crash with slow name resolving
* Fix iburst with jittery sources
* Fix offset stored in rtc data right after trimrtc
* Don't use readonly adjtime on Linux kernels before 2.6.28
* Changed chronyc protocol, incompatible with older versions
New in version 1.26
===================
* Add compatibility with Linux 3.0 and later
* Use proper source address in NTP replies on multihomed IPv6 hosts
* Accept NTP packets with versions 4, 3 and 2
* Cope with unexpected backward time jumps
* Don't reset kernel frequency on start without drift file
* Retry on permanent DNS error by default
* Add waitsync command
New in version 1.25
===================
@@ -6,6 +33,7 @@ New in version 1.25
* Improve polling interval adjustment
* Improve stability with temporary asymmetric delays
* Improve source selection
* Improve initial synchronisation
* Add delayed server name resolving
* Add temperature compensation
* Add nanosecond slewing to Linux driver
@@ -13,7 +41,8 @@ New in version 1.25
* Add iburst, minstratum, maxdelaydevratio, polltarget,
prefer, noselect options
* Add rtcsync directive to enable Linux 11-minute mode
* Add reselectdist, stratumweight, logbanner, maxclockerror directives
* Add reselectdist, stratumweight, logbanner, maxclockerror,
include directives
* Add -n option to not detach daemon from terminal
* Fix pidfile directive
* Fix name resolving with disabled IPv6 support
@@ -23,9 +52,9 @@ New in version 1.25
* Fix file descriptor leaks
* Increase burst polling interval and stop on KoD RATE
* Set maxupdateskew to 1000 ppm by default
* Consider offline sources unreachable
* Require password for clients command
* Update drift file at most once per hour
* Use system headers for Linux RTC support
* Reduce default chronyc timeout and make it configurable
* Avoid large values in chronyc sources and sourcestats output
* Add reselect command to force reselecting best source

View File

@@ -37,6 +37,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "acquire.h"
@@ -61,6 +63,10 @@
#define RETRANSMISSION_TIMEOUT (1.0)
#define NTP_VERSION 3
#define NTP_MAX_COMPAT_VERSION 4
#define NTP_MIN_COMPAT_VERSION 2
typedef struct {
IPAddr ip_addr; /* Address of the server */
int sanity; /* Flag indicating whether source
@@ -244,7 +250,7 @@ static void
probe_source(SourceRecord *src)
{
NTP_Packet pkt;
int version = 3;
int version = NTP_VERSION;
NTP_Mode my_mode = MODE_CLIENT;
struct timeval cooked;
union sockaddr_in46 his_addr;
@@ -264,7 +270,7 @@ probe_source(SourceRecord *src)
pkt.precision = -6; /* as ntpdate */
pkt.root_delay = double_to_int32(1.0); /* 1 second */
pkt.root_dispersion = double_to_int32(1.0); /* likewise */
pkt.reference_id = 0UL;
pkt.reference_id = 0;
pkt.reference_ts.hi = 0; /* Set to 0 */
pkt.reference_ts.lo = 0; /* Set to 0 */
pkt.originate_ts.hi = 0; /* Set to 0 */
@@ -370,7 +376,7 @@ process_receive(NTP_Packet *msg, SourceRecord *src, struct timeval *now)
mode = lvm & 0x7;
if ((leap == LEAP_Unsynchronised) ||
(version != 3) ||
(version < NTP_MIN_COMPAT_VERSION || version > NTP_MAX_COMPAT_VERSION) ||
(mode != MODE_SERVER && mode != MODE_PASSIVE)) {
return;
}
@@ -702,7 +708,7 @@ process_measurements(void)
LOG(LOGS_INFO, LOGF_Acquire, "System's initial offset : %.6f seconds %s of true (slew)",
fabs(estimated_offset),
(estimated_offset >= 0) ? "fast" : "slow");
LCL_AccumulateOffset(estimated_offset);
LCL_AccumulateOffset(estimated_offset, 0.0);
}
} else {

View File

@@ -28,6 +28,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "addrfilt.h"

View File

@@ -24,6 +24,8 @@
Deal with broadcast server functions.
*/
#include "config.h"
#include "sysincl.h"
#include "memory.h"
@@ -71,7 +73,7 @@ timeout_handler(void *arbitrary)
int leap;
int are_we_synchronised, our_stratum;
NTP_Leap leap_status;
unsigned long our_ref_id;
uint32_t our_ref_id;
struct timeval our_ref_time;
double our_root_delay, our_root_dispersion;
struct timeval local_transmit;
@@ -89,7 +91,7 @@ timeout_handler(void *arbitrary)
if (are_we_synchronised) {
leap = (int) leap_status;
} else {
leap = 3;
leap = LEAP_Unsynchronised;
}
message.lvm = ((leap << 6) &0xc0) | ((version << 3) & 0x38) | (MODE_BROADCAST & 0x07);

40
candm.h
View File

@@ -31,6 +31,7 @@
#include "sysincl.h"
#include "addressing.h"
#include "hash.h"
/* This is the default port to use for CANDM, if no alternative is
defined */
@@ -86,7 +87,8 @@
#define REQ_MODIFY_POLLTARGET 46
#define REQ_MODIFY_MAXDELAYDEVRATIO 47
#define REQ_RESELECT 48
#define N_REQUEST_TYPES 49
#define REQ_RESELECTDISTANCE 49
#define N_REQUEST_TYPES 50
/* Special utoken value used to log on with first exchange being the
password. (This time value has long since gone by) */
@@ -339,6 +341,11 @@ typedef struct {
int32_t EOR;
} REQ_Reselect;
typedef struct {
Float distance;
int32_t EOR;
} REQ_ReselectDistance;
/* ================================================== */
#define PKT_TYPE_CMD_REQUEST 1
@@ -359,11 +366,14 @@ typedef struct {
Version 4 : IPv6 addressing added, 64-bit time values, sourcestats
and tracking reports extended, added flags to NTP source request,
trimmed source report, replaced fixed-point format with floating-point
and used also instead of integer microseconds
and used also instead of integer microseconds, new commands: modify stratum,
modify polltarget, modify maxdelaydevratio, reselect, reselectdistance
Version 5 : auth data moved to the end of the packet to allow hashes with
different sizes, extended sources, tracking and activity reports
*/
#define PROTO_VERSION_NUMBER 4
#define PROTO_VERSION_NUMBER 5
/* The oldest protocol version that is compatible enough with
the current version to report a version mismatch */
@@ -383,7 +393,6 @@ typedef struct {
uint32_t sequence; /* Client's sequence number */
uint32_t utoken; /* Unique token per incarnation of daemon */
uint32_t token; /* Command token (to prevent replay attack) */
uint32_t auth[4]; /* MD5 authentication of the packet */
union {
REQ_Online online;
@@ -425,8 +434,13 @@ typedef struct {
REQ_MakeStep make_step;
REQ_Activity activity;
REQ_Reselect reselect;
REQ_ReselectDistance reselect_distance;
} data; /* Command specific parameters */
/* authentication of the packet, there is no hole after the actual data
from the data union, this field only sets the maximum auth size */
uint8_t auth[MAX_HASH_LENGTH];
} CMD_Request;
/* ================================================== */
@@ -495,12 +509,17 @@ typedef struct {
#define RPY_SD_ST_CANDIDATE 4
#define RPY_SD_ST_OUTLYER 5
#define RPY_SD_FLAG_NOSELECT 0x1
#define RPY_SD_FLAG_PREFER 0x2
typedef struct {
IPAddr ip_addr;
uint16_t poll;
uint16_t stratum;
uint16_t state;
uint16_t mode;
uint16_t flags;
uint16_t reachability;
uint32_t since_sample;
Float orig_latest_meas;
Float latest_meas;
@@ -511,14 +530,18 @@ typedef struct {
typedef struct {
uint32_t ref_id;
IPAddr ip_addr;
uint32_t stratum;
uint16_t stratum;
uint16_t leap_status;
Timeval ref_time;
Float current_correction;
Float last_offset;
Float rms_offset;
Float freq_ppm;
Float resid_freq_ppm;
Float skew_ppm;
Float root_delay;
Float root_dispersion;
Float last_update_interval;
int32_t EOR;
} RPY_Tracking;
@@ -606,6 +629,7 @@ typedef struct {
int32_t offline;
int32_t burst_online;
int32_t burst_offline;
int32_t unresolved;
int32_t EOR;
} RPY_Activity;
@@ -624,8 +648,6 @@ typedef struct {
uint32_t utoken; /* Unique token per incarnation of daemon */
uint32_t token; /* New command token (only if command was successfully
authenticated) */
uint32_t auth[4]; /* MD5 authentication of the packet */
union {
RPY_Null null;
RPY_N_Sources n_sources;
@@ -641,6 +663,10 @@ typedef struct {
RPY_Activity activity;
} data; /* Reply specific parameters */
/* authentication of the packet, there is no hole after the actual data
from the data union, this field only sets the maximum auth size */
uint8_t auth[MAX_HASH_LENGTH];
} CMD_Reply;
/* ================================================== */

View File

@@ -1,4 +1,4 @@
.TH CHRONY 1 "December 04, 2009" chrony "User's Manual"
.TH CHRONY 1 "@MAN_DATE@" "chrony @VERSION@" "User's Manual"
.SH NAME
chrony \- programs for keeping computer clocks accurate

View File

@@ -1,4 +1,4 @@
.TH chrony.conf 5 "December 04, 2009" chrony "Configuration Files"
.TH chrony.conf 5 "@MAN_DATE@" "chrony @VERSION@" "Configuration Files"
.SH NAME
chrony.conf \- chronyd configuration file

View File

@@ -1,29 +0,0 @@
Begin3
Title: chrony
Version: 1.18
Entered-date: 01APR02
Description: A pair of programs for keeping computer clocks accurate.
chronyd is a background (daemon) program and chronyc is a
command-line interface to it. Time reference sources for
chronyd can be RFC1305 NTP servers, human (via keyboard and
chronyc), and the computer's real-time clock at boot time
(Linux only). chronyd can determine the rate at which the
computer gains or loses time and compensate for it whilst no
external reference is present. chronyd's use of NTP servers
can be switched on and off (through chronyc) to support
computers with dial-up/intermittent access to the
Internet. chronyd can also act as an RFC1305-compatible NTP
server.
Keywords: time NTP RFC1305 RTC adjtime
Author: rc@rc0.org.uk (Richard Curnow)
Maintained-by: rc@rc0.org.uk (Richard Curnow)
Primary-site: chrony.tuxfamily.org
295k chrony-1.18.tar.gz
2k chrony.lsm
Platforms: Linux 2.0/2.1/2.2/2.3/2.4 (x86, powerpc)
Solaris 2.5/6/7/8, SunOS 4.1.4. (Sparc)
BSDI/386.
NetBSD
Solaris 2.8 (x86)
Copying-policy: GPL
End

View File

@@ -1173,14 +1173,17 @@ directives can occur in any order in the file.
* cmdallow directive:: Give control access to chronyc on other computers
* cmddeny directive:: Deny control access to chronyc on other computers
* commandkey directive:: Set runtime command key
* corrtimeratio directive:: Set correction time ratio
* cmdport directive:: Set port to use for runtime commanding
* deny directive:: Deny access to NTP clients
* driftfile directive:: Specify location of file containing drift data
* dumpdir directive:: Specify directory for dumping measurements
* dumponexit directive:: Dump measurements when daemon exits
* fallbackdrift directive:: Specify fallback drift intervals
* include directive:: Include a configuration file
* initstepslew directive:: Trim the system clock on boot-up.
* keyfile directive:: Specify location of file containing keys
* leapsectz directive:: Read leap second data from tz database
* linux_hz directive:: Define a non-standard value of the kernel HZ constant
* linux_freq_scale directive:: Define a non-standard value to compensate the kernel frequency bias
* local directive:: Allow unsynchronised machine to act as server
@@ -1190,6 +1193,7 @@ directives can occur in any order in the file.
* logdir directive:: Specify directory for logging
* mailonchange directive:: Send email if a clock correction above a threshold occurs
* makestep directive:: Step system clock if large correction is needed
* maxchange directive:: Set maximum allowed offset
* manual directive:: Allow manual entry using chronyc's settime cmd.
* maxclockerror directive:: Set maximum frequency error of local clock
* maxupdateskew directive:: Stop bad estimates upsetting machine clock
@@ -1492,6 +1496,38 @@ cmdport 257
This would make @code{chronyd} use 257/udp as its command port.
(@code{chronyc} would need to be run with the @code{-p 257} switch to
inter-operate correctly).
@c }}}
@c {{{ corrtimeratio
@node corrtimeratio directive
@subsection corrtimeratio
When @code{chronyd} makes a time correction, it controls how quickly
the system clock is slewed (so far only on Linux). This rate
temporarily affects the frequency error of the system clock.
The @code{corrtimeratio} directive controls the ratio between the
duration in which the clock is slewed for an average correction
according to the source history and the interval in which the
corrections are done (usually the NTP polling interval). Corrections
larger than the average take less time and smaller corrections take
more time, the amount of the correction and the correction time are
inversely proportional.
Increasing @code{corrtimeratio} makes the overall frequency error of
the system clock smaller, but increases the overall time error as
the corrections will take longer.
By default, the ratio is 1, which means the duration of an average
correction will be close to the update interval.
The syntax is
@example
corrtimeratio 10
@end example
The current remaining correction is shown in the @code{tracking} report
(@pxref{tracking command}) as the @code{System time} value.
@c }}}
@c {{{ deny
@node deny directive
@@ -1601,6 +1637,17 @@ By default (or if the specified maximum or minimum is 0), no fallbacks
will be used and the clock frequency will stay at the last value
calculated before synchronisation was lost.
@c }}}
@c {{{ include
@node include directive
@subsection include
The @code{include} directive includes a specified configuration file.
This is useful when maintaining configuration on multiple hosts to
keep the differences in a separate file.
@example
include /etc/chrony/local.conf
@end example
@c }}}
@c {{{ initstepslew
@node initstepslew directive
@subsection initstepslew
@@ -1682,21 +1729,50 @@ pairs. The format of the file is shown below
@example
10 tulip
11 hyacinth
20 crocus
25 iris
20 MD5 ASCII:crocus
25 SHA1 HEX:1dc764e0791b11fa67efc7ecbc4b0d73f68a070c
...
@end example
Each line consists of an ID and a password. The ID can be any
unsigned integer in the range 0 through 2**32-1. The password can be
any string of characters not containing a space.
For NTP use, the MD5 authentication scheme is always used. This must be
borne in mind if @code{chronyd} is to inter-operate in authenticated
mode with @code{xntpd} running on other computers.
Each line consists of an ID, a name of authentication hash function (optional)
and a password. The ID can be any unsigned integer in the range 0 through
2**32-1. The hash function is MD5 by default, depending on how was
@code{chronyd} compiled other allowed hash functions may be SHA1, SHA256,
SHA384, SHA512, RMD128, RMD160, RMD256, RMD320, TIGER and WHIRLPOOL. The
password can be encoded as a string of characters not containing a space with
optional @code{ASCII:} prefix or as a hexadecimal number with @code{HEX:}
prefix.
The ID for the chronyc authentication key is specified with the
commandkey command (see earlier).
@c }}}
@c {{{ leapsectz
@node leapsectz directive
@subsection leapsectz
This directive is used to set the name of the timezone in the system
tz database which @code{chronyd} can use to find out when will the
next leap second occur. It will periodically check if the times
23:59:59 and 23:59:60 are valid on Jun 30 and Dec 31 in the timezone.
A useful timezone is @code{right/UTC}.
This is mainly useful with reference clocks which don't provide the
leap second information. It is not necessary to restart
@code{chronyd} if the tz database is updated with a new leap second at
least 12 hours before the event.
An example of the command is
@example
leapsectz right/UTC
@end example
The following shell command verifies that the timezone contains leap
seconds and can be used with this directive
@example
$ TZ=right/UTC date -d 'Dec 31 2008 23:59:60'
Wed Dec 31 23:59:60 UTC 2008
@end example
@c }}}
@c {{{ local
@node local directive
@@ -1847,9 +1923,9 @@ expressed in UTC, not the local time zone.
IP address of server/peer from which measurement comes [158.152.1.76]
@item
Leap status (@code{N} means normal, @code{+} means that the last minute
of today has 61 seconds, @code{-} means that the last minute of the day
has 59 seconds, @code{?} means the remote computer is not currently
synchronised.) [N]
of the current month has 61 seconds, @code{-} means that the last minute
of the month has 59 seconds, @code{?} means the remote computer is not
currently synchronised.) [N]
@item
Stratum of remote computer. [2]
@item
@@ -1954,7 +2030,7 @@ An example line (which actually appears as a single line in the file)
from the tracking log file is shown below.
@example
1998-07-22 05:40:50 158.152.1.76 3 340.529 1.606 1.046e-03
2012-02-23 05:40:50 158.152.1.76 3 340.529 1.606 1.046e-03 N
@end example
The columns are as follows (the quantities in square brackets are the
@@ -1962,7 +2038,7 @@ values from the example line above) :
@enumerate 1
@item
Date [1998-07-22]
Date [2012-02-03]
@item
Hour:Minute:Second [05:40:50]. Note that the date/time pair is
expressed in UTC, not the local time zone.
@@ -1980,6 +2056,10 @@ The error bounds on the frequency (in ppm) [1.606]
The estimated local offset at the epoch (which is rapidly corrected by
slewing the local clock. (In seconds, positive indicates the local
system is fast of UTC). [1.046e-3]
@item
Leap status (@code{N} means normal, @code{+} means that the last minute
of this month has 61 seconds, @code{-} means that the last minute of the month
has 59 seconds, @code{?} means the clock is not currently synchronised.) [N]
@end enumerate
A banner is periodically written to the log file to indicate the
@@ -2063,8 +2143,8 @@ Sequence number of driver poll within one polling interval for raw
samples, or @code{-} for filtered samples. [7]
@item
Leap status (@code{N} means normal, @code{+} means that the last minute
of today has 61 seconds, @code{-} means that the last minute of the day
has 59 seconds). [N]
of the current month has 61 seconds, @code{-} means that the last minute
of the month has 59 seconds). [N]
@item
Flag indicating whether the sample comes from PPS source. (1 for yes,
0 for no, or @code{-} for filtered sample). [1]
@@ -2198,6 +2278,27 @@ makestep 1000 10
This would step system clock if the adjustment is larger than 1000
seconds, but only in the first ten clock updates.
@c }}}
@c {{{ maxchange
@node maxchange directive
@subsection maxchange
This directive sets the maximum allowed offset corrected on a clock
update. The check is performed only after the specified number of
updates to allow a large initial adjustment of the system clock. When
an offset larger than the specified maximum occurs, it will be ignored
for the specified number of times and then @code{chronyd} will give up
and exit (a negative value can be used to never exit). In both cases
a message is sent to syslog.
An example of the use of this directive is
@example
maxchange 1000 1 2
@end example
After the first clock update, @code{chronyd} will check the offset on
every clock update, it will ignore two adjustments larger than 1000
seconds and exit on another one.
@c }}}
@c {{{ manual
@node manual directive
@subsection manual
@@ -2219,7 +2320,7 @@ The @code{maxclockerror} directive sets the maximum assumed frequency
error of the local clock. This is a frequency stability of the clock,
not an absolute frequency error.
By default, the maximum assumed error is set to 10 ppm.
By default, the maximum assumed error is set to 1 ppm.
The syntax is
@@ -2326,30 +2427,33 @@ udp/11123.
@c {{{ refclock
@node refclock directive
@subsection refclock
The @code{refclock} directive allows reference clocks to be specified.
The directive is immediately followed by a refclock driver name and
its parameter.
Reference clocks allows very accurate synchronisation and @code{chronyd}
can function as a stratum 1 server. They are specified by the
@code{refclock} directive. It has two mandatory parameters, a refclock driver
name and a driver specific parameter.
There are currently three drivers implemented:
There are currently three drivers included:
@table @code
@item PPS
Pulse per second (PPS) API driver. The parameter is a path to the PPS
device. Assert events are used by default. Driver option
@code{:clear} can be appended to the path to use clear events instead.
PPSAPI (pulse per second) driver. The parameter is the path to a PPS
device. Assert events are used by default. Driver option @code{:clear}
can be appended to the path if clear events should be used instead.
PPS refclock needs another source (NTP or non-PPS refclock) or local
directive (@pxref{local directive}) enabled to function. For example:
As PPS refclock gets only sub-second time information, it needs another
source (NTP or non-PPS refclock) or local directive (@pxref{local
directive}) enabled to work. For example:
@example
refclock SHM 0 offset 0.5 delay 0.1
refclock PPS /dev/pps0
refclock PPS /dev/pps0 lock NMEA
refclock SHM 0 offset 0.5 delay 0.1 refid NMEA noselect
@end example
@item SHM
NTP shared memory driver. The parameter is the number of the
shared memory segment that should be used for receiving timestamps, usually
0, 1, 2 or 3. For example:
NTP shared memory driver. This driver uses a shared memory segment to
receive data from another daemon which communicates with an actual
reference clock. The parameter is the number of a shared memory segment,
usually 0, 1, 2 or 3. For example:
@example
refclock SHM 1 poll 3 refid GPS1
@@ -2359,15 +2463,25 @@ A driver option in form @code{:perm=NNN} can be appended to the
segment number to create the segment with permissions other than the
default @code{0600}.
Software that can be used as a source of reference time includes
@code{gpsd} and @code{shmpps}.
Some examples of applications that can be used as SHM sources are @code{gpsd},
@code{shmpps} and @code{radioclk}.
@item SOCK
Unix domain socket driver. The parameter is a path to the socket
which is used as the source of timestamps. This is as a better
alternative to SHM, it does not require polling, the offset
resolution is not limited to microsecond and it supports PPS.
The format for messages sent over the socket is declared in file
@code{refclock_sock.c}.
Unix domain socket driver. It is similar to the SHM driver, but uses a
different format and uses a socket instead of shared memory. It does not
require polling, the offset resolution is not limited to microseconds and it
supports transmitting of PPS data. The parameter is a path to the socket which
will be created by @code{chronyd} and used to receive the messages. The format
of messages sent over the socket is described in the
@code{refclock_sock.c} file.
Recent versions of the @code{gpsd} daemon include support for the SOCK
protocol. The path where the socket should be created is described in the
@code{gpsd(8)} man page. For example:
@example
refclock SOCK /var/run/chrony.ttyS0.sock
@end example
@end table
The @code{refclock} command also supports a number of subfields (which
@@ -2379,7 +2493,8 @@ Timestamps produced by refclock drivers are not used immediately, but
they are stored and processed by a median filter in intervals
specified by this option. This is defined as a power of 2. The
default is 4 (16 seconds). A shorter interval allows @code{chronyd}
to react faster to frequency changes, but it may increase noise.
to react faster to changes in clock frequency, but it may decrease
the accuracy if the source is too noisy.
@item dpoll
Some drivers are not controlled by external events and thus require
polling. Again this is defined as a power of 2 and can be negative
@@ -2388,7 +2503,7 @@ for sub-second intervals. The default is 0 (1 second).
This option is used to specify a reference id of the refclock, as up
to four ASCII characters. By default, first three characters from
driver name and the number of the refclock are used as refid. Each
refclock has to use an unique refid.
refclock must have an unique refid.
@item filter
This option sets the length of the median filter which is used to
reduce noise. With each poll about 40 percent of the stored samples is
@@ -2423,7 +2538,8 @@ for SHM refclock, and 1e-9 (1 nanosecond) for SOCK and PPS refclocks.
@item prefer
Prefer this source over sources without prefer option.
@item noselect
Never select this source. This is particularly useful for monitoring.
Never select this source. This is useful for monitoring or with sources
which are not very accurate, but are locked with a PPS refclock.
@end table
@c }}}
@@ -2667,7 +2783,7 @@ NTP client mode datagram.
The NTP protocol supports the inclusion of checksums in the packets, to
prevent computers having their system time upset by rogue packets being
sent to them. The checksums are generated as a function of a password,
using the MD5 algorithm.
using the cryptographic hash function set in the key file.
The association between key numbers and passwords is contained in the
keys file, defined by the keyfile command.
@@ -2862,6 +2978,7 @@ password:
@itemize @bullet
@item @code{activity}
@item @code{authhash}
@item @code{dns}
@item @code{exit}
@item @code{help}
@@ -2871,6 +2988,7 @@ password:
@item @code{sources}
@item @code{sourcestats}
@item @code{tracking}
@item @code{waitsync}
@end itemize
All other commands require a password to have been specified previously,
@@ -2891,6 +3009,7 @@ interface.
* add server command:: Add a new NTP server
* allow command:: Allowing NTP client access
* allow all command:: Allowing NTP client access
* authhash command:: Set the command authentication hash function
* burst command:: Initiating a rapid set of measurements
* clients command:: Show clients that have accessed the server
* cmdaccheck command:: Verifying command client access
@@ -2922,6 +3041,7 @@ interface.
* polltarget command:: Set poll target for a source
* quit command:: Exit from chronyc
* reselect command:: Reselect synchronisation source
* reselectdist command:: Set improvement in distance needed to reselect a source
* retries command:: Set maximum number of retries
* rtcdata command:: Display RTC parameters
* settime command:: Provide a manual input of the current time
@@ -2930,6 +3050,7 @@ interface.
* timeout command:: Set initial response timeout
* tracking command:: Display system clock performance
* trimrtc command:: Correct the RTC time to the current system time
* waitsync command:: Wait until synchronised
* writertc command:: Write the RTC parameters to file.
@end menu
@c }}}
@@ -2960,7 +3081,7 @@ If the auto_offline option is used in specifying some of the servers/peers, the
@code{activity} command may be useful for detecting when all of them have
entered the offline state after the PPP link has been disconnected.
The report shows the number of servers/peers in 4 states:
The report shows the number of servers/peers in 5 states:
@itemize
@item @code{online} : the server/peer is currently online (i.e. assumed by
chronyd to be reachable)
@@ -2972,6 +3093,9 @@ server/peer will be returned to the online state.
@item @code{burst_offline} : a burst command has been initiated for the
server/peer and is being performed; after the burst is complete, the
server/peer will be returned to the offline state.
@item @code{unresolved} : the name of the server/peer wasn't resolved to an
address yet; this server is not visible in the @code{sources} and
@code{sourcestats} reports.
@end itemize
@c }}}
@c {{{ add peer
@@ -3035,6 +3159,20 @@ directive in the configuration file.
The effect of the allow command is identical to the @code{allow all}
directive in the configuration file (@pxref{allow directive}).
@c }}}
@c {{{ authhash
@node authhash command
@subsubsection authhash
This command sets the hash function used for authenticating user commands.
For successful authentication the hash function has to be the same as the one
set for the command key in the keys file on the server. It needs to be set
before the @code{password} command is used. The default hash function is MD5.
An example is
@example
authhash SHA1
@end example
@c }}}
@c {{{ burst
@node burst command
@subsubsection burst
@@ -3685,6 +3823,8 @@ password on the command line is as follows
@example
password xyzzy
password ASCII:xyzzy
password HEX:78797a7a79
@end example
To enter the password without it being echoed, enter
@@ -3698,9 +3838,10 @@ should enter the password and press return. (Note that the no-echo mode
is limited to 8 characters on SunOS 4.1 due to limitations in the system
library. Other systems do not have this restriction.)
The password is any string of characters not containing whitespace. It
has to match @code{chronyd's} currently defined command key (@pxref{commandkey
directive}).
The password can be encoded as a string of characters not containing a space
with optional @code{ASCII:} prefix or as a hexadecimal number with @code{HEX:}
prefix. It has to match @code{chronyd's} currently defined command key
(@pxref{commandkey directive}).
@c }}}
@c {{{ polltarget
@node polltarget command
@@ -3744,6 +3885,13 @@ available sources.
The @code{reselect} command can be used to force @code{chronyd} to
reselect the best synchronisation source.
@c }}}
@c {{{ reselectdist command
@node reselectdist command
@subsubsection reselectdist
The @code{reselectdist} command sets the reselect distance. It is equivalent
to the @code{reselectdist} directive in the configuration file
(@pxref{reselectdist directive}).
@c }}}
@c {{{ retries
@node retries command
@subsubsection retries
@@ -3860,11 +4008,11 @@ columns.
@example
@group
210 Number of sources = 3
MS Name/IP address Stratum Poll LastRx Last sample
=======================================================================
^+ a.b.c 3 6 47m -9491us[-6983us] +/- 159ms
^+ d.e.f 3 6 47m +32ms[ +35ms] +/- 274ms
^* g.h.i 2 6 47m +8839us[ +11ms] +/- 214ms
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
#* GPS0 0 4 377 11 -479ns[ -621ns] +/- 134ns
^? a.b.c 2 6 377 23 -923us[ -924us] +/- 43ms
^+ d.e.f 1 6 377 21 -2629us[-2619us] +/- 86ms
@end group
@end example
@@ -3905,10 +4053,18 @@ that a measurement is being made every 64 seconds.
@code{chronyd} automatically varies the polling rate in response to prevailing
conditions.
@item Reach
This shows the source's reachability register printed as octal number. The
register has 8 bits and is updated on every received or missed packet from
the source. A value of 377 indicates that a valid reply was received for all
from the last eight transmissions.
@item LastRx
This column shows how long ago the last sample was received from the
source. This is normally in seconds. The letters @code{m}, @code{h},
@code{d} or @code{y} indicate minutes, hours, days or years.
@code{d} or @code{y} indicate minutes, hours, days or years. A value
of 10 years indicates there were no samples received from this source
yet.
@item Last sample
This column shows the offset between the local clock and the source at
@@ -4009,13 +4165,18 @@ performance. An example of the output is shown below.
@example
Reference ID : 1.2.3.4 (a.b.c)
Stratum : 3
Ref time (UTC) : Sun May 17 06:13:11 1998
System time : 0.000000000 seconds fast of NTP time
Ref time (UTC) : Fri Feb 3 15:00:29 2012
System time : 0.000001501 seconds slow of NTP time
Last offset : -0.000001632 seconds
RMS offset : 0.000002360 seconds
Frequency : 331.898 ppm fast
Residual freq : 0.004 ppm
Skew : 0.154 ppm
Root delay : 0.373169 seconds
Root dispersion : 0.024780 seconds
Update interval : 64.2 seconds
Leap status : Normal
@end example
The fields are explained as follows.
@@ -4036,7 +4197,7 @@ computer, so the computer in the example is two hops away
(i.e. @code{a.b.c} is a stratum-2 and is synchronised from a stratum-1).
@item Ref time
This is the time (GMT) at which the last measurement from the reference
This is the time (UTC) at which the last measurement from the reference
source was processed.
@item System time
@@ -4057,9 +4218,13 @@ On systems such as Solaris and SunOS, @code{chronyd} has no means to
adjust the fundamental rate of the system clock, so keeps the system
time correct by periodically making offsets to it as though an error had
been measured. The build up of these offsets will be observed in this
report. On systems such as Linux where @code{chronyd} can adjust the
fundamental rate of the system clock, this value will show zero unless a
very recent measurement has shown the system to be error.
report.
@item Last offset
This is the estimated local offset on the last clock update.
@item RMS offset
This is a long-term average of the offset value.
@item Frequency
The `frequency' is the rate by which the system's clock would be would
@@ -4113,6 +4278,13 @@ stratum-1 computer is correct) is given by
clock_error <= root_dispersion + (0.5 * |root_delay|)
@end example
@item Update interval
This is the interval between the last two clock updates.
@item Leap status
This is the leap status, which can be @code{Normal}, @code{Insert second},
@code{Delete second} or @code{Not synchronised}.
@end table
@c }}}
@c {{{ trimrtc
@@ -4153,6 +4325,31 @@ across machine reboots even if the @code{trimrtc} command is never used
corrected, in a manner compatible with @code{chronyd} using it to
maintain accurate time across machine reboots.
@c }}}
@c {{{ waitsync
@node waitsync command
@subsubsection waitsync
The @code{waitsync} command waits for @code{chronyd} to synchronise.
Up to three optional arguments can be specified, the first is the maximum
number of tries in 10 second intervals before giving up and returning a
non-zero error code. When 0 is specified, or there are no arguments, the
number of tries will not be limited.
The second and third arguments are the maximum allowed remaining correction of
the system clock and the maximum allowed skew (in ppm) as reported by the
@code{tracking} command (@pxref{tracking command}) in the @code{System time}
and @code{Skew} fields. If not specified or zero, the value will not be
checked.
An example is
@example
waitsync 60 0.01
@end example
which will wait up to about 10 minutes for @code{chronyd} to synchronise to a
source and the remaining correction to be less than 10 milliseconds.
@c }}}
@c {{{ writertc
@node writertc command
@subsubsection writertc

View File

@@ -40,6 +40,7 @@ struct timex {
#define ADJ_MAXERROR 0x0004 /* maximum time error */
#define ADJ_STATUS 0x0010 /* clock status */
#define ADJ_TIMECONST 0x0020 /* pll time constant */
#define ADJ_SETOFFSET 0x0100 /* add 'time' to current time */
#define ADJ_NANO 0x2000 /* select nanosecond resolution */
#define ADJ_TICK 0x4000 /* tick value */
#define ADJ_OFFSET_SINGLESHOT 0x8001 /* old-fashioned adjtime */

View File

@@ -1,4 +1,4 @@
.TH CHRONYC 1 "December 04, 2009" chrony "User's Manual"
.TH CHRONYC 1 "@MAN_DATE@" "chrony @VERSION@" "User's Manual"
.SH NAME
chronyc \- command-line interface for chronyd
@@ -46,10 +46,6 @@ will be interpreted as a whole command.
specify command. If no command is given, chronyc will read commands
interactively.
.SH VERSION
1.24
.SH BUGS
To report bugs, please visit \fIhttp://chrony.tuxfamily.org\fR
@@ -67,4 +63,3 @@ Man Pages Project". Please see \fIhttp://www.netmeister.org/misc/m2p2/index.htm
for details.
The complete chrony documentation is supplied in texinfo format.

View File

@@ -1,4 +1,4 @@
.TH CHRONYD 8 "December 04, 2009" chrony "System Administration"
.TH CHRONYD 8 "@MAN_DATE@" "chrony @VERSION@" "System Administration"
.SH NAME
chronyd \- chrony background daemon
@@ -108,9 +108,6 @@ Resolve hostnames only to IPv6 addresses.
.SH FILES
\fI/etc/chrony.conf\fR
.SH VERSION
Version 1.24
.SH BUGS
To report bugs, please visit \fIhttp://chrony.tuxfamily.org/\fR

321
client.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2011
* Copyright (C) Miroslav Lichvar 2009-2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -26,12 +26,13 @@
from it whilst running.
*/
#include "config.h"
#include "sysincl.h"
#include "candm.h"
#include "nameserv.h"
#include "md5.h"
#include "version.h"
#include "hash.h"
#include "getdate.h"
#include "cmdparse.h"
#include "pktlength.h"
@@ -959,17 +960,18 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
{
CPS_NTP_Source data;
CPS_Status status;
IPAddr ip_addr;
int result = 0;
status = CPS_ParseNTPSourceAdd(line, &data);
switch (status) {
case CPS_Success:
/* Don't retry name resolving */
if (data.ip_addr.family == IPADDR_UNSPEC) {
if (DNS_Name2IPAddress(data.name, &ip_addr) != DNS_Success) {
Free(data.name);
fprintf(stderr, "Invalid host/IP address\n");
break;
}
Free(data.name);
if (data.params.min_stratum != SRC_DEFAULT_MINSTRATUM) {
fprintf(stderr, "Option minstratum not supported\n");
@@ -987,7 +989,7 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
}
msg->data.ntp_source.port = htonl((unsigned long) data.port);
UTI_IPHostToNetwork(&data.ip_addr, &msg->data.ntp_source.ip_addr);
UTI_IPHostToNetwork(&ip_addr, &msg->data.ntp_source.ip_addr);
msg->data.ntp_source.minpoll = htonl(data.params.minpoll);
msg->data.ntp_source.maxpoll = htonl(data.params.maxpoll);
msg->data.ntp_source.presend_minpoll = htonl(data.params.presend_minpoll);
@@ -1081,20 +1083,20 @@ process_cmd_delete(CMD_Request *msg, char *line)
fprintf(stderr, "Could not get address for hostname\n");
ok = 0;
} else {
UTI_IPHostToNetwork(&address, &msg->data.del_source.ip_addr);
ok = 1;
}
}
UTI_IPHostToNetwork(&address, &msg->data.del_source.ip_addr);
return ok;
}
/* ================================================== */
static int password_seen = 0;
static MD5_CTX md5_after_just_password;
static char *password = NULL;
static int password_length;
static int auth_hash_id;
/* ================================================== */
@@ -1102,8 +1104,16 @@ static int
process_cmd_password(CMD_Request *msg, char *line)
{
char *p, *q;
char *password;
struct timeval now;
int i, len;
/* Blank and free the old password */
if (password) {
for (i = 0; i < password_length; i++)
password[i] = 0;
free(password);
password = NULL;
}
p = line;
while (*p && isspace((unsigned char)*p))
@@ -1114,28 +1124,31 @@ process_cmd_password(CMD_Request *msg, char *line)
if (isspace((unsigned char)*q)) *q = 0;
}
if (*p) {
password = p;
} else {
if (!*p) {
/* blank line, prompt for password */
password = getpass("Password: ");
p = getpass("Password: ");
}
if (!*password) {
password_seen = 0;
} else {
password_seen = 1;
if (!*p)
return 0;
len = strlen(p);
password_length = UTI_DecodePasswordFromText(p);
if (password_length > 0) {
password = malloc(password_length);
memcpy(password, p, password_length);
}
/* Generate MD5 initial context */
MD5Init(&md5_after_just_password);
MD5Update(&md5_after_just_password, (unsigned char *) password, strlen(password));
/* Blank the password for security */
for (p = password; *p; p++) {
*p = 0;
/* Erase the password from the input or getpass buffer */
for (i = 0; i < len; i++)
p[i] = 0;
if (password_length <= 0) {
fprintf(stderr, "Could not decode password\n");
return 0;
}
if (gettimeofday(&now, NULL) < 0) {
printf("500 - Could not read time of day\n");
return 0;
@@ -1148,43 +1161,33 @@ process_cmd_password(CMD_Request *msg, char *line)
/* ================================================== */
static void
static int
generate_auth(CMD_Request *msg)
{
MD5_CTX ctx;
int pkt_len;
int data_len;
pkt_len = PKL_CommandLength(msg);
ctx = md5_after_just_password;
MD5Update(&ctx, (unsigned char *) msg, offsetof(CMD_Request, auth));
if (pkt_len > offsetof(CMD_Request, data)) {
MD5Update(&ctx, (unsigned char *) &(msg->data), pkt_len - offsetof(CMD_Request, data));
}
MD5Final(&ctx);
memcpy(&(msg->auth), &ctx.digest, 16);
data_len = PKL_CommandLength(msg);
assert(auth_hash_id >= 0);
return UTI_GenerateNTPAuth(auth_hash_id, (unsigned char *)password, password_length,
(unsigned char *)msg, data_len, ((unsigned char *)msg) + data_len, sizeof (msg->auth));
}
/* ================================================== */
static int
check_reply_auth(CMD_Reply *msg)
check_reply_auth(CMD_Reply *msg, int len)
{
int pkt_len;
MD5_CTX ctx;
int data_len;
pkt_len = PKL_ReplyLength(msg);
ctx = md5_after_just_password;
MD5Update(&ctx, (unsigned char *) msg, offsetof(CMD_Request, auth));
if (pkt_len > offsetof(CMD_Reply, data)) {
MD5Update(&ctx, (unsigned char *) &(msg->data), pkt_len - offsetof(CMD_Reply, data));
}
MD5Final(&ctx);
data_len = PKL_ReplyLength(msg);
if (!memcmp((void *) &ctx.digest, (void *) &(msg->auth), 16)) {
return 1;
} else {
return 0;
}
assert(auth_hash_id >= 0);
return UTI_CheckNTPAuth(auth_hash_id, (unsigned char *)password, password_length,
(unsigned char *)msg, data_len,
((unsigned char *)msg) + data_len, len - data_len);
}
/* ================================================== */
@@ -1234,8 +1237,10 @@ give_help(void)
printf("sourcestats [-v] : Display estimation information about current sources\n");
printf("tracking : Display system time information\n");
printf("trimrtc : Correct RTC relative to system clock\n");
printf("waitsync [max-tries [max-correction [max-skew]]] : Wait until synchronised\n");
printf("writertc : Save RTC parameters to file\n");
printf("\n");
printf("authhash <name>: Set command authentication hash function\n");
printf("dns -n|+n : Disable/enable resolving IP addresses to hostnames\n");
printf("dns -4|-6|-46 : Resolve hostnames only to IPv4/IPv6/both addresses\n");
printf("timeout <milliseconds> : Set initial response timeout\n");
@@ -1271,6 +1276,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
int read_length;
int expected_length;
int command_length;
int auth_length;
struct timeval tv;
int timeout;
int n_attempts;
@@ -1293,25 +1299,32 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
do {
/* Decide whether to authenticate */
if (password_seen) {
if (password) {
if (!utoken || (request->command == htons(REQ_LOGON))) {
/* Otherwise, the daemon won't bother authenticating our
packet and we won't get a token back */
request->utoken = htonl(SPECIAL_UTOKEN);
}
generate_auth(request);
auth_length = generate_auth(request);
} else {
memset(request->auth, 0, sizeof (request->auth));
auth_length = 0;
}
command_length = PKL_CommandLength(request);
assert(command_length > 0);
/* add empty MD5 auth so older servers will not drop the request
due to bad length */
if (!auth_length) {
memset(((char *)request) + command_length, 0, 16);
auth_length = 16;
}
#if 0
printf("Sent command length=%d bytes\n", command_length);
printf("Sent command length=%d bytes auth length=%d bytes\n", command_length, auth_length);
#endif
if (sendto(sock_fd, (void *) request, command_length, 0,
if (sendto(sock_fd, (void *) request, command_length + auth_length, 0,
&his_addr.u, his_addr_len) < 0) {
@@ -1374,7 +1387,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
read_length = recvfrom_status;
expected_length = PKL_ReplyLength(reply);
bad_length = (read_length != expected_length);
bad_length = (read_length < expected_length);
bad_sender = (where_from.u.sa_family != his_addr.u.sa_family ||
(where_from.u.sa_family == AF_INET &&
(where_from.in4.sin_addr.s_addr != his_addr.in4.sin_addr.s_addr ||
@@ -1428,8 +1441,8 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
ntohl(reply->token));
#endif
if (password_seen) {
*reply_auth_ok = check_reply_auth(reply);
if (password) {
*reply_auth_ok = check_reply_auth(reply, read_length);
} else {
/* Assume in this case that the reply is always considered
to be authentic */
@@ -1678,7 +1691,7 @@ process_cmd_sources(char *line)
IPAddr ip_addr;
uint32_t latest_meas_ago;
uint16_t poll, stratum;
uint16_t state, mode;
uint16_t state, mode, flags, reachability;
char hostname_buf[50];
/* Check whether to output verbose headers */
@@ -1700,10 +1713,10 @@ process_cmd_sources(char *line)
printf("|| | | \n");
}
printf("MS Name/IP address Stratum Poll LastRx Last sample\n");
printf("============================================================================\n");
printf("MS Name/IP address Stratum Poll Reach LastRx Last sample\n");
printf("===============================================================================\n");
/* "MS NNNNNNNNNNNNNNNNNNNNNNNNN SS PP RRRR SSSSSSS[SSSSSSS] +/- SSSSSS" */
/* "MS NNNNNNNNNNNNNNNNNNNNNNNNNNN SS PP RRR RRRR SSSSSSS[SSSSSSS] +/- SSSSSS" */
for (i=0; i<n_sources; i++) {
request.command = htons(REQ_SOURCE_DATA);
@@ -1714,6 +1727,8 @@ process_cmd_sources(char *line)
stratum = ntohs(reply.data.source_data.stratum);
state = ntohs(reply.data.source_data.state);
mode = ntohs(reply.data.source_data.mode);
flags = ntohs(reply.data.source_data.flags);
reachability = ntohs(reply.data.source_data.reachability);
latest_meas_ago = ntohl(reply.data.source_data.since_sample);
orig_latest_meas = UTI_FloatNetworkToHost(reply.data.source_data.orig_latest_meas);
latest_meas = UTI_FloatNetworkToHost(reply.data.source_data.latest_meas);
@@ -1754,8 +1769,12 @@ process_cmd_sources(char *line)
default:
printf(" ");
}
switch (flags) {
default:
break;
}
printf(" %-25s %2d %2d ", hostname_buf, stratum, poll);
printf(" %-27s %2d %2d %3o ", hostname_buf, stratum, poll, reachability);
print_seconds(latest_meas_ago);
printf(" ");
print_signed_nanoseconds(latest_meas);
@@ -1787,8 +1806,8 @@ process_cmd_sourcestats(char *line)
char hostname_buf[50];
unsigned long n_samples, n_runs, span_seconds;
double resid_freq_ppm, skew_ppm, sd, est_offset, est_offset_err;
unsigned long ref_id;
double resid_freq_ppm, skew_ppm, sd, est_offset;
uint32_t ref_id;
IPAddr ip_addr;
verbose = check_for_verbose_flag(line);
@@ -1827,7 +1846,7 @@ process_cmd_sourcestats(char *line)
skew_ppm = UTI_FloatNetworkToHost(reply.data.sourcestats.skew_ppm);
sd = UTI_FloatNetworkToHost(reply.data.sourcestats.sd);
est_offset = UTI_FloatNetworkToHost(reply.data.sourcestats.est_offset);
est_offset_err = UTI_FloatNetworkToHost(reply.data.sourcestats.est_offset_err);
/* est_offset_err = UTI_FloatNetworkToHost(reply.data.sourcestats.est_offset_err); */
if (ip_addr.family == IPADDR_UNSPEC)
snprintf(hostname_buf, sizeof(hostname_buf), "%s", UTI_RefidToString(ref_id));
@@ -1867,18 +1886,22 @@ process_cmd_tracking(char *line)
CMD_Request request;
CMD_Reply reply;
IPAddr ip_addr;
unsigned long ref_id;
uint32_t ref_id;
char host[50];
char *ref_ip;
struct timeval ref_time;
struct tm ref_time_tm;
unsigned long a, b, c, d;
double correction;
double last_offset;
double rms_offset;
double freq_ppm;
double resid_freq_ppm;
double skew_ppm;
double root_delay;
double root_dispersion;
double last_update_interval;
const char *leap_status;
request.command = htons(REQ_TRACKING);
if (request_reply(&request, &reply, RPY_TRACKING, 0)) {
@@ -1898,24 +1921,49 @@ process_cmd_tracking(char *line)
ref_ip = host;
}
switch (ntohs(reply.data.tracking.leap_status)) {
case LEAP_Normal:
leap_status = "Normal";
break;
case LEAP_InsertSecond:
leap_status = "Insert second";
break;
case LEAP_DeleteSecond:
leap_status = "Delete second";
break;
case LEAP_Unsynchronised:
leap_status = "Not synchronised";
break;
default:
leap_status = "Unknown";
break;
}
printf("Reference ID : %lu.%lu.%lu.%lu (%s)\n", a, b, c, d, ref_ip);
printf("Stratum : %lu\n", (unsigned long) ntohl(reply.data.tracking.stratum));
printf("Stratum : %lu\n", (unsigned long) ntohs(reply.data.tracking.stratum));
UTI_TimevalNetworkToHost(&reply.data.tracking.ref_time, &ref_time);
ref_time_tm = *gmtime((time_t *)&ref_time.tv_sec);
printf("Ref time (UTC) : %s", asctime(&ref_time_tm));
correction = UTI_FloatNetworkToHost(reply.data.tracking.current_correction);
last_offset = UTI_FloatNetworkToHost(reply.data.tracking.last_offset);
rms_offset = UTI_FloatNetworkToHost(reply.data.tracking.rms_offset);
printf("System time : %.9f seconds %s of NTP time\n", fabs(correction),
(correction > 0.0) ? "slow" : "fast");
printf("Last offset : %.9f seconds\n", last_offset);
printf("RMS offset : %.9f seconds\n", rms_offset);
freq_ppm = UTI_FloatNetworkToHost(reply.data.tracking.freq_ppm);
resid_freq_ppm = UTI_FloatNetworkToHost(reply.data.tracking.resid_freq_ppm);
skew_ppm = UTI_FloatNetworkToHost(reply.data.tracking.skew_ppm);
root_delay = UTI_FloatNetworkToHost(reply.data.tracking.root_delay);
root_dispersion = UTI_FloatNetworkToHost(reply.data.tracking.root_dispersion);
last_update_interval = UTI_FloatNetworkToHost(reply.data.tracking.last_update_interval);
printf("Frequency : %.3f ppm %s\n", fabs(freq_ppm), (freq_ppm < 0.0) ? "slow" : "fast");
printf("Residual freq : %.3f ppm\n", resid_freq_ppm);
printf("Skew : %.3f ppm\n", skew_ppm);
printf("Root delay : %.6f seconds\n", root_delay);
printf("Root dispersion : %.6f seconds\n", root_dispersion);
printf("Update interval : %.1f seconds\n", last_update_interval);
printf("Leap status : %s\n", leap_status);
return 1;
}
return 0;
@@ -2365,11 +2413,13 @@ process_cmd_activity(const char *line)
"%ld sources online\n"
"%ld sources offline\n"
"%ld sources doing burst (return to online)\n"
"%ld sources doing burst (return to offline)\n",
"%ld sources doing burst (return to offline)\n"
"%ld sources with unknown address\n",
(long) ntohl(reply.data.activity.online),
(long) ntohl(reply.data.activity.offline),
(long) ntohl(reply.data.activity.burst_online),
(long) ntohl(reply.data.activity.burst_offline));
(long) ntohl(reply.data.activity.burst_offline),
(long) ntohl(reply.data.activity.unresolved));
return 1;
}
return 0;
@@ -2377,6 +2427,23 @@ process_cmd_activity(const char *line)
/* ================================================== */
static int
process_cmd_reselectdist(CMD_Request *msg, char *line)
{
double dist;
int ok;
msg->command = htons(REQ_RESELECTDISTANCE);
if (sscanf(line, "%lf", &dist) == 1) {
msg->data.reselect_distance.distance = UTI_FloatHostToNetwork(dist);
ok = 1;
} else {
ok = 0;
}
return ok;
}
/* ================================================== */
static void
process_cmd_reselect(CMD_Request *msg, char *line)
{
@@ -2385,6 +2452,56 @@ process_cmd_reselect(CMD_Request *msg, char *line)
/* ================================================== */
static int
process_cmd_waitsync(char *line)
{
CMD_Request request;
CMD_Reply reply;
uint32_t ref_id, a, b, c, d;
double correction, skew_ppm, max_correction, max_skew_ppm;
int ret = 0, max_tries, i;
max_tries = 0;
max_correction = 0.0;
max_skew_ppm = 0.0;
sscanf(line, "%d %lf %lf", &max_tries, &max_correction, &max_skew_ppm);
request.command = htons(REQ_TRACKING);
for (i = 1; ; i++) {
if (request_reply(&request, &reply, RPY_TRACKING, 0)) {
ref_id = ntohl(reply.data.tracking.ref_id);
a = (ref_id >> 24);
b = (ref_id >> 16) & 0xff;
c = (ref_id >> 8) & 0xff;
d = (ref_id) & 0xff;
correction = UTI_FloatNetworkToHost(reply.data.tracking.current_correction);
correction = fabs(correction);
skew_ppm = UTI_FloatNetworkToHost(reply.data.tracking.skew_ppm);
printf("try: %d, refid: %d.%d.%d.%d, correction: %.9f, skew: %.3f\n",
i, a, b, c, d, correction, skew_ppm);
if (ref_id != 0 && ref_id != 0x7f7f0101L /* LOCAL refid */ &&
(max_correction == 0.0 || correction <= max_correction) &&
(max_skew_ppm == 0.0 || skew_ppm <= max_skew_ppm)) {
ret = 1;
}
}
if (!ret && (!max_tries || i < max_tries)) {
sleep(10);
} else {
break;
}
}
return ret;
}
/* ================================================== */
static int
process_cmd_dns(const char *line)
{
@@ -2407,6 +2524,32 @@ process_cmd_dns(const char *line)
/* ================================================== */
static int
process_cmd_authhash(const char *line)
{
char hash_name[50];
int new_hash_id;
assert(auth_hash_id >= 0);
if (sscanf(line, "%49s", hash_name) != 1) {
fprintf(stderr, "Could not parse hash name\n");
return 0;
}
new_hash_id = HSH_GetHashId(hash_name);
if (new_hash_id < 0) {
fprintf(stderr, "Unknown hash name: %s\n", hash_name);
return 0;
}
auth_hash_id = new_hash_id;
return 1;
}
/* ================================================== */
static int
process_cmd_timeout(const char *line)
{
@@ -2459,7 +2602,7 @@ process_line(char *line, int *quit)
if (!*p) {
fflush(stderr);
fflush(stdout);
return ret;
return 1;
};
if (!strncmp(p, "offline", 7)) {
@@ -2558,8 +2701,16 @@ process_line(char *line, int *quit)
} else if (!strncmp(p, "activity", 8)) {
ret = process_cmd_activity(p+8);
do_normal_submit = 0;
} else if (!strncmp(p, "reselectdist", 12)) {
do_normal_submit = process_cmd_reselectdist(&tx_message, p+12);
} else if (!strncmp(p, "reselect", 8)) {
process_cmd_reselect(&tx_message, p+8);
} else if (!strncmp(p, "waitsync", 8)) {
ret = process_cmd_waitsync(p+8);
do_normal_submit = 0;
} else if (!strncmp(p, "authhash", 8)) {
ret = process_cmd_authhash(p+8);
do_normal_submit = 0;
} else if (!strncmp(p, "dns ", 4)) {
ret = process_cmd_dns(p+4);
do_normal_submit = 0;
@@ -2621,8 +2772,6 @@ process_args(int argc, char **argv, int multi)
}
}
strcat(line, "\n");
ret = process_line(line, &quit);
if (!ret)
break;
@@ -2638,12 +2787,12 @@ process_args(int argc, char **argv, int multi)
static void
display_gpl(void)
{
printf("chrony version %s, copyright (C) 1997-2002 Richard P. Curnow\n"
"chrony comes with ABSOLUTELY NO WARRANTY.\n"
"This is free software, and you are welcome to redistribute it\n"
"under certain conditions.\n"
"See the GNU General Public License version 2 for details.\n\n",
PROGRAM_VERSION_STRING);
printf("chrony version %s\n"
"Copyright (C) 1997-2003, 2007, 2009-2012 Richard P. Curnow and others\n"
"chrony comes with ABSOLUTELY NO WARRANTY. This is free software, and\n"
"you are welcome to redistribute it under certain conditions. See the\n"
"GNU General Public License version 2 for details.\n\n",
CHRONY_VERSION);
}
/* ================================================== */
@@ -2680,7 +2829,7 @@ main(int argc, char **argv)
DNS_SetAddressFamily(IPADDR_INET6);
hostname = "::1";
} else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
printf("chronyc (chrony) version %s\n", PROGRAM_VERSION_STRING);
printf("chronyc (chrony) version %s\n", CHRONY_VERSION);
exit(0);
} else if (!strncmp(*argv, "-", 1)) {
fprintf(stderr, "Usage : %s [-h <hostname>] [-p <port-number>] [-n] [-4|-6] [-m] [command]\n", progname);
@@ -2697,6 +2846,10 @@ main(int argc, char **argv)
if (on_terminal && (argc == 0)) {
display_gpl();
}
/* MD5 is the default authentication hash */
auth_hash_id = HSH_GetHashId("MD5");
assert(auth_hash_id >= 0);
open_io(hostname, port);
@@ -2716,6 +2869,8 @@ main(int argc, char **argv)
close_io();
free(password);
return !ret;
}

View File

@@ -31,6 +31,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "clientlog.h"
#include "conf.h"

147
cmdmon.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2011
* Copyright (C) Miroslav Lichvar 2009-2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -25,6 +25,8 @@
Command and monitoring module in the main program
*/
#include "config.h"
#include "sysincl.h"
#include "cmdmon.h"
@@ -158,7 +160,8 @@ static int permissions[] = {
PERMIT_AUTH, /* MODIFY_MINSTRATUM */
PERMIT_AUTH, /* MODIFY_POLLTARGET */
PERMIT_AUTH, /* MODIFY_MAXDELAYDEVRATIO */
PERMIT_AUTH /* RESELECT */
PERMIT_AUTH, /* RESELECT */
PERMIT_AUTH /* RESELECTDISTANCE */
};
/* ================================================== */
@@ -325,57 +328,28 @@ CAM_Finalise(void)
rest of the packet */
static int
check_rx_packet_auth(CMD_Request *packet)
check_rx_packet_auth(CMD_Request *packet, int packet_len)
{
char *key;
int keylen;
int pkt_len;
MD5_CTX ctx;
int pkt_len, auth_len;
pkt_len = PKL_CommandLength(packet);
auth_len = packet_len - pkt_len;
KEY_CommandKey(&key, &keylen);
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char *) key, keylen);
MD5Update(&ctx, (unsigned char *) packet, offsetof(CMD_Request, auth));
if (pkt_len > offsetof(CMD_Request, data)) {
MD5Update(&ctx, (unsigned char *) &(packet->data), pkt_len - offsetof(CMD_Request, data));
}
MD5Final(&ctx);
if (!memcmp((void *) &ctx.digest, (void *) &(packet->auth), 16)) {
return 1;
} else {
return 0;
}
return KEY_CheckAuth(KEY_GetCommandKey(), (unsigned char *)packet,
pkt_len, ((unsigned char *)packet) + pkt_len, auth_len);
}
/* ================================================== */
static void
static int
generate_tx_packet_auth(CMD_Reply *packet)
{
char *key;
int keylen;
MD5_CTX ctx;
int pkt_len;
pkt_len = PKL_ReplyLength(packet);
KEY_CommandKey(&key, &keylen);
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char *) key, keylen);
MD5Update(&ctx, (unsigned char *) packet, offsetof(CMD_Request, auth));
if (pkt_len > offsetof(CMD_Reply, data)) {
MD5Update(&ctx, (unsigned char *) &(packet->data), pkt_len - offsetof(CMD_Reply, data));
}
MD5Final(&ctx);
memcpy(&(packet->auth), &ctx.digest, 16);
return KEY_GenerateAuth(KEY_GetCommandKey(), (unsigned char *)packet,
pkt_len, ((unsigned char *)packet) + pkt_len, sizeof (packet->auth));
}
/* ================================================== */
@@ -717,7 +691,7 @@ print_reply_packet(CMD_Reply *pkt)
/* ================================================== */
static void
transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to)
transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to, int auth_len)
{
int status;
int tx_message_length;
@@ -739,7 +713,7 @@ transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to)
assert(0);
}
tx_message_length = PKL_ReplyLength(msg);
tx_message_length = PKL_ReplyLength(msg) + auth_len;
status = sendto(sock_fd, (void *) msg, tx_message_length, 0,
&where_to->u, addrlen);
@@ -1088,6 +1062,18 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
tx_message->data.source_data.mode = htons(RPY_SD_MD_REF);
break;
}
switch (report.sel_option) {
case RPT_NORMAL:
tx_message->data.source_data.flags = htons(0);
break;
case RPT_PREFER:
tx_message->data.source_data.flags = htons(RPY_SD_FLAG_PREFER);
break;
case RPT_NOSELECT:
tx_message->data.source_data.flags = htons(RPY_SD_FLAG_PREFER);
break;
}
tx_message->data.source_data.reachability = htons(report.reachability);
tx_message->data.source_data.since_sample = htonl(report.latest_meas_ago);
tx_message->data.source_data.orig_latest_meas = UTI_FloatHostToNetwork(report.orig_latest_meas);
tx_message->data.source_data.latest_meas = UTI_FloatHostToNetwork(report.latest_meas);
@@ -1380,7 +1366,7 @@ handle_doffset(CMD_Request *rx_message, CMD_Reply *tx_message)
usec = (long)(ntohl(rx_message->data.doffset.usec));
doffset = (double) sec + 1.0e-6 * (double) usec;
LOG(LOGS_INFO, LOGF_CmdMon, "Accumulated delta offset of %.6f seconds", doffset);
LCL_AccumulateOffset(doffset);
LCL_AccumulateOffset(doffset, 0.0);
tx_message->status = htons(STT_SUCCESS);
}
@@ -1396,14 +1382,18 @@ handle_tracking(CMD_Request *rx_message, CMD_Reply *tx_message)
tx_message->reply = htons(RPY_TRACKING);
tx_message->data.tracking.ref_id = htonl(rpt.ref_id);
UTI_IPHostToNetwork(&rpt.ip_addr, &tx_message->data.tracking.ip_addr);
tx_message->data.tracking.stratum = htonl(rpt.stratum);
tx_message->data.tracking.stratum = htons(rpt.stratum);
tx_message->data.tracking.leap_status = htons(rpt.leap_status);
UTI_TimevalHostToNetwork(&rpt.ref_time, &tx_message->data.tracking.ref_time);
tx_message->data.tracking.current_correction = UTI_FloatHostToNetwork(rpt.current_correction);
tx_message->data.tracking.last_offset = UTI_FloatHostToNetwork(rpt.last_offset);
tx_message->data.tracking.rms_offset = UTI_FloatHostToNetwork(rpt.rms_offset);
tx_message->data.tracking.freq_ppm = UTI_FloatHostToNetwork(rpt.freq_ppm);
tx_message->data.tracking.resid_freq_ppm = UTI_FloatHostToNetwork(rpt.resid_freq_ppm);
tx_message->data.tracking.skew_ppm = UTI_FloatHostToNetwork(rpt.skew_ppm);
tx_message->data.tracking.root_delay = UTI_FloatHostToNetwork(rpt.root_delay);
tx_message->data.tracking.root_dispersion = UTI_FloatHostToNetwork(rpt.root_dispersion);
tx_message->data.tracking.last_update_interval = UTI_FloatHostToNetwork(rpt.last_update_interval);
}
/* ================================================== */
@@ -1705,12 +1695,25 @@ handle_activity(CMD_Request *rx_message, CMD_Reply *tx_message)
tx_message->data.activity.offline = htonl(report.offline);
tx_message->data.activity.burst_online = htonl(report.burst_online);
tx_message->data.activity.burst_offline = htonl(report.burst_offline);
tx_message->data.activity.unresolved = htonl(report.unresolved);
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_ACTIVITY);
}
/* ================================================== */
static void
handle_reselect_distance(CMD_Request *rx_message, CMD_Reply *tx_message)
{
double dist;
dist = UTI_FloatNetworkToHost(rx_message->data.reselect_distance.distance);
SRC_SetReselectDistance(dist);
tx_message->status = htons(STT_SUCCESS);
return;
}
/* ================================================== */
static void
handle_reselect(CMD_Request *rx_message, CMD_Reply *tx_message)
{
@@ -1741,7 +1744,7 @@ read_from_cmd_socket(void *anything)
{
int status;
int read_length; /* Length of packet read */
int expected_length; /* Expected length of packet */
int expected_length; /* Expected length of packet without auth data */
unsigned long flags;
CMD_Request rx_message;
CMD_Reply tx_message, *prev_tx_message;
@@ -1751,7 +1754,8 @@ read_from_cmd_socket(void *anything)
socklen_t from_length;
IPAddr remote_ip;
unsigned short remote_port;
int md5_ok;
int auth_length;
int auth_ok;
int utoken_ok, token_ok;
int issue_token;
int valid_ts;
@@ -1852,7 +1856,10 @@ read_from_cmd_socket(void *anything)
if (rx_message.version >= PROTO_VERSION_MISMATCH_COMPAT) {
tx_message.status = htons(STT_BADPKTVERSION);
transmit_reply(&tx_message, &where_from);
/* add empty MD5 auth so older clients will not drop
the reply due to bad length */
memset(((char *)&tx_message) + PKL_ReplyLength(&tx_message), 0, 16);
transmit_reply(&tx_message, &where_from, 16);
}
return;
}
@@ -1865,11 +1872,11 @@ read_from_cmd_socket(void *anything)
CLG_LogCommandAccess(&remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec);
tx_message.status = htons(STT_INVALID);
transmit_reply(&tx_message, &where_from);
transmit_reply(&tx_message, &where_from, 0);
return;
}
if (read_length != expected_length) {
if (read_length < expected_length) {
if (!LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_CmdMon, "Read incorrectly sized command packet from %s:%hu", UTI_IPToString(&remote_ip), remote_port);
}
@@ -1877,7 +1884,7 @@ read_from_cmd_socket(void *anything)
CLG_LogCommandAccess(&remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec);
tx_message.status = htons(STT_BADPKTLENGTH);
transmit_reply(&tx_message, &where_from);
transmit_reply(&tx_message, &where_from, 0);
return;
}
@@ -1894,7 +1901,7 @@ read_from_cmd_socket(void *anything)
}
tx_message.status = htons(STT_NOHOSTACCESS);
transmit_reply(&tx_message, &where_from);
transmit_reply(&tx_message, &where_from, 0);
return;
}
@@ -1905,18 +1912,18 @@ read_from_cmd_socket(void *anything)
clients will set their utokens to 0 to save us wasting our time
if the packet is unauthenticatable. */
if (rx_message.utoken != 0) {
md5_ok = check_rx_packet_auth(&rx_message);
auth_ok = check_rx_packet_auth(&rx_message, read_length);
} else {
md5_ok = 0;
auth_ok = 0;
}
/* All this malarky is to protect the system against various forms
of attack.
Simple packet forgeries are blocked by requiring the packet to
authenticate properly with MD5. (The assumption is that the
command key is in a read-only keys file read by the daemon, and
is known only to administrators.)
authenticate properly with MD5 or other crypto hash. (The
assumption is that the command key is in a read-only keys file
read by the daemon, and is known only to administrators.)
Replay attacks are prevented by 2 fields in the packet. The
'token' field is where the client plays back to us a token that
@@ -1958,13 +1965,13 @@ read_from_cmd_socket(void *anything)
rx_message_seq = ntohl(rx_message.sequence);
rx_attempt = ntohs(rx_message.attempt);
if (md5_ok && utoken_ok) {
if (auth_ok && utoken_ok) {
token_ok = check_token(rx_message_token);
} else {
token_ok = 0;
}
if (md5_ok && utoken_ok && !token_ok) {
if (auth_ok && utoken_ok && !token_ok) {
/* This might be a resent message, due to the client not getting
our reply to the first attempt. See if we can find the message. */
prev_tx_message = lookup_reply(rx_message_token, rx_message_seq, rx_attempt);
@@ -1982,14 +1989,14 @@ read_from_cmd_socket(void *anything)
}
if (md5_ok && utoken_ok && token_ok) {
if (auth_ok && utoken_ok && token_ok) {
/* See whether we can discard the previous reply from storage */
token_acknowledged(rx_message_token, &now);
}
valid_ts = 0;
if (md5_ok) {
if (auth_ok) {
struct timeval ts;
UTI_TimevalNetworkToHost(&rx_message.data.logon.ts, &ts);
@@ -2004,7 +2011,7 @@ read_from_cmd_socket(void *anything)
issue_token = 0;
}
authenticated = md5_ok & utoken_ok & token_ok;
authenticated = auth_ok & utoken_ok & token_ok;
if (authenticated) {
CLG_LogCommandAccess(&remote_ip, CLG_CMD_AUTH, cooked_now.tv_sec);
@@ -2104,15 +2111,15 @@ read_from_cmd_socket(void *anything)
/* If the log-on fails, record the reason why */
if (!issue_token && !LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_CmdMon,
"Bad command logon from %s port %d (md5_ok=%d valid_ts=%d)\n",
"Bad command logon from %s port %d (auth_ok=%d valid_ts=%d)",
UTI_IPToString(&remote_ip),
remote_port,
md5_ok, valid_ts);
auth_ok, valid_ts);
}
if (issue_token == 1) {
tx_message.status = htons(STT_SUCCESS);
} else if (!md5_ok) {
} else if (!auth_ok) {
tx_message.status = htons(STT_UNAUTH);
} else if (!valid_ts) {
tx_message.status = htons(STT_INVALIDTS);
@@ -2258,6 +2265,10 @@ read_from_cmd_socket(void *anything)
handle_activity(&rx_message, &tx_message);
break;
case REQ_RESELECTDISTANCE:
handle_reselect_distance(&rx_message, &tx_message);
break;
case REQ_RESELECT:
handle_reselect(&rx_message, &tx_message);
break;
@@ -2271,7 +2282,7 @@ read_from_cmd_socket(void *anything)
break;
default:
/* Ignore message */
assert(0);
break;
}
} else {
@@ -2279,8 +2290,10 @@ read_from_cmd_socket(void *anything)
}
}
if (md5_ok) {
generate_tx_packet_auth(&tx_message);
if (auth_ok) {
auth_length = generate_tx_packet_auth(&tx_message);
} else {
auth_length = 0;
}
if (token_ok) {
@@ -2299,7 +2312,7 @@ read_from_cmd_socket(void *anything)
static int do_it=1;
if (do_it) {
transmit_reply(&tx_message, &where_from);
transmit_reply(&tx_message, &where_from, auth_length);
}
#if 0

View File

@@ -26,6 +26,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "cmdparse.h"
@@ -43,7 +45,6 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
int ok, n, done;
char cmd[MAXLEN+1], hostname[MAXLEN+1];
CPS_Status result;
DNS_Status s;
src->port = SRC_DEFAULT_PORT;
src->params.minpoll = SRC_DEFAULT_MINPOLL;
@@ -64,14 +65,7 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
ok = 0;
if (sscanf(line, "%" SMAXLEN "s%n", hostname, &n) == 1) {
s = DNS_Name2IPAddress(hostname, &src->ip_addr);
if (s == DNS_Success) {
ok = 1;
src->name = NULL;
} else if (s == DNS_TryAgain) {
ok = 1;
src->ip_addr.family = IPADDR_UNSPEC;
}
ok = 1;
}
if (!ok) {
@@ -197,7 +191,7 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
} while (!done);
}
if (ok && src->ip_addr.family == IPADDR_UNSPEC) {
if (ok) {
n = strlen(hostname);
src->name = MallocArray(char, n + 1);
strncpy(src->name, hostname, n);

View File

@@ -47,7 +47,6 @@ typedef enum {
} CPS_Status;
typedef struct {
IPAddr ip_addr;
char *name;
unsigned short port;
SourceParameters params;

134
conf.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2011
* Copyright (C) Miroslav Lichvar 2009-2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -36,6 +36,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "conf.h"
@@ -74,6 +76,7 @@ static void parse_logbanner(const char *);
static void parse_logdir(const char *);
static void parse_maxupdateskew(const char *);
static void parse_maxclockerror(const char *);
static void parse_corrtimeratio(const char *);
static void parse_reselectdist(const char *);
static void parse_stratumweight(const char *);
static void parse_peer(const char *);
@@ -95,6 +98,7 @@ static void parse_noclientlog(const char *);
static void parse_clientloglimit(const char *);
static void parse_fallbackdrift(const char *);
static void parse_makestep(const char *);
static void parse_maxchange(const char *);
static void parse_logchange(const char *);
static void parse_mailonchange(const char *);
static void parse_bindaddress(const char *);
@@ -107,6 +111,8 @@ static void parse_linux_freq_scale(const char *);
static void parse_sched_priority(const char *);
static void parse_lockall(const char *);
static void parse_tempcomp(const char *);
static void parse_include(const char *);
static void parse_leapsectz(const char *);
/* ================================================== */
/* Configuration variables */
@@ -119,7 +125,8 @@ static char *drift_file = NULL;
static char *rtc_file = NULL;
static unsigned long command_key_id;
static double max_update_skew = 1000.0;
static double max_clock_error = 10; /* in ppm */
static double correction_time_ratio = 1.0;
static double max_clock_error = 1.0; /* in ppm */
static double reselect_distance = 1e-4;
static double stratum_weight = 1.0;
@@ -163,6 +170,12 @@ static int rtc_sync = 0;
static int make_step_limit = 0;
static double make_step_threshold = 0.0;
/* Number of updates before offset checking, number of ignored updates
before exiting and the maximum allowed offset */
static int max_offset_delay = -1;
static int max_offset_ignore;
static double max_offset;
/* Flag set if we should log to syslog when a time adjustment
exceeding the threshold is initiated */
static int do_log_change = 0;
@@ -212,6 +225,9 @@ static double linux_freq_scale;
static int sched_priority = 0;
static int lock_memory = 0;
/* Name of a system timezone containing leap seconds occuring at midnight */
static char *leapsec_tz = NULL;
/* ================================================== */
typedef struct {
@@ -236,6 +252,7 @@ static const Command commands[] = {
{"dumpdir", 7, parse_dumpdir},
{"maxupdateskew", 13, parse_maxupdateskew},
{"maxclockerror", 13, parse_maxclockerror},
{"corrtimeratio", 13, parse_corrtimeratio},
{"commandkey", 10, parse_commandkey},
{"initstepslew", 12, parse_initstepslew},
{"local", 5, parse_local},
@@ -251,6 +268,7 @@ static const Command commands[] = {
{"clientloglimit", 14, parse_clientloglimit},
{"fallbackdrift", 13, parse_fallbackdrift},
{"makestep", 8, parse_makestep},
{"maxchange", 9, parse_maxchange},
{"logchange", 9, parse_logchange},
{"mailonchange", 12, parse_mailonchange},
{"bindaddress", 11, parse_bindaddress},
@@ -261,6 +279,8 @@ static const Command commands[] = {
{"tempcomp", 8, parse_tempcomp},
{"reselectdist", 12, parse_reselectdist},
{"stratumweight", 13, parse_stratumweight},
{"include", 7, parse_include},
{"leapsectz", 9, parse_leapsectz},
{"linux_hz", 8, parse_linux_hz},
{"linux_freq_scale", 16, parse_linux_freq_scale},
{"sched_priority", 14, parse_sched_priority},
@@ -313,6 +333,7 @@ CNF_ReadFile(const char *filename)
char line[2048];
char *p;
int i, ok;
int prev_line_number;
if (filename == NULL) {
filename = DEFAULT_CONF_FILE;
@@ -323,6 +344,9 @@ CNF_ReadFile(const char *filename)
LOG(LOGS_ERR, LOGF_Configure, "Could not open configuration file [%s]", filename);
} else {
/* Save current line number in case this is an included file */
prev_line_number = line_number;
line_number = 0;
/* Success */
@@ -357,6 +381,8 @@ CNF_ReadFile(const char *filename)
}
line_number = prev_line_number;
fclose(in);
}
@@ -458,10 +484,10 @@ static void
parse_refclock(const char *line)
{
int i, n, poll, dpoll, filter_length, pps_rate;
unsigned long ref_id, lock_ref_id;
uint32_t ref_id, lock_ref_id;
double offset, delay, precision;
const char *tmp;
char name[5], cmd[10 + 1], *param;
char cmd[10 + 1], *name, *param;
unsigned char ref[5];
SRC_SelectOption sel_option;
@@ -480,11 +506,20 @@ parse_refclock(const char *line)
lock_ref_id = 0;
sel_option = SRC_SelectNormal;
if (sscanf(line, "%4s%n", name, &n) != 1) {
while (isspace(line[0]))
line++;
tmp = line;
while (line[0] != '\0' && !isspace(line[0]))
line++;
if (line == tmp) {
LOG(LOGS_WARN, LOGF_Configure, "Could not read refclock driver name at line %d", line_number);
return;
}
line += n;
name = MallocArray(char, 1 + line - tmp);
strncpy(name, tmp, line - tmp);
name[line - tmp] = '\0';
while (isspace(line[0]))
line++;
@@ -494,6 +529,7 @@ parse_refclock(const char *line)
if (line == tmp) {
LOG(LOGS_WARN, LOGF_Configure, "Could not read refclock parameter at line %d", line_number);
Free(name);
return;
}
@@ -548,7 +584,7 @@ parse_refclock(const char *line)
line += n;
}
strncpy(refclock_sources[i].driver_name, name, 4);
refclock_sources[i].driver_name = name;
refclock_sources[i].driver_parameter = param;
refclock_sources[i].driver_poll = dpoll;
refclock_sources[i].poll = poll;
@@ -612,6 +648,16 @@ parse_maxclockerror(const char *line)
/* ================================================== */
static void
parse_corrtimeratio(const char *line)
{
if (sscanf(line, "%lf", &correction_time_ratio) != 1) {
LOG(LOGS_WARN, LOGF_Configure, "Could not read correction time ratio at line %d", line_number);
}
}
/* ================================================== */
static void
parse_reselectdist(const char *line)
{
@@ -910,6 +956,19 @@ parse_makestep(const char *line)
/* ================================================== */
static void
parse_maxchange(const char *line)
{
if (sscanf(line, "%lf %d %d", &max_offset, &max_offset_delay, &max_offset_ignore) != 3) {
max_offset_delay = -1;
LOG(LOGS_WARN, LOGF_Configure,
"Could not read offset, check delay or ignore limit for maximum change at line %d\n",
line_number);
}
}
/* ================================================== */
static void
parse_logchange(const char *line)
{
@@ -1218,6 +1277,26 @@ parse_tempcomp(const char *line)
/* ================================================== */
static void
parse_include(const char *line)
{
while (isspace(line[0]))
line++;
CNF_ReadFile(line);
}
/* ================================================== */
static void
parse_leapsectz(const char *line)
{
/* This must allocate enough space! */
leapsec_tz = MallocArray(char, 1 + strlen(line));
sscanf(line, "%s", leapsec_tz);
}
/* ================================================== */
static void
parse_linux_hz(const char *line)
{
@@ -1256,22 +1335,15 @@ CNF_ProcessInitStepSlew(void (*after_hook)(void *), void *anything)
void
CNF_AddSources(void) {
NTP_Remote_Address server;
int i;
for (i=0; i<n_ntp_sources; i++) {
if (ntp_sources[i].params.ip_addr.family != IPADDR_UNSPEC) {
server.ip_addr = ntp_sources[i].params.ip_addr;
memset(&server.local_ip_addr, 0, sizeof (server.local_ip_addr));
server.port = ntp_sources[i].params.port;
NSR_AddSource(&server, ntp_sources[i].type, &ntp_sources[i].params.params);
} else {
NSR_AddUnresolvedSource(ntp_sources[i].params.name, ntp_sources[i].params.port,
ntp_sources[i].type, &ntp_sources[i].params.params);
}
NSR_AddUnresolvedSource(ntp_sources[i].params.name, ntp_sources[i].params.port,
ntp_sources[i].type, &ntp_sources[i].params.params);
}
NSR_ResolveSources();
return;
}
@@ -1454,6 +1526,14 @@ CNF_GetMaxClockError(void)
/* ================================================== */
double
CNF_GetCorrectionTimeRatio(void)
{
return correction_time_ratio;
}
/* ================================================== */
double
CNF_GetReselectDistance(void)
{
@@ -1523,6 +1603,16 @@ CNF_GetMakeStep(int *limit, double *threshold)
/* ================================================== */
void
CNF_GetMaxChange(int *delay, int *ignore, double *offset)
{
*delay = max_offset_delay;
*ignore = max_offset_ignore;
*offset = max_offset;
}
/* ================================================== */
void
CNF_GetLogChange(int *enabled, double *threshold)
{
@@ -1632,6 +1722,14 @@ CNF_GetPidFile(void)
/* ================================================== */
char *
CNF_GetLeapSecTimezone(void)
{
return leapsec_tz;
}
/* ================================================== */
void
CNF_GetLinuxHz(int *set, int *hz)
{

3
conf.h
View File

@@ -60,6 +60,7 @@ extern int CNF_GetCommandPort(void);
extern int CNF_GetRTCOnUTC(void);
extern int CNF_GetRTCSync(void);
extern void CNF_GetMakeStep(int *limit, double *threshold);
extern void CNF_GetMaxChange(int *delay, int *ignore, double *offset);
extern void CNF_GetLogChange(int *enabled, double *threshold);
extern void CNF_GetMailOnChange(int *enabled, double *threshold, char **user);
extern int CNF_GetNoClientLog(void);
@@ -68,12 +69,14 @@ extern void CNF_GetFallbackDrifts(int *min, int *max);
extern void CNF_GetBindAddress(int family, IPAddr *addr);
extern void CNF_GetBindCommandAddress(int family, IPAddr *addr);
extern char *CNF_GetPidFile(void);
extern char *CNF_GetLeapSecTimezone(void);
extern void CNF_GetLinuxHz(int *set, int *hz);
extern void CNF_GetLinuxFreqScale(int *set, double *freq_scale);
/* Value returned in ppm, as read from file */
extern double CNF_GetMaxUpdateSkew(void);
extern double CNF_GetMaxClockError(void);
extern double CNF_GetCorrectionTimeRatio(void);
extern double CNF_GetReselectDistance(void);
extern double CNF_GetStratumWeight(void);

169
configure vendored
View File

@@ -4,9 +4,12 @@
# chronyd/chronyc - Programs for keeping computer clocks accurate.
#
# Copyright (C) Richard P. Curnow 1997-2003
# Copyright (C) Miroslav Lichvar 2009, 2012
#
# =======================================================================
rm -f config.h
# This configure script determines the operating system type and version
if [ "x${CC}" = "x" ]; then
@@ -24,9 +27,7 @@ fi
MYCPPFLAGS="${CPPFLAGS}"
if [ "x${MYCC}" = "xgcc" ]; then
CCWARNFLAGS="-Wmissing-prototypes -Wall"
else
CCWARNFLAGS=""
MYCFLAGS="${MYCFLAGS} -Wmissing-prototypes -Wall"
fi
MYLDFLAGS="${LDFLAGS}"
@@ -68,7 +69,7 @@ test_code () {
#}}}
#{{{ usage
usage () {
cat <<EOF;
cat <<EOF
\`configure' configures tdl to adapt to many kinds of systems.
Usage: ./configure [OPTION]...
@@ -97,10 +98,14 @@ For better control, use the options below.
--readline-inc-dir=DIR Specify where readline include directory is
--readline-lib-dir=DIR Specify where readline lib directory is
--with-ncurses-library=DIR Specify where ncurses lib directory is
--without-nss Don't use NSS even if it is available
--without-tomcrypt Don't use libtomcrypt even if it is available
--disable-ipv6 Disable IPv6 support
--disable-pps Disable PPS API support
--disable-rtc Don't include RTC even on Linux
--disable-linuxcaps Disable Linux capabilities support
--disable-forcednsretry Don't retry on permanent DNS error
--with-sendmail=PATH Path to sendmail binary [/usr/lib/sendmail]
Fine tuning of the installation directories:
--sysconfdir=DIR chrony.conf location [/etc]
@@ -131,6 +136,15 @@ EOF
}
#}}}
#{{{
add_def () {
if [ "x$2" = "x" ]; then
echo "#define $1 1" >> config.h
else
echo "#define $1 $2" >> config.h
fi
}
#}}}
# ======================================================================
@@ -150,7 +164,10 @@ SYSDEFS=""
feat_readline=1
try_readline=1
try_editline=1
try_nss=1
try_tomcrypt=1
feat_rtc=1
try_rtc=0
feat_linuxcaps=1
try_linuxcaps=0
readline_lib=""
@@ -160,12 +177,14 @@ feat_ipv6=1
feat_pps=1
try_setsched=0
try_lockmem=0
feat_forcednsretry=1
mail_program="/usr/lib/sendmail"
for option
do
case "$option" in
--trace )
EXTRA_DEFS="-DTRACEON"
add_def TRACEON
;;
--disable-readline )
feat_readline=0
@@ -224,6 +243,18 @@ do
--disable-linuxcaps)
feat_linuxcaps=0
;;
--disable-forcednsretry)
feat_forcednsretry=0
;;
--with-sendmail=* )
mail_program=`echo $option | sed -e 's/^.*=//;'`
;;
--without-nss )
try_nss=0
;;
--without-tomcrypt )
try_tomcrypt=0
;;
--host-system=* )
OPERATINGSYSTEM=`echo $option | sed -e 's/^.*=//;'`
;;
@@ -250,17 +281,17 @@ case $SYSTEM in
4.* )
EXTRA_OBJECTS="sys_sunos.o strerror.o"
EXTRA_LIBS="-lkvm"
SYSDEFS="-DSUNOS"
add_def SUNOS
echo "Configuring for SunOS (" $SYSTEM "version" $VERSION ")"
;;
5.* )
EXTRA_OBJECTS="sys_solaris.o"
EXTRA_LIBS="-lsocket -lnsl -lkvm -lelf"
EXTRA_CLI_LIBS="-lsocket -lnsl"
SYSDEFS="-DSOLARIS"
add_def SOLARIS
echo "Configuring for Solaris (" $SYSTEM "SunOS version" $VERSION ")"
if [ $VERSION = "5.3" ]; then
SYSDEFS="$SYSDEFS -DHAS_NO_BZERO"
add_def HAS_NO_BZERO
echo "Using memset() instead of bzero()"
fi
;;
@@ -268,19 +299,16 @@ case $SYSTEM in
;;
Linux* )
EXTRA_OBJECTS="sys_linux.o wrap_adjtimex.o"
if [ $feat_rtc -eq 1 ] ; then
EXTRA_OBJECTS="$EXTRA_OBJECTS rtc_linux.o"
EXTRA_DEFS="$EXTRA_DEFS -DFEAT_RTC=1"
fi
try_linuxcaps=1
try_rtc=1
try_setsched=1
try_lockmem=1
SYSDEFS="-DLINUX"
add_def LINUX
echo "Configuring for " $SYSTEM
if [ "${MACHINE}" = "alpha" ]; then
echo "Enabling -mieee"
# FIXME: Should really test for GCC
SYSDEFS="$SYSDEFS -mieee -DALPHA"
MYCFLAGS="$MYCFLAGS -mieee"
fi
;;
@@ -289,7 +317,7 @@ case $SYSTEM in
# be supported with the SunOS 4.x driver files.
EXTRA_OBJECTS="sys_sunos.o strerror.o"
EXTRA_LIBS="-lkvm"
SYSDEFS="-DSUNOS"
add_def SUNOS
echo "Configuring for $SYSTEM (using SunOS driver)"
;;
NetBSD-* )
@@ -304,13 +332,13 @@ case $SYSTEM in
EXTRA_OBJECTS="sys_solaris.o"
EXTRA_LIBS="-lsocket -lnsl -lkvm -lelf"
EXTRA_CLI_LIBS="-lsocket -lnsl"
SYSDEFS="-DSOLARIS"
add_def SOLARIS
echo "Configuring for Solaris (" $SYSTEM "SunOS version" $VERSION ")"
;;
CYGWIN32_NT-i[3456]86 )
EXTRA_OBJECTS="sys_winnt.o"
EXTRA_LIBS=""
SYSDEFS="-DWINNT"
add_def WINNT
echo "Configuring for Windows NT (Cygwin32)"
;;
* )
@@ -332,11 +360,11 @@ else
fi
if test_code '<stdint.h>' 'stdint.h' '' '' ''; then
SYSDEFS="${SYSDEFS} -DHAS_STDINT_H"
add_def HAS_STDINT_H
fi
if test_code '<inttypes.h>' 'inttypes.h' '' '' ''; then
SYSDEFS="${SYSDEFS} -DHAS_INTTYPES_H"
add_def HAS_INTTYPES_H
fi
if [ $feat_ipv6 = "1" ] && \
@@ -346,17 +374,42 @@ if [ $feat_ipv6 = "1" ] && \
n.sin6_addr = in6addr_any;
return !inet_ntop(AF_INET6, &n.sin6_addr.s6_addr, p, sizeof(p));'
then
SYSDEFS="${SYSDEFS} -DHAVE_IPV6"
add_def HAVE_IPV6
if test_code 'in6_pktinfo' 'sys/socket.h netinet/in.h' '' '' '
return sizeof(struct in6_pktinfo);'
then
add_def HAVE_IN6_PKTINFO
else
if test_code 'in6_pktinfo with _GNU_SOURCE' 'sys/socket.h netinet/in.h' \
'-D_GNU_SOURCE' '' 'return sizeof(struct in6_pktinfo);'
then
add_def _GNU_SOURCE
add_def HAVE_IN6_PKTINFO
fi
fi
fi
if [ $feat_pps = "1" ] && \
test_code 'PPS API' 'timepps.h' '' '' '
timepps_h=""
if [ $feat_pps = "1" ]; then
if test_code '<sys/timepps.h>' 'sys/timepps.h' '' '' ''; then
timepps_h="sys/timepps.h"
add_def HAVE_SYS_TIMEPPS_H
else
if test_code '<timepps.h>' 'timepps.h' '' '' ''; then
timepps_h="timepps.h"
add_def HAVE_TIMEPPS_H
fi
fi
fi
if [ "x$timepps_h" != "x" ] && \
test_code 'PPSAPI' "string.h $timepps_h" '' '' '
pps_handle_t h;
pps_info_t i;
struct timespec ts;
return time_pps_fetch(&h, PPS_TSFMT_TSPEC, &i, &ts);'
return time_pps_fetch(h, PPS_TSFMT_TSPEC, &i, &ts);'
then
SYSDEFS="${SYSDEFS} -DHAVE_PPSAPI"
add_def HAVE_PPSAPI
fi
if [ $feat_linuxcaps = "1" ] && [ $try_linuxcaps = "1" ] && \
@@ -366,10 +419,18 @@ if [ $feat_linuxcaps = "1" ] && [ $try_linuxcaps = "1" ] && \
'' '-lcap' \
'prctl(PR_SET_KEEPCAPS, 1);cap_set_proc(cap_from_text("cap_sys_time=ep"));'
then
EXTRA_DEFS="${EXTRA_DEFS} -DFEAT_LINUXCAPS=1"
add_def FEAT_LINUXCAPS
EXTRA_LIBS="-lcap"
fi
if [ $feat_rtc = "1" ] && [ $try_rtc = "1" ] && \
test_code '<linux/rtc.h>' 'sys/ioctl.h linux/rtc.h' '' '' \
'ioctl(1, RTC_UIE_ON&RTC_UIE_OFF&RTC_RD_TIME&RTC_SET_TIME, 0&RTC_UF);'
then
EXTRA_OBJECTS="$EXTRA_OBJECTS rtc_linux.o"
add_def FEAT_RTC
fi
if [ $try_setsched = "1" ] && \
test_code \
'sched_setscheduler()' \
@@ -378,7 +439,7 @@ if [ $try_setsched = "1" ] && \
sched_get_priority_max(SCHED_FIFO);
sched_setscheduler(0, SCHED_FIFO, &sched);'
then
SYSDEFS="${SYSDEFS} -DHAVE_SCHED_SETSCHEDULER"
add_def HAVE_SCHED_SETSCHEDULER
fi
if [ $try_lockmem = "1" ] && \
@@ -389,7 +450,12 @@ if [ $try_lockmem = "1" ] && \
setrlimit(RLIMIT_MEMLOCK, &rlim);
mlockall(MCL_CURRENT|MCL_FUTURE);'
then
SYSDEFS="${SYSDEFS} -DHAVE_MLOCKALL"
add_def HAVE_MLOCKALL
fi
if [ $feat_forcednsretry = "1" ]
then
add_def FORCE_DNSRETRY
fi
READLINE_COMPILE=""
@@ -400,7 +466,9 @@ if [ $feat_readline = "1" ]; then
"$readline_inc" "$readline_lib -ledit" \
'add_history(readline("prompt"));'
then
READLINE_COMPILE="-DFEAT_READLINE=1 -DUSE_EDITLINE=1 $readline_inc"
add_def FEAT_READLINE
add_def USE_EDITLINE
READLINE_COMPILE="$readline_inc"
READLINE_LINK="$readline_lib -ledit"
fi
fi
@@ -410,12 +478,40 @@ if [ $feat_readline = "1" ]; then
"$readline_inc" "$readline_lib $ncurses_lib -lreadline -lncurses" \
'add_history(readline("prompt"));'
then
READLINE_COMPILE="-DFEAT_READLINE=1 $readline_inc"
add_def FEAT_READLINE
READLINE_COMPILE="$readline_inc"
READLINE_LINK="$readline_lib $ncurses_lib -lreadline -lncurses"
fi
fi
fi
HASH_OBJ="hash_intmd5.o"
HASH_COMPILE=""
HASH_LINK=""
if [ $try_nss = "1" ]; then
test_cflags="`pkg-config --cflags nss`"
test_link="`pkg-config --libs-only-L nss` -lfreebl3"
if test_code 'NSS' 'nss.h hasht.h nsslowhash.h' \
"$test_cflags" "$test_link" \
'NSSLOWHASH_Begin(NSSLOWHASH_NewContext(NSSLOW_Init(), HASH_AlgSHA512));'
then
HASH_OBJ="hash_nss.o"
HASH_COMPILE="$test_cflags"
HASH_LINK="$test_link"
fi
fi
if [ "x$HASH_LINK" = "x" ] && [ $try_tomcrypt = "1" ]; then
if test_code 'tomcrypt' 'tomcrypt.h' '-I/usr/include/tomcrypt' '-ltomcrypt' \
'hash_memory_multi(find_hash("md5"), NULL, NULL, NULL, 0, NULL, 0);'
then
HASH_OBJ="hash_tomcrypt.o"
HASH_COMPILE="-I/usr/include/tomcrypt"
HASH_LINK="-ltomcrypt"
fi
fi
SYSCONFDIR=/etc
if [ "x$SETSYSCONFDIR" != "x" ]; then
SYSCONFDIR=$SETSYSCONFDIR
@@ -461,19 +557,28 @@ if [ "x$SETDOCDIR" != "x" ]; then
DOCDIR=$SETDOCDIR
fi
add_def DEFAULT_CONF_DIR "\"$SYSCONFDIR\""
add_def MAIL_PROGRAM "\"$mail_program\""
if [ -f version.txt ]; then
add_def CHRONY_VERSION "\"`cat version.txt`\""
else
add_def CHRONY_VERSION "\"DEVELOPMENT\""
fi
sed -e "s%@EXTRA_OBJECTS@%${EXTRA_OBJECTS}%;\
s%@CC@%${MYCC}%;\
s%@CFLAGS@%${MYCFLAGS}%;\
s%@CCWARNFLAGS@%${CCWARNFLAGS}%;\
s%@CPPFLAGS@%${CPPFLAGS}%;\
s%@LIBS@%${LIBS}%;\
s%@LDFLAGS@%${MYLDFLAGS}%;\
s%@EXTRA_LIBS@%${EXTRA_LIBS}%;\
s%@SYSDEFS@%${SYSDEFS}%;\
s%@EXTRA_DEFS@%${EXTRA_DEFS}%;\
s%@EXTRA_CLI_LIBS@%${EXTRA_CLI_LIBS}%;\
s%@READLINE_COMPILE@%${READLINE_COMPILE}%;\
s%@READLINE_LINK@%${READLINE_LINK}%;\
s%@HASH_OBJ@%${HASH_OBJ}%;\
s%@HASH_LINK@%${HASH_LINK}%;\
s%@HASH_COMPILE@%${HASH_COMPILE}%;\
s%@SYSCONFDIR@%${SYSCONFDIR}%;\
s%@BINDIR@%${BINDIR}%;\
s%@SBINDIR@%${SBINDIR}%;\

View File

@@ -0,0 +1,39 @@
# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
server 0.pool.ntp.org iburst
server 1.pool.ntp.org iburst
server 2.pool.ntp.org iburst
server 3.pool.ntp.org iburst
# Ignore stratum in source selection.
stratumweight 0
# Record the rate at which the system clock gains/losses time.
driftfile /var/lib/chrony/drift
# Enable kernel RTC synchronization.
rtcsync
# In first three updates step the system clock instead of slew
# if the adjustment is larger than 100 seconds.
makestep 100 3
# Allow client access from local network.
#allow 192.168/16
# Serve time even if not synchronized to any NTP server.
#local stratum 10
keyfile /etc/chrony.keys
# Specify the key used as password for chronyc.
commandkey 1
# Disable logging of client accesses.
noclientlog
# Send a message to syslog if a clock adjustment is larger than 0.5 seconds.
logchange 0.5
logdir /var/log/chrony
#log measurements statistics tracking

41
hash.h Normal file
View File

@@ -0,0 +1,41 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Header file for crypto hashing.
*/
#ifndef GOT_HASH_H
#define GOT_HASH_H
/* length of hash values produced by SHA512 */
#define MAX_HASH_LENGTH 64
extern int HSH_GetHashId(const char *name);
extern unsigned int HSH_Hash(int id,
const unsigned char *in1, unsigned int in1_len,
const unsigned char *in2, unsigned int in2_len,
unsigned char *out, unsigned int out_len);
#endif

64
hash_intmd5.c Normal file
View File

@@ -0,0 +1,64 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Routines implementing crypto hashing using internal MD5 implementation.
*/
#include "config.h"
#include "sysincl.h"
#include "hash.h"
#include "memory.h"
#include "md5.c"
static MD5_CTX ctx;
int
HSH_GetHashId(const char *name)
{
/* only MD5 is supported */
if (strcmp(name, "MD5"))
return -1;
return 0;
}
unsigned int
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
const unsigned char *in2, unsigned int in2_len,
unsigned char *out, unsigned int out_len)
{
if (out_len < 16)
return 0;
MD5Init(&ctx);
MD5Update(&ctx, in1, in1_len);
if (in2)
MD5Update(&ctx, in2, in2_len);
MD5Final(&ctx);
memcpy(out, ctx.digest, 16);
return 16;
}

89
hash_nss.c Normal file
View File

@@ -0,0 +1,89 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Routines implementing crypto hashing using NSSLOWHASH API of the NSS library.
*/
#include <nss.h>
#include <hasht.h>
#include <nsslowhash.h>
/* #include "config.h" */
#include "hash.h"
static NSSLOWInitContext *ictx;
struct hash {
HASH_HashType type;
const char *name;
NSSLOWHASHContext *context;
};
static struct hash hashes[] = {
{ HASH_AlgMD5, "MD5", NULL },
{ HASH_AlgSHA1, "SHA1", NULL },
{ HASH_AlgSHA256, "SHA256", NULL },
{ HASH_AlgSHA384, "SHA384", NULL },
{ HASH_AlgSHA512, "SHA512", NULL },
{ 0, NULL, NULL }
};
int
HSH_GetHashId(const char *name)
{
int i;
for (i = 0; hashes[i].name; i++) {
if (!strcmp(name, hashes[i].name))
break;
}
if (!hashes[i].name)
return -1; /* not found */
if (!ictx && !(ictx = NSSLOW_Init()))
return -1; /* couldn't init NSS */
if (!hashes[i].context &&
!(hashes[i].context = NSSLOWHASH_NewContext(ictx, hashes[i].type)))
return -1; /* couldn't init hash */
return i;
}
unsigned int
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
const unsigned char *in2, unsigned int in2_len,
unsigned char *out, unsigned int out_len)
{
unsigned int ret;
NSSLOWHASH_Begin(hashes[id].context);
NSSLOWHASH_Update(hashes[id].context, in1, in1_len);
if (in2)
NSSLOWHASH_Update(hashes[id].context, in2, in2_len);
NSSLOWHASH_End(hashes[id].context, out, &ret, out_len);
return ret;
}

116
hash_tomcrypt.c Normal file
View File

@@ -0,0 +1,116 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Routines implementing crypto hashing using tomcrypt library.
*/
#include <tomcrypt.h>
#include "config.h"
#include "hash.h"
struct hash {
const char *name;
const char *int_name;
const struct ltc_hash_descriptor *desc;
};
static const struct hash hashes[] = {
{ "MD5", "md5", &md5_desc },
#ifdef LTC_RIPEMD128
{ "RMD128", "rmd128", &rmd128_desc },
#endif
#ifdef LTC_RIPEMD160
{ "RMD160", "rmd160", &rmd160_desc },
#endif
#ifdef LTC_RIPEMD256
{ "RMD256", "rmd256", &rmd256_desc },
#endif
#ifdef LTC_RIPEMD320
{ "RMD320", "rmd320", &rmd320_desc },
#endif
#ifdef LTC_SHA1
{ "SHA1", "sha1", &sha1_desc },
#endif
#ifdef LTC_SHA256
{ "SHA256", "sha256", &sha256_desc },
#endif
#ifdef LTC_SHA384
{ "SHA384", "sha384", &sha384_desc },
#endif
#ifdef LTC_SHA512
{ "SHA512", "sha512", &sha512_desc },
#endif
#ifdef LTC_TIGER
{ "TIGER", "tiger", &tiger_desc },
#endif
#ifdef LTC_WHIRLPOOL
{ "WHIRLPOOL", "whirlpool", &whirlpool_desc },
#endif
{ NULL, NULL, NULL }
};
int
HSH_GetHashId(const char *name)
{
int i, h;
for (i = 0; hashes[i].name; i++) {
if (!strcmp(name, hashes[i].name))
break;
}
if (!hashes[i].name)
return -1; /* not found */
h = find_hash(hashes[i].int_name);
if (h >= 0)
return h; /* already registered */
/* register and try again */
register_hash(hashes[i].desc);
return find_hash(hashes[i].int_name);
}
unsigned int
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
const unsigned char *in2, unsigned int in2_len,
unsigned char *out, unsigned int out_len)
{
unsigned long len;
int r;
len = out_len;
if (in2)
r = hash_memory_multi(id, out, &len,
in1, (unsigned long)in1_len, in2, (unsigned long)in2_len, NULL, 0);
else
r = hash_memory(id, in1, in1_len, out, &len);
if (r != CRYPT_OK)
return 0;
return len;
}

View File

@@ -1,75 +0,0 @@
/* Taken from <asm-$foo/ioctl.h> in the Linux kernel sources.
* The ioctl.h file is pretty similar from one architecture to another.
* */
#ifndef IO_LINUX_H
#define IO_LINUX_H
/* Hmm. These constants vary a bit between systems. */
/* (__sh__ includes both sh and sh64) */
/* (__s390__ includes both s390 and s390x) */
#if defined(__i386__) || defined(__sh__) || defined(__arm__) || defined(__x86_64__) || defined(__s390__)
#define CHRONY_IOC_NRBITS 8
#define CHRONY_IOC_TYPEBITS 8
#define CHRONY_IOC_SIZEBITS 14
#define CHRONY_IOC_DIRBITS 2
#define CHRONY_IOC_NONE 0U
#define CHRONY_IOC_WRITE 1U
#define CHRONY_IOC_READ 2U
#elif defined(__alpha__) || defined(__sparc__) || defined(__ppc__) || defined(__ppc64__) || defined(__sparc64__)
#define CHRONY_IOC_NRBITS 8
#define CHRONY_IOC_TYPEBITS 8
#define CHRONY_IOC_SIZEBITS 13
#define CHRONY_IOC_DIRBITS 2
#define CHRONY_IOC_NONE 1U
#define CHRONY_IOC_READ 2U
#define CHRONY_IOC_WRITE 4U
#elif defined(__mips__) || defined(__mips32__) || defined(__powerpc__)
#define CHRONY_IOC_NRBITS 8
#define CHRONY_IOC_TYPEBITS 8
#define CHRONY_IOC_SIZEBITS 13
#define CHRONY_IOC_DIRBITS 3
#define CHRONY_IOC_NONE 1U
#define CHRONY_IOC_READ 2U
#define CHRONY_IOC_WRITE 4U
#else
#error "I don't know the values of the _IOC_* constants for your architecture"
#endif
#define CHRONY_IOC_NRMASK ((1 << CHRONY_IOC_NRBITS)-1)
#define CHRONY_IOC_TYPEMASK ((1 << CHRONY_IOC_TYPEBITS)-1)
#define CHRONY_IOC_SIZEMASK ((1 << CHRONY_IOC_SIZEBITS)-1)
#define CHRONY_IOC_DIRMASK ((1 << CHRONY_IOC_DIRBITS)-1)
#define CHRONY_IOC_NRSHIFT 0
#define CHRONY_IOC_TYPESHIFT (CHRONY_IOC_NRSHIFT+CHRONY_IOC_NRBITS)
#define CHRONY_IOC_SIZESHIFT (CHRONY_IOC_TYPESHIFT+CHRONY_IOC_TYPEBITS)
#define CHRONY_IOC_DIRSHIFT (CHRONY_IOC_SIZESHIFT+CHRONY_IOC_SIZEBITS)
#define CHRONY_IOC(dir,type,nr,size) \
(((dir) << CHRONY_IOC_DIRSHIFT) | \
((type) << CHRONY_IOC_TYPESHIFT) | \
((nr) << CHRONY_IOC_NRSHIFT) | \
((size) << CHRONY_IOC_SIZESHIFT))
/* used to create numbers */
#define CHRONY_IO(type,nr) CHRONY_IOC(CHRONY_IOC_NONE,(type),(nr),0)
#define CHRONY_IOR(type,nr,size) CHRONY_IOC(CHRONY_IOC_READ,(type),(nr),sizeof(size))
#define CHRONY_IOW(type,nr,size) CHRONY_IOC(CHRONY_IOC_WRITE,(type),(nr),sizeof(size))
#define CHRONY_IOWR(type,nr,size) CHRONY_IOC(CHRONY_IOC_READ|CHRONY_IOC_WRITE,(type),(nr),sizeof(size))
#define RTC_UIE_ON CHRONY_IO('p', 0x03) /* Update int. enable on */
#define RTC_UIE_OFF CHRONY_IO('p', 0x04) /* ... off */
#define RTC_RD_TIME CHRONY_IOR('p', 0x09, struct rtc_time) /* Read RTC time */
#define RTC_SET_TIME CHRONY_IOW('p', 0x0a, struct rtc_time) /* Set RTC time */
/* From mc146818.h */
#define RTC_UIE 0x10 /* update-finished interrupt enable */
#endif

182
keys.c
View File

@@ -3,6 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -25,6 +26,8 @@
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -32,11 +35,17 @@
#include "keys.h"
#include "conf.h"
#include "memory.h"
#include "util.h"
#include "local.h"
#include "logging.h"
typedef struct {
unsigned long id;
char *val;
int len;
int hash_id;
int auth_delay;
} Key;
#define MAX_KEYS 256
@@ -45,7 +54,7 @@ static int n_keys;
static Key keys[MAX_KEYS];
static int command_key_valid;
static int command_key_pos;
static int command_key_id;
static int cache_valid;
static unsigned long cache_key_id;
static int cache_key_pos;
@@ -73,6 +82,37 @@ KEY_Finalise(void)
/* ================================================== */
static int
determine_hash_delay(int key_id)
{
NTP_Packet pkt;
struct timeval before, after;
unsigned long usecs, min_usecs=0;
int i;
for (i = 0; i < 10; i++) {
LCL_ReadRawTime(&before);
KEY_GenerateAuth(key_id, (unsigned char *)&pkt, NTP_NORMAL_PACKET_SIZE,
(unsigned char *)&pkt.auth_data, sizeof (pkt.auth_data));
LCL_ReadRawTime(&after);
usecs = (after.tv_sec - before.tv_sec) * 1000000 + (after.tv_usec - before.tv_usec);
if (i == 0 || usecs < min_usecs) {
min_usecs = usecs;
}
}
#if 0
LOG(LOGS_INFO, LOGF_Keys, "authentication delay for key %d: %d useconds", key_id, min_usecs);
#endif
/* Add on a bit extra to allow for copying, conversions etc */
return min_usecs + (min_usecs >> 4);
}
/* ================================================== */
/* Compare two keys */
static int
@@ -100,16 +140,16 @@ compare_keys_by_id(const void *a, const void *b)
void
KEY_Reload(void)
{
int i, len1;
int i, len1, fields;
char *key_file;
FILE *in;
unsigned long key_id;
char line[KEYLEN+1], keyval[KEYLEN+1];
char line[KEYLEN+1], buf1[KEYLEN+1], buf2[KEYLEN+1];
char *keyval, *hashname;
for (i=0; i<n_keys; i++) {
Free(keys[i].val);
}
n_keys = 0;
key_file = CNF_GetKeysFile();
@@ -125,12 +165,30 @@ KEY_Reload(void)
if (line[len1] == '\n') {
line[len1] = '\0';
}
fields = sscanf(line, "%lu%" SKEYLEN "s%" SKEYLEN "s", &key_id, buf1, buf2);
if (fields >= 2 && fields <= 3) {
if (fields == 3) {
hashname = buf1;
keyval = buf2;
} else {
hashname = "MD5";
keyval = buf1;
}
keys[n_keys].hash_id = HSH_GetHashId(hashname);
if (keys[n_keys].hash_id < 0) {
LOG(LOGS_WARN, LOGF_Keys, "Unknown hash function in key %d", key_id);
continue;
}
keys[n_keys].len = UTI_DecodePasswordFromText(keyval);
if (!keys[n_keys].len) {
LOG(LOGS_WARN, LOGF_Keys, "Could not decode password in key %d", key_id);
continue;
}
if (sscanf(line, "%lu%" SKEYLEN "s", &key_id, keyval) == 2) {
keys[n_keys].id = key_id;
keys[n_keys].len = strlen(keyval);
keys[n_keys].val = MallocArray(char, 1 + keys[n_keys].len);
strcpy(keys[n_keys].val, keyval);
keys[n_keys].val = MallocArray(char, keys[n_keys].len);
memcpy(keys[n_keys].val, keyval, keys[n_keys].len);
n_keys++;
}
}
@@ -141,12 +199,20 @@ KEY_Reload(void)
more careful! */
qsort((void *) keys, n_keys, sizeof(Key), compare_keys_by_id);
/* Erase the passwords from stack */
memset(line, 0, sizeof (line));
memset(buf1, 0, sizeof (buf1));
memset(buf2, 0, sizeof (buf2));
}
}
command_key_valid = 0;
cache_valid = 0;
for (i=0; i<n_keys; i++) {
keys[i].auth_delay = determine_hash_delay(keys[i].id);
}
return;
}
@@ -170,30 +236,8 @@ lookup_key(unsigned long id)
/* ================================================== */
void
KEY_CommandKey(char **key, int *len)
{
unsigned long command_key_id;
if (!command_key_valid) {
command_key_id = CNF_GetCommandKey();
command_key_pos = lookup_key(command_key_id);
command_key_valid = 1;
}
if (command_key_pos >= 0) {
*key = keys[command_key_pos].val;
*len = keys[command_key_pos].len;
} else {
*key = "";
*len = 0;
}
}
/* ================================================== */
int
KEY_GetKey(unsigned long key_id, char **key, int *len)
static int
get_key_pos(unsigned long key_id)
{
if (!cache_valid || key_id != cache_key_id) {
cache_valid = 1;
@@ -201,15 +245,19 @@ KEY_GetKey(unsigned long key_id, char **key, int *len)
cache_key_id = key_id;
}
if (cache_key_pos >= 0) {
*key = keys[cache_key_pos].val;
*len = keys[cache_key_pos].len;
return 1;
} else {
*key = "";
*len = 0;
return 0;
return cache_key_pos;
}
/* ================================================== */
unsigned long
KEY_GetCommandKey(void)
{
if (!command_key_valid) {
command_key_id = CNF_GetCommandKey();
}
return command_key_id;
}
/* ================================================== */
@@ -237,3 +285,57 @@ KEY_KeyKnown(unsigned long key_id)
}
}
}
/* ================================================== */
int
KEY_GetAuthDelay(unsigned long key_id)
{
int key_pos;
key_pos = get_key_pos(key_id);
if (key_pos < 0) {
return 0;
}
return keys[key_pos].auth_delay;
}
/* ================================================== */
int
KEY_GenerateAuth(unsigned long key_id, const unsigned char *data, int data_len,
unsigned char *auth, int auth_len)
{
int key_pos;
key_pos = get_key_pos(key_id);
if (key_pos < 0) {
return 0;
}
return UTI_GenerateNTPAuth(keys[key_pos].hash_id,
(unsigned char *)keys[key_pos].val, keys[key_pos].len,
data, data_len, auth, auth_len);
}
/* ================================================== */
int
KEY_CheckAuth(unsigned long key_id, const unsigned char *data, int data_len,
const unsigned char *auth, int auth_len)
{
int key_pos;
key_pos = get_key_pos(key_id);
if (key_pos < 0) {
return 0;
}
return UTI_CheckNTPAuth(keys[key_pos].hash_id,
(unsigned char *)keys[key_pos].val, keys[key_pos].len,
data, data_len, auth, auth_len);
}

8
keys.h
View File

@@ -32,9 +32,15 @@ extern void KEY_Finalise(void);
extern void KEY_Reload(void);
extern void KEY_CommandKey(char **key, int *len);
extern unsigned long KEY_GetCommandKey(void);
extern int KEY_GetKey(unsigned long key_id, char **key, int *len);
extern int KEY_KeyKnown(unsigned long key_id);
extern int KEY_GetAuthDelay(unsigned long key_id);
extern int KEY_GenerateAuth(unsigned long key_id, const unsigned char *data,
int data_len, unsigned char *auth, int auth_len);
extern int KEY_CheckAuth(unsigned long key_id, const unsigned char *data,
int data_len, const unsigned char *auth, int auth_len);
#endif /* GOT_KEYS_H */

35
local.c
View File

@@ -28,6 +28,8 @@
They interface with the system specific driver files in sys_*.c
*/
#include "config.h"
#include <assert.h>
#include <stddef.h>
@@ -103,12 +105,11 @@ static double max_clock_error;
static void
calculate_sys_precision(void)
{
struct timeval tv, old_tv, first_tv;
struct timeval tv, old_tv;
int dusec, best_dusec;
int iters;
gettimeofday(&old_tv, NULL);
first_tv = old_tv;
best_dusec = 1000000; /* Assume we must be better than a second */
iters = 0;
do {
@@ -357,14 +358,14 @@ LCL_GetOffsetCorrection(struct timeval *raw, double *correction, double *err)
}
/* ================================================== */
/* This is just a simple passthrough of the system specific routine */
/* Return current frequency */
double
LCL_ReadAbsoluteFrequency(void)
{
double freq;
freq = (*drv_read_freq)();
freq = current_freq_ppm;
/* Undo temperature compensation */
if (temp_comp_ppm != 0.0) {
@@ -442,7 +443,7 @@ LCL_AccumulateDeltaFrequency(double dfreq)
/* ================================================== */
void
LCL_AccumulateOffset(double offset)
LCL_AccumulateOffset(double offset, double corr_rate)
{
ChangeListEntry *ptr;
struct timeval raw, cooked;
@@ -453,7 +454,7 @@ LCL_AccumulateOffset(double offset)
LCL_ReadRawTime(&raw);
LCL_CookTime(&raw, &cooked, NULL);
(*drv_accrue_offset)(offset);
(*drv_accrue_offset)(offset, corr_rate);
/* Dispatch to all handlers */
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
@@ -488,7 +489,23 @@ LCL_ApplyStepOffset(double offset)
/* ================================================== */
void
LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset)
LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked,
double offset, double dispersion)
{
ChangeListEntry *ptr;
/* Dispatch to all handlers */
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
(ptr->handler)(raw, cooked, 0.0, offset, 1, ptr->anything);
}
lcl_InvokeDispersionNotifyHandlers(dispersion);
}
/* ================================================== */
void
LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
{
ChangeListEntry *ptr;
struct timeval raw, cooked;
@@ -515,7 +532,7 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset)
current_freq_ppm = (*drv_set_freq)(current_freq_ppm);
dfreq = (current_freq_ppm - old_freq_ppm) / (1.0e6 + old_freq_ppm);
(*drv_accrue_offset)(doffset);
(*drv_accrue_offset)(doffset, corr_rate);
/* Dispatch to all handlers */
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
@@ -581,7 +598,7 @@ LCL_MakeStep(double threshold)
return 0;
/* Cancel remaining slew and make the step */
LCL_AccumulateOffset(correction);
LCL_AccumulateOffset(correction, 0.0);
LCL_ApplyStepOffset(-correction);
LOG(LOGS_WARN, LOGF_Local, "System clock was stepped by %.3f seconds", correction);

12
local.h
View File

@@ -138,9 +138,10 @@ extern void LCL_AccumulateDeltaFrequency(double dfreq);
/* Routine to apply an offset (in seconds) to the local clock. The
argument should be positive to move the clock backwards (i.e. the
local clock is currently fast of true time), or negative to move it
forwards (i.e. it is currently slow of true time). */
forwards (i.e. it is currently slow of true time). Provided is also
a suggested correction rate (correction time * offset). */
extern void LCL_AccumulateOffset(double offset);
extern void LCL_AccumulateOffset(double offset, double corr_rate);
/* Routine to apply an immediate offset by doing a sudden step if
possible. (Intended for use after an initial estimate of offset has
@@ -151,9 +152,14 @@ extern void LCL_AccumulateOffset(double offset);
extern void LCL_ApplyStepOffset(double offset);
/* Routine to invoke notify handlers on an unexpected time jump
in system clock */
extern void LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked,
double offset, double dispersion);
/* Perform the combination of modifying the frequency and applying
a slew, in one easy step */
extern void LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset);
extern void LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate);
/* Routine to read the system precision as a log to base 2 value. */
extern int LCL_GetSysPrecisionAsLog(void);

View File

@@ -41,8 +41,9 @@ typedef double (*lcl_ReadFrequencyDriver)(void);
typedef double (*lcl_SetFrequencyDriver)(double freq_ppm);
/* System driver to accrue an offset. A positive argument means slew
the clock forwards. */
typedef void (*lcl_AccrueOffsetDriver)(double offset);
the clock forwards. The suggested correction rate of time to correct the
offset is given in 'corr_rate'. */
typedef void (*lcl_AccrueOffsetDriver)(double offset, double corr_rate);
/* System driver to apply a step offset. A positive argument means step
the clock forwards. */

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011
* Copyright (C) Miroslav Lichvar 2011-2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -25,12 +25,13 @@
Module to handle logging of diagnostic information
*/
#include "config.h"
#include "sysincl.h"
#include "main.h"
#include "conf.h"
#include "logging.h"
#include "version.h"
#include "mkdirpp.h"
#include "util.h"
@@ -40,6 +41,8 @@ static int initialised = 0;
static int system_log = 0;
static int parent_fd = 0;
static time_t last_limited = 0;
#ifdef WINNT
@@ -153,6 +156,10 @@ LOG_Fatal_Function(LOG_Facility facility, const char *format, ...)
} else {
fprintf(stderr, "Fatal error : %s\n", buf);
}
if (parent_fd) {
if (write(parent_fd, buf, strlen(buf) + 1) < 0)
; /* Not much we can do here */
}
#endif
MAI_CleanupAndExit();
@@ -190,12 +197,28 @@ LOG_OpenSystemLog(void)
#else
system_log = 1;
openlog("chronyd", LOG_PID, LOG_DAEMON);
LOG(LOGS_INFO, LOGF_Logging, "chronyd version %s starting", PROGRAM_VERSION_STRING);
#endif
}
/* ================================================== */
void
LOG_SetParentFd(int fd)
{
parent_fd = fd;
}
/* ================================================== */
void
LOG_CloseParentFd()
{
if (parent_fd > 0)
close(parent_fd);
}
/* ================================================== */
int
LOG_RateLimited(void)
{
@@ -282,14 +305,10 @@ LOG_CreateLogFileDir(void)
{
const char *logdir;
if (n_filelogs <= 0)
return;
logdir = CNF_GetLogDir();
if (!mkdir_and_parents(logdir)) {
LOG(LOGS_ERR, LOGF_Logging, "Could not create directory %s", logdir);
n_filelogs = 0;
}
}

View File

@@ -54,6 +54,7 @@ typedef enum {
LOGF_CmdMon,
LOGF_Acquire,
LOGF_Manual,
LOGF_Keys,
LOGF_Logging,
LOGF_Rtc,
LOGF_Regress,
@@ -85,6 +86,12 @@ extern void LOG_Position(const char *filename, int line_number, const char *func
/* Log messages to syslog instead of stderr */
extern void LOG_OpenSystemLog(void);
/* Send fatal message also to the foreground process */
extern void LOG_SetParentFd(int fd);
/* Close the pipe to the foreground process so it can exit */
extern void LOG_CloseParentFd(void);
/* Return zero once per 10 seconds */
extern int LOG_RateLimited(void);

63
main.c
View File

@@ -4,6 +4,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) John G. Hasler 2009
* Copyright (C) Miroslav Lichvar 2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -25,6 +26,8 @@
The main program
*/
#include "config.h"
#include "sysincl.h"
#include "main.h"
@@ -43,7 +46,6 @@
#include "keys.h"
#include "acquire.h"
#include "manual.h"
#include "version.h"
#include "rtc.h"
#include "refclock.h"
#include "clientlog.h"
@@ -114,7 +116,6 @@ MAI_CleanupAndExit(void)
static void
signal_cleanup(int x)
{
LOG(LOGS_WARN, LOGF_Main, "chronyd exiting on signal");
if (!initialised) exit(0);
SCH_QuitProgram();
}
@@ -124,6 +125,8 @@ signal_cleanup(int x)
static void
post_acquire_hook(void *anything)
{
/* Close the pipe to the foreground process so it can exit */
LOG_CloseParentFd();
CNF_AddSources();
CNF_AddBroadcasts();
@@ -214,7 +217,13 @@ go_daemon(void)
#else
int pid, fd;
int pid, fd, pipefd[2];
/* Create pipe which will the daemon use to notify the grandparent
when it's initialised or send an error message */
if (pipe(pipefd)) {
LOG(LOGS_ERR, LOGF_Logging, "Could not detach, pipe failed : %s", strerror(errno));
}
/* Does this preserve existing signal handlers? */
pid = fork();
@@ -222,8 +231,22 @@ go_daemon(void)
if (pid < 0) {
LOG(LOGS_ERR, LOGF_Logging, "Could not detach, fork failed : %s", strerror(errno));
} else if (pid > 0) {
exit(0); /* In the 'grandparent' */
/* In the 'grandparent' */
char message[1024];
int r;
close(pipefd[1]);
r = read(pipefd[0], message, sizeof (message));
if (r) {
if (r > 0) {
/* Print the error message from the child */
fprintf(stderr, "%.1024s\n", message);
}
exit(1);
} else
exit(0);
} else {
close(pipefd[0]);
setsid();
@@ -237,10 +260,19 @@ go_daemon(void)
} else {
/* In the child we want to leave running as the daemon */
/* Don't keep stdin/out/err from before. */
for (fd=0; fd<1024; fd++) {
close(fd);
/* Change current directory to / */
if (chdir("/") < 0) {
LOG(LOGS_ERR, LOGF_Logging, "Could not chdir to / : %s", strerror(errno));
}
/* Don't keep stdin/out/err from before. But don't close
the parent pipe yet. */
for (fd=0; fd<1024; fd++) {
if (fd != pipefd[1])
close(fd);
}
LOG_SetParentFd(pipefd[1]);
}
}
@@ -287,7 +319,7 @@ int main
do_init_rtc = 1;
} else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
/* This write to the terminal is OK, it comes before we turn into a daemon */
printf("chronyd (chrony) version %s\n", PROGRAM_VERSION_STRING);
printf("chronyd (chrony) version %s\n", CHRONY_VERSION);
exit(0);
} else if (!strcmp("-n", *argv)) {
nofork = 1;
@@ -303,9 +335,6 @@ int main
}
}
CNF_ReadFile(conf_file);
#ifndef SYS_WINNT
if (getuid() != 0) {
/* This write to the terminal is OK, it comes before we turn into a daemon */
fprintf(stderr,"Not superuser\n");
@@ -321,19 +350,21 @@ int main
LOG_OpenSystemLog();
}
LOG(LOGS_INFO, LOGF_Main, "chronyd version %s starting", CHRONY_VERSION);
CNF_ReadFile(conf_file);
/* Check whether another chronyd may already be running. Do this after
* forking, so that message logging goes to the right place (i.e. syslog), in
* case this chronyd is being run from a boot script. */
if (maybe_another_chronyd_running(&other_pid)) {
LOG_FATAL(LOGF_Main, "Another chronyd may already be running (pid=%d), check lockfile (%s)",
other_pid, CNF_GetPidFile());
exit(1);
}
/* Write our lockfile to prevent other chronyds running. This has *GOT* to
* be done *AFTER* the daemon-creation fork() */
write_lockfile();
#endif
if (do_init_rtc) {
RTC_TimePreInit();
@@ -364,6 +395,8 @@ int main
SYS_DropRoot(user);
}
LOG_CreateLogFileDir();
REF_Initialise();
SST_Initialise();
BRD_Initialise();
@@ -375,8 +408,6 @@ int main
MNL_Initialise();
TMC_Initialise();
LOG_CreateLogFileDir();
/* From now on, it is safe to do finalisation on exit */
initialised = 1;
@@ -397,6 +428,8 @@ int main
the scheduler. */
SCH_MainLoop();
LOG(LOGS_INFO, LOGF_Main, "chronyd exiting");
MAI_CleanupAndExit();
return 0;

View File

@@ -1,52 +1,51 @@
#!/usr/bin/env perl
#!/bin/sh
$tool = "chrony";
LANG=C
export LANG
$version = shift || die "Usage : $0 <version>\n";
$subdir = "${tool}-${version}";
if [ $# -ne 1 ]; then
echo "Usage : $0 <version>"
exit 2
fi
unless (-d ".git") {
die "No .git subdirectory?"
}
version=$1
subdir=chrony-${version}
mandate=$(date +'%B %Y')
unless (-d "RELEASES") {
mkdir "RELEASES", 0755;
}
umask 022
system ("git tag -s $version");
die "git-tag failed" if ($? != 0);
if (-d "RELEASES/$subdir") {
system ("rm -rf RELEASES/$subdir");
}
if [ ! -d .git ]; then
echo "No .git subdirectory?"
exit 3
fi
system ("git archive --format=tar --prefix=RELEASES/${subdir}/ $version | tar xf -");
die "git-tar-tree failed" if ($? != 0);
[ -d RELEASES ] || mkdir RELEASES
chdir "RELEASES";
$here = qx/pwd/;
chomp $here;
chdir $subdir;
git tag -s $version || exit 1
open (OUT, ">version.txt");
print OUT $version."\n";
close OUT;
rm -rf RELEASES/$subdir
open (IN, "<${tool}.spec.sample");
open (OUT, ">${tool}.spec");
while (<IN>) {
s/\@\@VERSION\@\@/$version/;
print OUT;
}
close (IN);
close (OUT);
git archive --format=tar --prefix=RELEASES/${subdir}/ $version | \
tar xf - || exit 1
system("makeinfo --no-headers --number-sections -o chrony.txt chrony.texi");
unlink "make_release";
unlink "${tool}.spec.sample";
unlink ".gitignore";
cd RELEASES/$subdir || exit 1
chdir $here;
system ("tar cvf - $subdir | gzip -9 > ${subdir}.tar.gz");
system ("gpg -b -a -o ${subdir}-tar-gz-asc.txt ${subdir}.tar.gz");
echo $version > version.txt
sed -e "s%@@VERSION@@%${version}%" < chrony.spec.sample > chrony.spec
for m in chrony.1 chronyc.1 chrony.conf.5 chronyd.8; do
sed -e "s%@VERSION@%${version}%;s%@MAN_DATE@%${mandate}%" \
< $m > ${m}_
mv -f ${m}_ $m
done
makeinfo --no-headers --number-sections -o chrony.txt chrony.texi
rm -f make_release chrony.spec.sample .gitignore
cd ..
tar cvf - $subdir | gzip -9 > ${subdir}.tar.gz
gpg -b -a -o ${subdir}-tar-gz-asc.txt ${subdir}.tar.gz

View File

@@ -30,6 +30,8 @@
*/
#include "config.h"
#include <stddef.h>
#include "manual.h"
@@ -143,6 +145,8 @@ estimate_and_set_system(struct timeval *now, int offset_provided, double offset,
}
b1 = freq = 0.0;
found_freq = 0;
agos[0] = 0.0;
offsets[0] = b0;
}
if (offset_provided) {

View File

@@ -26,6 +26,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "mkdirpp.h"

View File

@@ -1,15 +0,0 @@
#!/bin/sh
rm -f version.h
echo "#ifndef VERSION_H" > version.h
echo "#define VERSION_H 1" >> version.h
if [ -f version.txt ]; then
ver=`cat version.txt`
echo "#define PROGRAM_VERSION_STRING \"$ver\"" >> version.h
else
echo "#define PROGRAM_VERSION_STRING \"DEVELOPMENT\"" >> version.h
fi
echo "#endif /* VERSION_H */" >> version.h

View File

@@ -26,6 +26,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "nameserv.h"
@@ -56,7 +58,11 @@ DNS_Name2IPAddress(const char *name, IPAddr *addr)
result = getaddrinfo(name, NULL, &hints, &res);
if (result) {
#ifdef FORCE_DNSRETRY
return DNS_TryAgain;
#else
return result == EAI_AGAIN ? DNS_TryAgain : DNS_Failure;
#endif
}
for (ai = res; !result && ai != NULL; ai = ai->ai_next) {
@@ -94,8 +100,13 @@ DNS_Name2IPAddress(const char *name, IPAddr *addr)
return DNS_Success;
}
#ifdef FORCE_DNSRETRY
return DNS_TryAgain;
#else
return DNS_Failure;
#endif
#endif
}
/* ================================================== */

8
ntp.h
View File

@@ -33,6 +33,8 @@
#include <inttypes.h>
#endif
#include "hash.h"
typedef struct {
uint32_t hi;
uint32_t lo;
@@ -40,7 +42,7 @@ typedef struct {
typedef uint32_t NTP_int32;
#define AUTH_DATA_LEN 16
#define MAX_NTP_AUTH_DATA_LEN MAX_HASH_LENGTH
/* Type definition for leap bits */
typedef enum {
@@ -72,7 +74,7 @@ typedef struct {
NTP_int64 receive_ts;
NTP_int64 transmit_ts;
NTP_int32 auth_keyid;
uint8_t auth_data[AUTH_DATA_LEN];
uint8_t auth_data[MAX_NTP_AUTH_DATA_LEN];
} NTP_Packet;
/* We have to declare a buffer type to hold a datagram read from the
@@ -89,7 +91,7 @@ typedef union {
uint8_t arbitrary[MAX_NTP_MESSAGE_SIZE];
} ReceiveBuffer;
#define NTP_NORMAL_PACKET_SIZE (sizeof(NTP_Packet) - (sizeof(NTP_int32) + AUTH_DATA_LEN))
#define NTP_NORMAL_PACKET_SIZE offsetof(NTP_Packet, auth_keyid)
/* ================================================== */

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2011
* Copyright (C) Miroslav Lichvar 2009-2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -25,6 +25,8 @@
Core NTP protocol engine
*/
#include "config.h"
#include "sysincl.h"
#include "ntp_core.h"
@@ -38,7 +40,6 @@
#include "conf.h"
#include "logging.h"
#include "keys.h"
#include "md5.h"
#include "addrfilt.h"
#include "clientlog.h"
@@ -190,6 +191,10 @@ struct NCR_Instance_Record {
/* The NTP protocol version that we support */
#define NTP_VERSION 3
/* Compatible NTP protocol versions */
#define NTP_MAX_COMPAT_VERSION 4
#define NTP_MIN_COMPAT_VERSION 2
/* Maximum allowed dispersion - as defined in RFC1305 (16 seconds) */
#define NTP_MAX_DISPERSION 16.0
@@ -206,13 +211,10 @@ struct NCR_Instance_Record {
static ADF_AuthTable access_auth_table;
static int md5_offset_usecs;
/* ================================================== */
/* Forward prototypes */
static void transmit_timeout(void *arg);
static void determine_md5_delay(void);
/* ================================================== */
@@ -224,9 +226,6 @@ NCR_Initialise(void)
: -1;
access_auth_table = ADF_CreateTable();
determine_md5_delay();
}
/* ================================================== */
@@ -357,100 +356,11 @@ NCR_DestroyInstance(NCR_Instance instance)
/* ================================================== */
/* ================================================== */
static int
generate_packet_auth(NTP_Packet *pkt, unsigned long keyid)
check_packet_auth(NTP_Packet *pkt, unsigned long keyid, int auth_len)
{
int keylen;
char *keytext;
int keyok;
MD5_CTX ctx;
keyok = KEY_GetKey(keyid, &keytext, &keylen);
if (keyok) {
pkt->auth_keyid = htonl(keyid);
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char *) keytext, keylen);
MD5Update(&ctx, (unsigned char *) pkt, offsetof(NTP_Packet, auth_keyid));
MD5Final(&ctx);
memcpy(&(pkt->auth_data), &ctx.digest, 16);
return 1;
} else {
pkt->auth_keyid = htonl(0);
return 0;
}
}
/* ================================================== */
static void
determine_md5_delay(void)
{
NTP_Packet pkt;
struct timeval before, after;
unsigned long usecs, min_usecs=0;
MD5_CTX ctx;
static const char *example_key = "#a0,243asd=-b ds";
int slen;
int i;
slen = strlen(example_key);
for (i=0; i<10; i++) {
LCL_ReadRawTime(&before);
MD5Init(&ctx);
MD5Update(&ctx, (unsigned const char *) example_key, slen);
MD5Update(&ctx, (unsigned const char *) &pkt, offsetof(NTP_Packet, auth_keyid));
MD5Final(&ctx);
LCL_ReadRawTime(&after);
usecs = (after.tv_sec - before.tv_sec) * 1000000 + (after.tv_usec - before.tv_usec);
if (i == 0) {
min_usecs = usecs;
} else {
if (usecs < min_usecs) {
min_usecs = usecs;
}
}
}
#ifdef TRACEON
LOG(LOGS_INFO, LOGF_NtpCore, "MD5 took %d useconds", min_usecs);
#endif
/* Add on a bit extra to allow for copying, conversions etc */
md5_offset_usecs = min_usecs + (min_usecs >> 4);
}
/* ================================================== */
static int
check_packet_auth(NTP_Packet *pkt, unsigned long keyid)
{
int keylen;
char *keytext;
int keyok;
MD5_CTX ctx;
keyok = KEY_GetKey(keyid, &keytext, &keylen);
if (keyok) {
pkt->auth_keyid = htonl(keyid);
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char *) keytext, keylen);
MD5Update(&ctx, (unsigned char *) pkt, offsetof(NTP_Packet, auth_keyid));
MD5Final(&ctx);
if (!memcmp((void *) &ctx.digest, (void *) &(pkt->auth_data), 16)) {
return 1;
} else {
return 0;
}
} else {
return 0;
}
return KEY_CheckAuth(keyid, (void *)pkt, offsetof(NTP_Packet, auth_keyid),
(void *)&(pkt->auth_data), auth_len);
}
/* ================================================== */
@@ -509,11 +419,11 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
/* Parameters read from reference module */
int are_we_synchronised, our_stratum;
NTP_Leap leap_status;
unsigned long our_ref_id;
uint32_t our_ref_id;
struct timeval our_ref_time;
double our_root_delay, our_root_dispersion;
version = 3;
version = NTP_VERSION;
LCL_ReadCookedTime(&local_transmit, NULL);
REF_GetReferenceParams(&local_transmit,
@@ -525,7 +435,7 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
if (are_we_synchronised) {
leap = (int) leap_status;
} else {
leap = 3;
leap = LEAP_Unsynchronised;
}
/* Generate transmit packet */
@@ -566,13 +476,21 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
/* Authenticate */
if (do_auth) {
int auth_len;
/* Pre-compensate the transmit time by approx. how long it will
take to generate the MD5 authentication bytes. */
local_transmit.tv_usec += md5_offset_usecs;
take to generate the authentication data. */
local_transmit.tv_usec += KEY_GetAuthDelay(key_id);
UTI_NormaliseTimeval(&local_transmit);
UTI_TimevalToInt64(&local_transmit, &message.transmit_ts);
generate_packet_auth(&message, key_id);
NIO_SendAuthenticatedPacket(&message, where_to);
auth_len = KEY_GenerateAuth(key_id, (unsigned char *) &message,
offsetof(NTP_Packet, auth_keyid),
(unsigned char *)&message.auth_data, sizeof (message.auth_data));
if (auth_len > 0) {
message.auth_keyid = htonl(key_id);
NIO_SendAuthenticatedPacket(&message, where_to,
sizeof (message.auth_keyid) + auth_len);
}
} else {
UTI_TimevalToInt64(&local_transmit, &message.transmit_ts);
NIO_SendNormalPacket(&message, where_to);
@@ -717,7 +635,7 @@ transmit_timeout(void *arg)
/* ================================================== */
static void
receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance inst, int do_auth)
receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance inst, int auth_len)
{
int pkt_leap;
int source_is_synchronized;
@@ -888,7 +806,7 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
sample_time = local_average;
/* Calculate skew */
skew = source_freq_hi - source_freq_lo;
skew = (source_freq_hi - source_freq_lo) / 2.0;
/* and then calculate peer dispersion */
epsilon = LCL_GetSysPrecisionAsQuantum() + now_err + skew * local_interval;
@@ -926,7 +844,8 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
round trip delay to the minimum one currently in the stats data
register is less than an administrator-defined value */
if (fabs(delta/SRC_MinRoundTripDelay(inst->source)) > inst->max_delay_ratio) {
if (inst->max_delay_ratio > 1.0 &&
fabs(delta/SRC_MinRoundTripDelay(inst->source)) > inst->max_delay_ratio) {
test4b = 0; /* Failed */
} else {
test4b = 1; /* Success */
@@ -946,12 +865,12 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
/* Test 5 relates to authentication. */
if (inst->do_auth) {
if (do_auth) {
if (auth_len > 0) {
auth_key_id = ntohl(message->auth_keyid);
if (!KEY_KeyKnown(auth_key_id)) {
test5 = 0;
} else {
test5 = check_packet_auth(message, auth_key_id);
test5 = check_packet_auth(message, auth_key_id, auth_len);
}
} else {
/* If we expect authenticated info from this peer/server and the packet
@@ -1307,27 +1226,28 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
*/
/* ================================================== */
/* This routine is called when a new packet arrives off the network,
and it relates to a source we have an ongoing protocol exchange with */
static void
process_known
void
NCR_ProcessKnown
(NTP_Packet *message, /* the received message */
struct timeval *now, /* timestamp at time of receipt */
double now_err,
NCR_Instance inst, /* the instance record for this peer/server */
int do_auth /* whether the received packet allegedly contains
authentication info*/
int length /* the length of the received packet */
)
{
int pkt_mode;
int version;
int valid_auth, valid_key;
int authenticate_reply;
int authenticate_reply, auth_len;
unsigned long auth_key_id;
unsigned long reply_auth_key_id;
/* Check version */
version = (message->lvm >> 3) & 0x7;
if (version != NTP_VERSION) {
if (version < NTP_MIN_COMPAT_VERSION || version > NTP_MAX_COMPAT_VERSION) {
/* Ignore packet, but might want to log it */
return;
}
@@ -1335,6 +1255,12 @@ process_known
/* Perform tests mentioned in RFC1305 to validate packet contents */
pkt_mode = (message->lvm >> 0) & 0x7;
/* Length of the authentication data, if any */
auth_len = length - (NTP_NORMAL_PACKET_SIZE + sizeof (message->auth_keyid));
if (auth_len < 0) {
auth_len = 0;
}
/* Now, depending on the mode we decide what to do */
switch (pkt_mode) {
case MODE_CLIENT:
@@ -1358,11 +1284,11 @@ process_known
CLG_LogNTPClientAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec);
if (do_auth) {
if (auth_len > 0) {
auth_key_id = ntohl(message->auth_keyid);
valid_key = KEY_KeyKnown(auth_key_id);
if (valid_key) {
valid_auth = check_packet_auth(message, auth_key_id);
valid_auth = check_packet_auth(message, auth_key_id, auth_len);
} else {
valid_auth = 0;
}
@@ -1401,7 +1327,7 @@ process_known
case MODE_ACTIVE:
/* Ordinary symmetric peering */
CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec);
receive_packet(message, now, now_err, inst, do_auth);
receive_packet(message, now, now_err, inst, auth_len);
break;
case MODE_PASSIVE:
/* In this software this case should not arise, we don't
@@ -1411,7 +1337,7 @@ process_known
/* This is where we have the remote configured as a server and he has
us configured as a peer - fair enough. */
CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec);
receive_packet(message, now, now_err, inst, do_auth);
receive_packet(message, now, now_err, inst, auth_len);
break;
case MODE_SERVER:
/* Nonsense - we can't have a preconfigured server */
@@ -1432,14 +1358,14 @@ process_known
case MODE_ACTIVE:
/* Slightly bizarre combination, but we can still process it */
CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec);
receive_packet(message, now, now_err, inst, do_auth);
receive_packet(message, now, now_err, inst, auth_len);
break;
case MODE_PASSIVE:
/* We have no passive peers in this software */
break;
case MODE_CLIENT:
/* Standard case where he's a server and we're the client */
receive_packet(message, now, now_err, inst, do_auth);
receive_packet(message, now, now_err, inst, auth_len);
break;
case MODE_SERVER:
/* RFC1305 error condition. */
@@ -1460,7 +1386,7 @@ process_known
/* This would arise if we have the remote configured as a peer and
he does not have us configured */
CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec);
receive_packet(message, now, now_err, inst, do_auth);
receive_packet(message, now, now_err, inst, auth_len);
break;
case MODE_PASSIVE:
/* Error condition in RFC1305. Also, we can't have any
@@ -1469,7 +1395,7 @@ process_known
break;
case MODE_CLIENT:
/* This is a wierd combination - how could it arise? */
receive_packet(message, now, now_err, inst, do_auth);
receive_packet(message, now, now_err, inst, auth_len);
break;
case MODE_SERVER:
/* Error condition in RFC1305 */
@@ -1492,9 +1418,6 @@ process_known
break;
}
}
/* ================================================== */
@@ -1502,95 +1425,27 @@ process_known
and it relates to a source we have an ongoing protocol exchange with */
void
NCR_ProcessNoauthKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance inst)
NCR_ProcessUnknown
(NTP_Packet *message, /* the received message */
struct timeval *now, /* timestamp at time of receipt */
double now_err, /* assumed error in the timestamp */
NTP_Remote_Address *remote_addr,
int length /* the length of the received packet */
)
{
process_known(message, now, now_err, inst, 0);
}
/* ================================================== */
/* This routine is called when a new packet arrives off the network,
and we do not recognize its source */
void
NCR_ProcessNoauthUnknown(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr)
{
NTP_Mode his_mode;
NTP_Mode my_mode;
int my_poll;
if (ADF_IsAllowed(access_auth_table, &remote_addr->ip_addr)) {
his_mode = message->lvm & 0x07;
if (his_mode == MODE_CLIENT) {
/* We are server */
my_mode = MODE_SERVER;
CLG_LogNTPClientAccess(&remote_addr->ip_addr, (time_t) now->tv_sec);
} else if (his_mode == MODE_ACTIVE) {
/* We are symmetric passive, even though we don't ever lock to him */
my_mode = MODE_PASSIVE;
CLG_LogNTPPeerAccess(&remote_addr->ip_addr, (time_t) now->tv_sec);
} else {
my_mode = MODE_UNDEFINED;
}
/* If we can't determine a sensible mode to reply with, it means
he has supplied a wierd mode in his request, so ignore it. */
if (my_mode != MODE_UNDEFINED) {
my_poll = message->poll; /* What should this be set to? Does the client actually care? */
transmit_packet(my_mode, my_poll,
0, 0UL,
&message->transmit_ts, /* Originate (for us) is the transmit time for the client */
now, /* Time we received the packet */
NULL, /* Don't care when we send reply, we aren't maintaining state about this client */
NULL, /* Ditto */
remote_addr);
}
} else if (!LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_NtpCore, "NTP packet received from unauthorised host %s port %d",
UTI_IPToString(&remote_addr->ip_addr),
remote_addr->port);
}
return;
}
/* ================================================== */
/* This routine is called when a new authenticated packet arrives off
the network, and it relates to a source we have an ongoing protocol
exchange with */
void
NCR_ProcessAuthKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance data)
{
process_known(message, now, now_err, data, 1);
}
/* ================================================== */
/* This routine is called when a new authenticated packet arrives off
the network, and we do not recognize its source */
void
NCR_ProcessAuthUnknown(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr)
{
NTP_Mode his_mode;
NTP_Mode my_mode;
int my_poll;
int valid_key, valid_auth;
int my_poll, version;
int valid_key, valid_auth, auth_len;
unsigned long key_id;
/* Check version */
version = (message->lvm >> 3) & 0x7;
if (version < NTP_MIN_COMPAT_VERSION || version > NTP_MAX_COMPAT_VERSION) {
/* Ignore packet, but might want to log it */
return;
}
if (ADF_IsAllowed(access_auth_table, &remote_addr->ip_addr)) {
his_mode = message->lvm & 0x07;
@@ -1613,23 +1468,28 @@ NCR_ProcessAuthUnknown(NTP_Packet *message, struct timeval *now, double now_err,
he has supplied a wierd mode in his request, so ignore it. */
if (my_mode != MODE_UNDEFINED) {
int do_auth = 0;
auth_len = length - (NTP_NORMAL_PACKET_SIZE + sizeof (message->auth_keyid));
/* Only reply if we know the key and the packet authenticates
properly. */
key_id = ntohl(message->auth_keyid);
valid_key = KEY_KeyKnown(key_id);
if (auth_len > 0) {
/* Only reply if we know the key and the packet authenticates
properly. */
key_id = ntohl(message->auth_keyid);
valid_key = KEY_KeyKnown(key_id);
do_auth = 1;
if (valid_key) {
valid_auth = check_packet_auth(message, key_id);
} else {
valid_auth = 0;
if (valid_key) {
valid_auth = check_packet_auth(message, key_id, auth_len);
} else {
valid_auth = 0;
}
}
if (valid_key && valid_auth) {
if (!do_auth || (valid_key && valid_auth)) {
my_poll = message->poll; /* What should this be set to? Does the client actually care? */
transmit_packet(my_mode, my_poll,
1, key_id,
do_auth, do_auth ? key_id : 0,
&message->transmit_ts, /* Originate (for us) is the transmit time for the client */
now, /* Time we received the packet */
NULL, /* Don't care when we send reply, we aren't maintaining state about this client */
@@ -1637,10 +1497,12 @@ NCR_ProcessAuthUnknown(NTP_Packet *message, struct timeval *now, double now_err,
remote_addr);
}
}
} else if (!LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_NtpCore, "NTP packet received from unauthorised host %s port %d",
UTI_IPToString(&remote_addr->ip_addr),
remote_addr->port);
}
return;
}
/* ================================================== */
@@ -1661,6 +1523,8 @@ NCR_SlewTimes(NCR_Instance inst, struct timeval *when, double dfreq, double doff
#ifdef TRACEON
LOG(LOGS_INFO, LOGF_NtpCore, "tx prev=[%s] new=[%s]",
UTI_TimevalToString(&prev), UTI_TimevalToString(&inst->local_tx));
#else
(void)prev;
#endif
}
@@ -1809,34 +1673,22 @@ NCR_InitiateSampleBurst(NCR_Instance inst, int n_good_samples, int n_total_sampl
break;
case MD_ONLINE:
inst->opmode = MD_BURST_WAS_ONLINE;
inst->burst_good_samples_to_go = n_good_samples;
inst->burst_total_samples_to_go = n_total_samples;
if (inst->timer_running) {
SCH_RemoveTimeout(inst->timeout_id);
}
inst->timer_running = 1;
inst->timeout_id = SCH_AddTimeoutInClass(0.0, SAMPLING_SEPARATION,
SAMPLING_RANDOMNESS,
SCH_NtpSamplingClass,
transmit_timeout, (void *) inst);
break;
case MD_OFFLINE:
inst->opmode = MD_BURST_WAS_OFFLINE;
if (inst->opmode == MD_ONLINE)
inst->opmode = MD_BURST_WAS_ONLINE;
else
inst->opmode = MD_BURST_WAS_OFFLINE;
inst->burst_good_samples_to_go = n_good_samples;
inst->burst_total_samples_to_go = n_total_samples;
if (inst->timer_running) {
SCH_RemoveTimeout(inst->timeout_id);
}
inst->timer_running = 1;
inst->timeout_id = SCH_AddTimeoutInClass(0.0, SAMPLING_SEPARATION,
inst->timeout_id = SCH_AddTimeoutInClass(INITIAL_DELAY, SAMPLING_SEPARATION,
SAMPLING_RANDOMNESS,
SCH_NtpSamplingClass,
transmit_timeout, (void *) inst);
break;
default:
assert(0);
break;

View File

@@ -54,20 +54,11 @@ extern void NCR_DestroyInstance(NCR_Instance instance);
/* This routine is called when a new packet arrives off the network,
and it relates to a source we have an ongoing protocol exchange with */
extern void NCR_ProcessNoauthKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance data);
extern void NCR_ProcessKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance data, int length);
/* This routine is called when a new packet arrives off the network,
and we do not recognize its source */
extern void NCR_ProcessNoauthUnknown(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr);
/* This routine is called when a new authenticated packet arrives off
the network, and it relates to a source we have an ongoing protocol
exchange with */
extern void NCR_ProcessAuthKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance data);
/* This routine is called when a new authenticated packet arrives off
the network, and we do not recognize its source */
extern void NCR_ProcessAuthUnknown(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr);
extern void NCR_ProcessUnknown(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, int length);
/* Slew receive and transmit times in instance records */
extern void NCR_SlewTimes(NCR_Instance inst, struct timeval *when, double dfreq, double doffset);

View File

@@ -26,6 +26,8 @@
This file deals with the IO aspects of reading and writing NTP packets
*/
#include "config.h"
#include "sysincl.h"
#include "ntp_io.h"
@@ -157,6 +159,16 @@ prepare_socket(int family)
LOG(LOGS_ERR, LOGF_NtpIO, "Could not request IPV6_V6ONLY socket option");
}
#endif
#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");
}
#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");
}
#endif
}
#endif
@@ -343,6 +355,17 @@ read_from_socket(void *anything)
}
#endif
#if defined(IPV6_PKTINFO) && defined(HAVE_IN6_PKTINFO)
if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
struct in6_pktinfo ipi;
memcpy(&ipi, CMSG_DATA(cmsg), sizeof(ipi));
memcpy(&remote_addr.local_ip_addr.addr.in6, &ipi.ipi6_addr.s6_addr,
sizeof (remote_addr.local_ip_addr.addr.in6));
remote_addr.local_ip_addr.family = IPADDR_INET6;
}
#endif
#ifdef SO_TIMESTAMP
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMP) {
struct timeval tv;
@@ -353,13 +376,9 @@ read_from_socket(void *anything)
#endif
}
if (status == NTP_NORMAL_PACKET_SIZE) {
if (status >= NTP_NORMAL_PACKET_SIZE && status <= sizeof(NTP_Packet)) {
NSR_ProcessReceive((NTP_Packet *) &message.ntp_pkt, &now, now_err, &remote_addr);
} else if (status == sizeof(NTP_Packet)) {
NSR_ProcessAuthenticatedReceive((NTP_Packet *) &message.ntp_pkt, &now, now_err, &remote_addr);
NSR_ProcessReceive((NTP_Packet *) &message.ntp_pkt, &now, now_err, &remote_addr, status);
} else {
@@ -443,6 +462,25 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr)
}
#endif
#if defined(IPV6_PKTINFO) && defined(HAVE_IN6_PKTINFO)
if (remote_addr->local_ip_addr.family == IPADDR_INET6) {
struct cmsghdr *cmsg;
struct in6_pktinfo *ipi;
cmsg = CMSG_FIRSTHDR(&msg);
memset(cmsg, 0, CMSG_SPACE(sizeof(struct in6_pktinfo)));
cmsglen += CMSG_SPACE(sizeof(struct in6_pktinfo));
cmsg->cmsg_level = IPPROTO_IPV6;
cmsg->cmsg_type = IPV6_PKTINFO;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
ipi = (struct in6_pktinfo *) CMSG_DATA(cmsg);
memcpy(&ipi->ipi6_addr.s6_addr, &remote_addr->local_ip_addr.addr.in6,
sizeof(ipi->ipi6_addr.s6_addr));
}
#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));
@@ -481,9 +519,9 @@ NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr)
/* Send an authenticated packet to a given address */
void
NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr)
NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, int auth_len)
{
send_packet((void *) packet, sizeof(NTP_Packet), remote_addr);
send_packet((void *) packet, NTP_NORMAL_PACKET_SIZE + auth_len, remote_addr);
}
/* ================================================== */

View File

@@ -41,7 +41,7 @@ extern void NIO_Finalise(void);
extern void NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr);
/* Function to transmit an authenticated packet */
extern void NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr);
extern void NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_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);

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011
* Copyright (C) Miroslav Lichvar 2011-2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -27,6 +27,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "ntp_sources.h"
@@ -285,6 +287,19 @@ NSR_AddUnresolvedSource(char *name, int port, NTP_Source_Type type, SourceParame
/* ================================================== */
void
NSR_ResolveSources(void)
{
/* Try to resolve unresolved sources now */
if (resolving_interval) {
SCH_RemoveTimeout(resolving_id);
resolving_interval--;
resolve_sources(NULL);
}
}
/* ================================================== */
/* Procedure to remove a source. We don't bother whether the port
address is matched - we're only interested in removing a record for
the right IP address. Thus the caller can specify the port number
@@ -331,9 +346,10 @@ NSR_RemoveSource(NTP_Remote_Address *remote_addr)
/* ================================================== */
/* This routine is called by ntp_io when a new packet arrives off the network.*/
/* This routine is called by ntp_io when a new packet arrives off the network,
possibly with an authentication tail */
void
NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr)
NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, int length)
{
int slot, found;
@@ -347,27 +363,9 @@ NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP
find_slot(remote_addr, &slot, &found);
if (found == 2) { /* Must match IP address AND port number */
NCR_ProcessNoauthKnown(message, now, now_err, records[slot].data);
NCR_ProcessKnown(message, now, now_err, records[slot].data, length);
} else {
NCR_ProcessNoauthUnknown(message, now, now_err, remote_addr);
}
}
/* ================================================== */
/* This routine is called by ntp_io when a new packet with an authentication tail arrives off the network */
void
NSR_ProcessAuthenticatedReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr)
{
int slot, found;
assert(initialised);
find_slot(remote_addr, &slot, &found);
if (found == 2) {
NCR_ProcessAuthKnown(message, now, now_err, records[slot].data);
} else {
NCR_ProcessAuthUnknown(message, now, now_err, remote_addr);
NCR_ProcessUnknown(message, now, now_err, remote_addr, length);
}
}
@@ -404,12 +402,7 @@ NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address)
int i;
int any;
/* Try to resolve unresolved sources now */
if (resolving_interval) {
SCH_RemoveTimeout(resolving_id);
resolving_interval--;
resolve_sources(NULL);
}
NSR_ResolveSources();
any = 0;
for (i=0; i<N_RECORDS; i++) {
@@ -672,9 +665,10 @@ NSR_GetActivityReport(RPT_ActivityReport *report)
}
}
/* Add unresolved sources to offline count */
report->unresolved = 0;
for (us = unresolved_sources; us; us = us->next) {
report->offline++;
report->unresolved++;
}
return;

View File

@@ -54,14 +54,14 @@ extern NSR_Status NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type
until it succeeds or fails with a non-temporary error. */
extern void NSR_AddUnresolvedSource(char *name, int port, NTP_Source_Type type, SourceParameters *params);
/* Procedure to try resolve unresolved sources immediately. */
extern void NSR_ResolveSources(void);
/* Procedure to remove a source */
extern NSR_Status NSR_RemoveSource(NTP_Remote_Address *remote_addr);
/* This routine is called by ntp_io when a new packet arrives off the network */
extern void NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr);
/* This routine is called by ntp_io when a new packet with an authentication tail arrives off the network */
extern void NSR_ProcessAuthenticatedReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr);
extern void NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, int length);
/* Initialisation function */
extern void NSR_Initialise(void);

View File

@@ -26,6 +26,8 @@
integer endianness within the structures.
*/
#include "config.h"
#include "sysincl.h"
#include "util.h"
@@ -147,6 +149,8 @@ PKL_CommandLength(CMD_Request *r)
return offsetof(CMD_Request, data.activity.EOR);
case REQ_RESELECT:
return offsetof(CMD_Request, data.reselect.EOR);
case REQ_RESELECTDISTANCE:
return offsetof(CMD_Request, data.reselect_distance.EOR);
case REQ_MODIFY_MINSTRATUM:
return offsetof(CMD_Request, data.modify_minstratum.EOR);
case REQ_MODIFY_POLLTARGET:

View File

@@ -25,6 +25,8 @@
*/
#include "config.h"
#include "refclock.h"
#include "reference.h"
#include "conf.h"
@@ -72,8 +74,8 @@ struct RCL_Instance_Record {
int leap_status;
int pps_rate;
struct MedianFilter filter;
unsigned long ref_id;
unsigned long lock_ref;
uint32_t ref_id;
uint32_t lock_ref;
double offset;
double delay;
double precision;
@@ -112,6 +114,11 @@ RCL_Initialise(void)
{
CNF_AddRefclocks();
if (n_sources > 0) {
LCL_AddParameterChangeHandler(slew_samples, NULL);
LCL_AddDispersionNotifyHandler(add_dispersion, NULL);
}
logfileid = CNF_GetLogRefclocks() ? LOG_FileOpen("refclocks",
" Date (UTC) Time Refid DP L P Raw offset Cooked offset Disp.")
: -1;
@@ -148,14 +155,14 @@ RCL_AddRefclock(RefclockParameters *params)
if (n_sources == MAX_RCL_SOURCES)
return 0;
if (strncmp(params->driver_name, "SHM", 4) == 0) {
if (strcmp(params->driver_name, "SHM") == 0) {
inst->driver = &RCL_SHM_driver;
inst->precision = 1e-6;
} else if (strncmp(params->driver_name, "SOCK", 4) == 0) {
} else if (strcmp(params->driver_name, "SOCK") == 0) {
inst->driver = &RCL_SOCK_driver;
inst->precision = 1e-9;
pps_source = 1;
} else if (strncmp(params->driver_name, "PPS", 4) == 0) {
} else if (strcmp(params->driver_name, "PPS") == 0) {
inst->driver = &RCL_PPS_driver;
inst->precision = 1e-9;
pps_source = 1;
@@ -175,7 +182,7 @@ RCL_AddRefclock(RefclockParameters *params)
inst->driver_poll = params->driver_poll;
inst->poll = params->poll;
inst->driver_polled = 0;
inst->leap_status = 0;
inst->leap_status = LEAP_Normal;
inst->pps_rate = params->pps_rate;
inst->lock_ref = params->lock_ref_id;
inst->offset = params->offset;
@@ -242,6 +249,8 @@ RCL_AddRefclock(RefclockParameters *params)
#endif
n_sources++;
Free(params->driver_name);
return 1;
}
@@ -264,18 +273,13 @@ RCL_StartRefclocks(void)
} else
inst->lock_ref = -1;
}
if (n_sources > 0) {
LCL_AddParameterChangeHandler(slew_samples, NULL);
LCL_AddDispersionNotifyHandler(add_dispersion, NULL);
}
}
void
RCL_ReportSource(RPT_SourceReport *report, struct timeval *now)
{
int i;
unsigned long ref_id;
uint32_t ref_id;
assert(report->ip_addr.family == IPADDR_INET4);
ref_id = report->ip_addr.addr.in4;
@@ -334,7 +338,7 @@ RCL_GetDriverOption(RCL_Instance instance, char *name)
}
int
RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset, NTP_Leap leap_status)
RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset, int leap)
{
double correction, dispersion;
struct timeval cooked_time;
@@ -347,7 +351,17 @@ RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset,
return 0;
filter_add_sample(&instance->filter, &cooked_time, offset - correction + instance->offset, dispersion);
instance->leap_status = leap_status;
switch (leap) {
case LEAP_Normal:
case LEAP_InsertSecond:
case LEAP_DeleteSecond:
instance->leap_status = leap;
break;
default:
instance->leap_status = LEAP_Unsynchronised;
break;
}
log_sample(instance, &cooked_time, 0, 0, offset, offset - correction + instance->offset, dispersion);
@@ -416,7 +430,7 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
int is_synchronised, stratum;
double root_delay, root_dispersion, distance;
NTP_Leap leap;
unsigned long ref_id;
uint32_t ref_id;
/* Ignore the pulse if we are not well synchronized */
@@ -467,7 +481,7 @@ pps_stratum(RCL_Instance instance, struct timeval *tv)
int is_synchronised, stratum, i;
double root_delay, root_dispersion;
NTP_Leap leap;
unsigned long ref_id;
uint32_t ref_id;
REF_GetReferenceParams(tv, &is_synchronised, &leap, &stratum,
&ref_id, &ref_time, &root_delay, &root_dispersion);
@@ -825,8 +839,8 @@ filter_get_sample(struct MedianFilter *filter, struct timeval *sample_time, doub
prev_avg_var = filter->avg_var;
/* update exponential moving average of the variance */
if (filter->avg_var_n > 100) {
filter->avg_var += dof / (dof + 100.0) * (var - filter->avg_var);
if (filter->avg_var_n > 50) {
filter->avg_var += dof / (dof + 50.0) * (var - filter->avg_var);
} else {
filter->avg_var = (filter->avg_var * filter->avg_var_n + var * dof) /
(dof + filter->avg_var_n);
@@ -867,6 +881,8 @@ filter_slew_samples(struct MedianFilter *filter, struct timeval *when, double df
#if 0
LOG(LOGS_INFO, LOGF_Refclock, "i=%d old_off=%.9f new_off=%.9f",
i, prev_offset, filter->samples[i].offset);
#else
(void)prev_offset;
#endif
}
}

View File

@@ -32,14 +32,14 @@
#include "sources.h"
typedef struct {
char driver_name[4];
char *driver_name;
char *driver_parameter;
int driver_poll;
int poll;
int filter_length;
int pps_rate;
unsigned long ref_id;
unsigned long lock_ref_id;
uint32_t ref_id;
uint32_t lock_ref_id;
double offset;
double delay;
double precision;
@@ -66,7 +66,7 @@ extern void RCL_SetDriverData(RCL_Instance instance, void *data);
extern void *RCL_GetDriverData(RCL_Instance instance);
extern char *RCL_GetDriverParameter(RCL_Instance instance);
extern char *RCL_GetDriverOption(RCL_Instance instance, char *name);
extern int RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset, NTP_Leap leap_status);
extern int RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset, int leap);
extern int RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second);
#endif

View File

@@ -25,11 +25,17 @@
*/
#include "config.h"
#include "refclock.h"
#if HAVE_PPSAPI
#if defined(HAVE_SYS_TIMEPPS_H)
#include <sys/timepps.h>
#elif defined(HAVE_TIMEPPS_H)
#include <timepps.h>
#endif
#include "logging.h"
#include "memory.h"

View File

@@ -25,6 +25,8 @@
*/
#include "config.h"
#include "refclock.h"
#include "logging.h"
#include "util.h"

View File

@@ -25,6 +25,8 @@
*/
#include "config.h"
#include "refclock.h"
#include "logging.h"
#include "util.h"

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2011
* Copyright (C) Miroslav Lichvar 2009-2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -25,6 +25,8 @@
This module keeps track of the source which we are claiming to be
our reference, for the purposes of generating outgoing NTP packets */
#include "config.h"
#include "sysincl.h"
#include "memory.h"
@@ -43,10 +45,9 @@ static int local_stratum;
static NTP_Leap our_leap_status;
static int our_leap_sec;
static int our_stratum;
static unsigned long our_ref_id;
static uint32_t our_ref_id;
static IPAddr our_ref_ip;
struct timeval our_ref_time; /* Stored relative to reference, NOT local time */
static double our_offset;
static double our_skew;
static double our_residual_freq;
static double our_root_delay;
@@ -54,6 +55,12 @@ static double our_root_dispersion;
static double max_update_skew;
static double last_offset;
static double avg2_offset;
static int avg2_moving;
static double correction_time_ratio;
/* Flag indicating that we are initialised */
static int initialised = 0;
@@ -61,6 +68,12 @@ static int initialised = 0;
static int make_step_limit;
static double make_step_threshold;
/* Number of updates before offset checking, number of ignored updates
before exiting and the maximum allowed offset */
static int max_offset_delay;
static int max_offset_ignore;
static double max_offset;
/* Flag and threshold for logging clock changes to syslog */
static int do_log_change;
static double log_change_threshold;
@@ -76,7 +89,10 @@ static double drift_file_age;
static void update_drift_file(double, double);
#define MAIL_PROGRAM "/usr/lib/sendmail"
/* Name of a system timezone containing leap seconds occuring at midnight */
static char *leap_tzname;
static time_t last_tz_leap_check;
static NTP_Leap tz_leap;
/* ================================================== */
@@ -110,6 +126,25 @@ static double last_ref_update_interval;
/* ================================================== */
static NTP_Leap get_tz_leap(time_t when);
/* ================================================== */
static void
handle_slew(struct timeval *raw,
struct timeval *cooked,
double dfreq,
double doffset,
int is_step_change,
void *anything)
{
if (is_step_change) {
UTI_AddDoubleToTimeval(&last_ref_update, -doffset, &last_ref_update);
}
}
/* ================================================== */
void
REF_Initialise(void)
{
@@ -127,6 +162,7 @@ REF_Initialise(void)
our_frequency_ppm = 0.0;
our_skew = 1.0; /* i.e. rather bad */
our_residual_freq = 0.0;
drift_file_age = 0.0;
/* Now see if we can get the drift file opened */
drift_file = CNF_GetDriftFile();
@@ -138,6 +174,8 @@ REF_Initialise(void)
/* We have read valid data */
our_frequency_ppm = file_freq_ppm;
our_skew = 1.0e-6 * file_skew_ppm;
LOG(LOGS_INFO, LOGF_Reference, "Frequency %.3f +/- %.3f ppm read from %s", file_freq_ppm, file_skew_ppm, drift_file);
LCL_SetAbsoluteFrequency(our_frequency_ppm);
} else {
LOG(LOGS_WARN, LOGF_Reference, "Could not parse valid frequency and skew from driftfile %s",
drift_file);
@@ -147,25 +185,40 @@ REF_Initialise(void)
drift_file);
}
fclose(in);
} else {
LOG(LOGS_WARN, LOGF_Reference, "Could not open driftfile %s for reading",
drift_file);
}
drift_file_age = 0.0;
}
LCL_SetAbsoluteFrequency(our_frequency_ppm);
if (our_frequency_ppm == 0.0) {
our_frequency_ppm = LCL_ReadAbsoluteFrequency();
if (our_frequency_ppm != 0.0) {
LOG(LOGS_INFO, LOGF_Reference, "Initial frequency %.3f ppm", our_frequency_ppm);
}
}
logfileid = CNF_GetLogTracking() ? LOG_FileOpen("tracking",
" Date (UTC) Time IP Address St Freq ppm Skew ppm Offset")
" Date (UTC) Time IP Address St Freq ppm Skew ppm Offset L")
: -1;
max_update_skew = fabs(CNF_GetMaxUpdateSkew()) * 1.0e-6;
correction_time_ratio = CNF_GetCorrectionTimeRatio();
enable_local_stratum = CNF_AllowLocalReference(&local_stratum);
leap_tzname = CNF_GetLeapSecTimezone();
if (leap_tzname) {
/* Check that the timezone has good data for Jun 30 2008 and Dec 31 2008 */
if (get_tz_leap(1214784000) == LEAP_Normal &&
get_tz_leap(1230681600) == LEAP_InsertSecond) {
LOG(LOGS_INFO, LOGF_Reference, "Using %s timezone to obtain leap second data", leap_tzname);
} else {
LOG(LOGS_WARN, LOGF_Reference, "Timezone %s failed leap second check, ignoring", leap_tzname);
leap_tzname = NULL;
}
}
CNF_GetMakeStep(&make_step_limit, &make_step_threshold);
CNF_GetMaxChange(&max_offset_delay, &max_offset_ignore, &max_offset);
CNF_GetLogChange(&do_log_change, &log_change_threshold);
CNF_GetMailOnChange(&do_mail_change, &mail_change_threshold, &mail_change_user);
@@ -176,11 +229,14 @@ REF_Initialise(void)
memset(fb_drifts, 0, sizeof (struct fb_drift) * (fb_drift_max - fb_drift_min + 1));
next_fb_drift = 0;
fb_drift_timeout_id = -1;
last_ref_update.tv_sec = 0;
last_ref_update.tv_usec = 0;
last_ref_update_interval = 0;
}
last_ref_update.tv_sec = 0;
last_ref_update.tv_usec = 0;
last_ref_update_interval = 0.0;
LCL_AddParameterChangeHandler(handle_slew, NULL);
/* And just to prevent anything wierd ... */
if (do_log_change) {
log_change_threshold = fabs(log_change_threshold);
@@ -365,7 +421,7 @@ schedule_fb_drift(struct timeval *now)
UTI_DiffTimevalsToDouble(&unsynchronised, now, &last_ref_update);
for (c = 0, i = fb_drift_min; i <= fb_drift_max; i++) {
for (c = secs = 0, i = fb_drift_min; i <= fb_drift_max; i++) {
secs = 1 << i;
if (fb_drifts[i - fb_drift_min].secs < secs)
@@ -464,20 +520,109 @@ maybe_make_step()
/* ================================================== */
static void
update_leap_status(NTP_Leap leap)
static int
is_offset_ok(double offset)
{
if (max_offset_delay < 0)
return 1;
if (max_offset_delay > 0) {
max_offset_delay--;
return 1;
}
offset = fabs(offset);
if (offset > max_offset) {
LOG(LOGS_WARN, LOGF_Reference,
"Adjustment of %.3f seconds exceeds the allowed maximum of %.3f seconds (%s) ",
offset, max_offset, !max_offset_ignore ? "exiting" : "ignored");
if (!max_offset_ignore)
SCH_QuitProgram();
else if (max_offset_ignore > 0)
max_offset_ignore--;
return 0;
}
return 1;
}
/* ================================================== */
static NTP_Leap
get_tz_leap(time_t when)
{
struct tm stm;
time_t t;
char *tz_env, tz_orig[128];
/* Do this check at most twice a day */
when = when / (12 * 3600) * (12 * 3600);
if (last_tz_leap_check == when)
return tz_leap;
last_tz_leap_check = when;
tz_leap = LEAP_Normal;
stm = *gmtime(&when);
/* Check for leap second only in the latter half of June and December */
if (stm.tm_mon == 5 && stm.tm_mday > 14)
stm.tm_mday = 30;
else if (stm.tm_mon == 11 && stm.tm_mday > 14)
stm.tm_mday = 31;
else
return tz_leap;
/* Temporarily switch to the timezone containing leap seconds */
tz_env = getenv("TZ");
if (tz_env) {
if (strlen(tz_env) >= sizeof (tz_orig))
return tz_leap;
strcpy(tz_orig, tz_env);
}
setenv("TZ", leap_tzname, 1);
tzset();
/* Set the time to 23:59:60 and see how it overflows in mktime() */
stm.tm_sec = 60;
stm.tm_min = 59;
stm.tm_hour = 23;
t = mktime(&stm);
if (tz_env)
setenv("TZ", tz_orig, 1);
else
unsetenv("TZ");
tzset();
if (t == -1)
return tz_leap;
if (stm.tm_sec == 60)
tz_leap = LEAP_InsertSecond;
else if (stm.tm_sec == 1)
tz_leap = LEAP_DeleteSecond;
return tz_leap;
}
/* ================================================== */
static void
update_leap_status(NTP_Leap leap, time_t now)
{
time_t now;
struct tm stm;
int leap_sec;
leap_sec = 0;
if (leap_tzname && now && leap == LEAP_Normal)
leap = get_tz_leap(now);
if (leap == LEAP_InsertSecond || leap == LEAP_DeleteSecond) {
/* Insert/delete leap second only on June 30 or December 31
and in other months ignore the leap status completely */
now = time(NULL);
stm = *gmtime(&now);
if (stm.tm_mon != 5 && stm.tm_mon != 11) {
@@ -503,11 +648,12 @@ update_leap_status(NTP_Leap leap)
/* ================================================== */
static void
write_log(struct timeval *ref_time, char *ref, int stratum, double freq, double skew, double offset)
write_log(struct timeval *ref_time, char *ref, int stratum, NTP_Leap leap, double freq, double skew, double offset)
{
const char leap_codes[4] = {'N', '+', '-', '?'};
if (logfileid != -1) {
LOG_FileWrite(logfileid, "%s %-15s %2d %10.3f %10.3f %10.3e",
UTI_TimeToLogForm(ref_time->tv_sec), ref, stratum, freq, skew, offset);
LOG_FileWrite(logfileid, "%s %-15s %2d %10.3f %10.3f %10.3e %1c",
UTI_TimeToLogForm(ref_time->tv_sec), ref, stratum, freq, skew, offset, leap_codes[leap]);
}
}
@@ -516,10 +662,11 @@ write_log(struct timeval *ref_time, char *ref, int stratum, double freq, double
void
REF_SetReference(int stratum,
NTP_Leap leap,
unsigned long ref_id,
uint32_t ref_id,
IPAddr *ref_ip,
struct timeval *ref_time,
double offset,
double offset_sd,
double frequency,
double skew,
double root_delay,
@@ -531,11 +678,13 @@ REF_SetReference(int stratum,
double old_weight, new_weight, sum_weight;
double delta_freq1, delta_freq2;
double skew1, skew2;
double our_offset;
double our_frequency;
double abs_freq_ppm;
double update_interval;
double elapsed;
double correction_rate;
struct timeval now, raw_now;
assert(initialised);
@@ -563,6 +712,14 @@ REF_SetReference(int stratum,
}
}
LCL_ReadRawTime(&raw_now);
LCL_CookTime(&raw_now, &now, NULL);
UTI_DiffTimevalsToDouble(&elapsed, &now, ref_time);
our_offset = offset + elapsed * frequency;
if (!is_offset_ok(offset))
return;
are_we_synchronised = 1;
our_stratum = stratum + 1;
@@ -572,11 +729,34 @@ REF_SetReference(int stratum,
else
our_ref_ip.family = IPADDR_UNSPEC;
our_ref_time = *ref_time;
our_offset = offset;
our_root_delay = root_delay;
our_root_dispersion = root_dispersion;
update_leap_status(leap);
update_leap_status(leap, raw_now.tv_sec);
if (last_ref_update.tv_sec) {
UTI_DiffTimevalsToDouble(&update_interval, &now, &last_ref_update);
if (update_interval < 0.0)
update_interval = 0.0;
} else {
update_interval = 0.0;
}
last_ref_update = now;
/* We want to correct the offset quickly, but we also want to keep the
frequency error caused by the correction itself low.
Define correction rate as the area of the region bounded by the graph of
offset corrected in time. Set the rate so that the time needed to correct
an offset equal to the current sourcestats stddev will be equal to the
update interval multiplied by the correction time ratio (assuming linear
adjustment). The offset and the time needed to make the correction are
inversely proportional.
This is only a suggestion and it's up to the system driver how the
adjustment will be executed. */
correction_rate = correction_time_ratio * 0.5 * offset_sd * update_interval;
/* Eliminate updates that are based on totally unreliable frequency
information */
@@ -612,7 +792,7 @@ REF_SetReference(int stratum,
our_residual_freq = new_freq - our_frequency;
maybe_log_offset(our_offset);
LCL_AccumulateFrequencyAndOffset(our_frequency, our_offset);
LCL_AccumulateFrequencyAndOffset(our_frequency, our_offset, correction_rate);
} else {
@@ -620,7 +800,7 @@ REF_SetReference(int stratum,
LOG(LOGS_INFO, LOGF_Reference, "Skew %f too large to track, offset=%f", skew, our_offset);
#endif
maybe_log_offset(our_offset);
LCL_AccumulateOffset(our_offset);
LCL_AccumulateOffset(our_offset, correction_rate);
our_residual_freq = frequency;
}
@@ -629,15 +809,14 @@ REF_SetReference(int stratum,
abs_freq_ppm = LCL_ReadAbsoluteFrequency();
write_log(ref_time,
write_log(&now,
our_ref_ip.family != IPADDR_UNSPEC ? UTI_IPToString(&our_ref_ip) : UTI_RefidToString(our_ref_id),
our_stratum,
our_leap_status,
abs_freq_ppm,
1.0e6*our_skew,
our_offset);
UTI_DiffTimevalsToDouble(&update_interval, ref_time, &last_ref_update);
if (drift_file) {
/* Update drift file at most once per hour */
drift_file_age += update_interval;
@@ -652,8 +831,17 @@ REF_SetReference(int stratum,
update_fb_drifts(abs_freq_ppm, update_interval);
}
last_ref_update = *ref_time;
last_ref_update_interval = update_interval;
last_offset = our_offset;
/* Update the moving average of squares of offset, quickly on start */
if (avg2_moving) {
avg2_offset += 0.1 * (our_offset * our_offset - avg2_offset);
} else {
if (avg2_offset > 0.0 && avg2_offset < our_offset * our_offset)
avg2_moving = 1;
avg2_offset = our_offset * our_offset;
}
/* And now set the freq and offset to zero */
our_frequency = 0.0;
@@ -684,7 +872,7 @@ REF_SetManualReference
our_residual_freq = 0.0;
maybe_log_offset(offset);
LCL_AccumulateFrequencyAndOffset(frequency, offset);
LCL_AccumulateFrequencyAndOffset(frequency, offset, 0.0);
maybe_make_step();
abs_freq_ppm = LCL_ReadAbsoluteFrequency();
@@ -692,9 +880,10 @@ REF_SetManualReference
write_log(ref_time,
"127.127.1.1",
our_stratum,
our_leap_status,
abs_freq_ppm,
1.0e6*our_skew,
our_offset);
offset);
if (drift_file) {
update_drift_file(abs_freq_ppm, our_skew);
@@ -717,16 +906,16 @@ REF_SetUnsynchronised(void)
schedule_fb_drift(&now);
}
update_leap_status(LEAP_Unsynchronised, 0);
are_we_synchronised = 0;
write_log(&now,
"0.0.0.0",
0,
our_leap_status,
LCL_ReadAbsoluteFrequency(),
1.0e6*our_skew,
0.0);
are_we_synchronised = 0;
update_leap_status(LEAP_Unsynchronised);
}
/* ================================================== */
@@ -738,7 +927,7 @@ REF_GetReferenceParams
int *is_synchronised,
NTP_Leap *leap_status,
int *stratum,
unsigned long *ref_id,
uint32_t *ref_id,
struct timeval *ref_time,
double *root_delay,
double *root_dispersion
@@ -791,7 +980,7 @@ REF_GetReferenceParams
*leap_status = LEAP_Unsynchronised;
*stratum = 0;
*ref_id = 0UL;
*ref_id = 0;
ref_time->tv_sec = ref_time->tv_usec = 0;
/* These values seem to be standard for a client, and
any peer or client of ours will ignore them anyway because
@@ -866,6 +1055,22 @@ REF_GetTrackingReport(RPT_TrackingReport *rep)
LCL_GetOffsetCorrection(&now_raw, &correction, NULL);
UTI_AddDoubleToTimeval(&now_raw, correction, &now_cooked);
rep->ref_id = 0;
rep->ip_addr.family = IPADDR_UNSPEC;
rep->stratum = 0;
rep->leap_status = our_leap_status;
rep->ref_time.tv_sec = 0;
rep->ref_time.tv_usec = 0;
rep->current_correction = correction;
rep->freq_ppm = LCL_ReadAbsoluteFrequency();
rep->resid_freq_ppm = 0.0;
rep->skew_ppm = 0.0;
rep->root_delay = 0.0;
rep->root_dispersion = 0.0;
rep->last_update_interval = last_ref_update_interval;
rep->last_offset = last_offset;
rep->rms_offset = sqrt(avg2_offset);
if (are_we_synchronised) {
UTI_DiffTimevalsToDouble(&elapsed, &now_cooked, &our_ref_time);
@@ -875,8 +1080,6 @@ REF_GetTrackingReport(RPT_TrackingReport *rep)
rep->ip_addr = our_ref_ip;
rep->stratum = our_stratum;
rep->ref_time = our_ref_time;
rep->current_correction = correction;
rep->freq_ppm = LCL_ReadAbsoluteFrequency();
rep->resid_freq_ppm = 1.0e6 * our_residual_freq;
rep->skew_ppm = 1.0e6 * our_skew;
rep->root_delay = our_root_delay;
@@ -888,26 +1091,7 @@ REF_GetTrackingReport(RPT_TrackingReport *rep)
rep->ip_addr.family = IPADDR_UNSPEC;
rep->stratum = local_stratum;
rep->ref_time = now_cooked;
rep->current_correction = correction;
rep->freq_ppm = LCL_ReadAbsoluteFrequency();
rep->resid_freq_ppm = 0.0;
rep->skew_ppm = 0.0;
rep->root_delay = 0.0;
rep->root_dispersion = LCL_GetSysPrecisionAsQuantum();
} else {
rep->ref_id = 0UL;
rep->ip_addr.family = IPADDR_UNSPEC;
rep->stratum = 0;
rep->ref_time.tv_sec = 0;
rep->ref_time.tv_usec = 0;
rep->current_correction = correction;
rep->freq_ppm = LCL_ReadAbsoluteFrequency();
rep->resid_freq_ppm = 0.0;
rep->skew_ppm = 0.0;
rep->root_delay = 0.0;
rep->root_dispersion = 0.0;
}
}

View File

@@ -71,7 +71,7 @@ extern void REF_GetReferenceParams
int *is_synchronised,
NTP_Leap *leap,
int *stratum,
unsigned long *ref_id,
uint32_t *ref_id,
struct timeval *ref_time,
double *root_delay,
double *root_dispersion
@@ -105,10 +105,11 @@ extern void REF_SetReference
(
int stratum,
NTP_Leap leap,
unsigned long ref_id,
uint32_t ref_id,
IPAddr *ref_ip,
struct timeval *ref_time,
double offset,
double offset_sd,
double frequency,
double skew,
double root_delay,

View File

@@ -26,6 +26,8 @@
*/
#include "config.h"
#include <assert.h>
#include <math.h>
@@ -298,6 +300,10 @@ RGR_FindBestRegression
nruns = n_runs_from_residuals(resid, n - resid_start);
if (nruns > critical_runs[n - resid_start] || n - start <= MIN_SAMPLES_FOR_REGRESS) {
if (start != resid_start) {
/* Ignore extra samples in returned nruns */
nruns = n_runs_from_residuals(resid - resid_start + start, n - start);
}
break;
} else {
/* Try dropping one sample at a time until the runs test passes. */

View File

@@ -38,7 +38,9 @@ typedef struct {
int poll;
enum {RPT_NTP_CLIENT, RPT_NTP_PEER, RPT_LOCAL_REFERENCE} mode;
enum {RPT_SYNC, RPT_UNREACH, RPT_FALSETICKER, RPT_JITTERY, RPT_CANDIDATE} state;
enum {RPT_NORMAL, RPT_PREFER, RPT_NOSELECT} sel_option;
int reachability;
unsigned long latest_meas_ago; /* seconds */
double orig_latest_meas; /* seconds */
double latest_meas; /* seconds */
@@ -46,20 +48,24 @@ typedef struct {
} RPT_SourceReport ;
typedef struct {
unsigned long ref_id;
uint32_t ref_id;
IPAddr ip_addr;
unsigned long stratum;
unsigned long leap_status;
struct timeval ref_time;
double current_correction;
double last_offset;
double rms_offset;
double freq_ppm;
double resid_freq_ppm;
double skew_ppm;
double root_delay;
double root_dispersion;
double last_update_interval;
} RPT_TrackingReport;
typedef struct {
unsigned long ref_id;
uint32_t ref_id;
IPAddr ip_addr;
unsigned long n_samples;
unsigned long n_runs;
@@ -113,6 +119,7 @@ typedef struct {
int offline;
int burst_online;
int burst_offline;
int unresolved;
} RPT_ActivityReport;
#endif /* GOT_REPORTS_H */

2
rtc.c
View File

@@ -23,6 +23,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "rtc.h"

View File

@@ -3,6 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -26,6 +27,8 @@
*/
#include "config.h"
#if defined LINUX
#ifdef sparc
@@ -45,6 +48,7 @@
#include <errno.h>
#include <assert.h>
#include <string.h>
#include <linux/rtc.h>
#include "logging.h"
#include "sched.h"
@@ -54,22 +58,9 @@
#include "regress.h"
#include "rtc.h"
#include "rtc_linux.h"
#include "io_linux.h"
#include "conf.h"
#include "memory.h"
struct rtc_time {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};
/* ================================================== */
/* Forward prototypes */
@@ -244,14 +235,12 @@ run_regression(int new_sample,
{
double rtc_rel[MAX_SAMPLES]; /* Relative times on RTC axis */
double offsets[MAX_SAMPLES]; /* How much the RTC is fast of the system clock */
int i, n;
int i;
double est_intercept, est_slope;
int best_new_start;
if (n_samples > 0) {
n = n_samples - 1;
for (i=0; i<n_samples; i++) {
rtc_rel[i] = rtc_trim[i] + (double)(rtc_sec[i] - rtc_ref);
offsets[i] = ((double) (rtc_ref - system_times[i].tv_sec) -
@@ -319,6 +308,8 @@ slew_samples
dfreq, doffset,
old_seconds_fast, 1.0e6 * old_gain_rate,
coef_seconds_fast, 1.0e6 * coef_gain_rate);
#else
(void)old_seconds_fast; (void)old_gain_rate;
#endif
}
@@ -517,62 +508,6 @@ write_coefs_to_file(int valid,time_t ref_time,double offset,double rate)
int
RTC_Linux_Initialise(void)
{
int major, minor, patch;
/* Check whether we can support the real time clock.
Linux 1.2.x - haven't checked yet
Linux 1.3.x - don't know, haven't got a system to look at
Linux 2.0.x - For x<=31, using any variant of the adjtimex() call
sets the kernel into a mode where the RTC was updated every 11
minutes. The only way to escape this is to use settimeofday().
Since we need to have sole control over the RTC to be able to
measure its drift rate, and there is no 'notify' callback to warn
you that the kernel is going to do this, I can't see a way to
support this.
Linux 2.0.x - For x>=32 the adjtimex()/RTC behaviour was
modified, so that as long as the STA_UNSYNC flag is set the RTC
is left alone. This is the mode we exploit here, so that the RTC
continues to go its own sweet way, unless we make updates to it
from this module.
Linux 2.1.x - don't know, haven't got a system to look at.
Linux 2.2.x, 2.3.x and 2.4.x are believed to be OK for all
patch levels
*/
SYS_Linux_GetKernelVersion(&major, &minor, &patch);
/* Obviously this test can get more elaborate when we know about
more system types. */
if (major != 2) {
return 0;
} else {
switch (minor) {
case 0:
if (patch <= 31) {
return 0;
}
break;
case 1:
return 0;
break;
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
break; /* OK for all patch levels */
}
}
/* Setup details depending on configuration options */
setup_config();
@@ -681,6 +616,9 @@ set_rtc(time_t new_rtc_time)
rtc_raw.tm_mday = rtc_tm.tm_mday;
rtc_raw.tm_mon = rtc_tm.tm_mon;
rtc_raw.tm_year = rtc_tm.tm_year;
rtc_raw.tm_wday = rtc_tm.tm_wday;
rtc_raw.tm_yday = rtc_tm.tm_yday;
rtc_raw.tm_isdst = rtc_tm.tm_isdst;
status = ioctl(fd, RTC_SET_TIME, &rtc_raw);
if (status < 0) {
@@ -727,7 +665,7 @@ handle_initial_trim(void)
sys_error_now = rtc_error_now - coef_seconds_fast;
LOG(LOGS_INFO, LOGF_RtcLinux, "System trim from RTC = %f", sys_error_now);
LCL_AccumulateOffset(sys_error_now);
LCL_AccumulateOffset(sys_error_now, 0.0);
} else {
LOG(LOGS_WARN, LOGF_RtcLinux, "No valid file coefficients, cannot trim system time");
}
@@ -758,6 +696,7 @@ handle_relock_after_trim(void)
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not do regression after trim");
}
coefs_valid = 0;
n_samples = 0;
n_samples_since_regression = 0;
operating_mode = OM_NORMAL;
@@ -846,7 +785,7 @@ read_from_device(void *any)
return;
}
if ((data & RTC_UIE) == RTC_UIE) {
if ((data & RTC_UF) == RTC_UF) {
/* Update interrupt detected */
/* Read RTC time, sandwiched between two polls of the system clock
@@ -997,7 +936,7 @@ RTC_Linux_TimePreInit(void)
time_t rtc_t, estimated_correct_rtc_t;
long interval;
double accumulated_error = 0.0;
struct timeval new_sys_time;
struct timeval new_sys_time, old_sys_time;
coefs_file_name = CNF_GetRtcFile();
@@ -1032,8 +971,6 @@ RTC_Linux_TimePreInit(void)
accumulated_error = file_ref_offset + (double)(interval) * 1.0e-6 * file_rate_ppm;
/* Correct time */
LOG(LOGS_INFO, LOGF_RtcLinux, "Set system time, error in RTC = %f",
accumulated_error);
estimated_correct_rtc_t = rtc_t - (long)(0.5 + accumulated_error);
} else {
estimated_correct_rtc_t = rtc_t - (long)(0.5 + accumulated_error);
@@ -1042,9 +979,18 @@ RTC_Linux_TimePreInit(void)
new_sys_time.tv_sec = estimated_correct_rtc_t;
new_sys_time.tv_usec = 0;
/* Tough luck if this fails */
if (settimeofday(&new_sys_time, NULL) < 0) {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not settimeofday");
/* 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)) {
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");
}
}
} else {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not convert RTC reading to seconds since 1/1/1970");
@@ -1107,6 +1053,11 @@ RTC_Linux_Trim(void)
n_samples = 0;
operating_mode = OM_AFTERTRIM;
/* Estimate the offset in case writertc is called or chronyd
is terminated during rapid sampling */
coef_seconds_fast = -now.tv_usec / 1e6 + 0.5;
coef_ref_time = now.tv_sec;
/* And start rapid sampling, interrupts on now */
if (timeout_running) {
SCH_RemoveTimeout(timeout_id);

105
sched.c
View File

@@ -26,6 +26,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "sched.h"
@@ -68,9 +70,9 @@ typedef struct {
static FileHandlerEntry file_handlers[FD_SET_SIZE];
/* Last timestamp when a file descriptor became readable */
static struct timeval last_fdready;
static double last_fdready_err;
/* Timestamp when last select() returned */
static struct timeval last_select_ts, last_select_ts_raw;
static double last_select_ts_err;
/* ================================================== */
@@ -227,9 +229,9 @@ SCH_RemoveInputFileHandler(int fd)
void
SCH_GetFileReadyTime(struct timeval *tv, double *err)
{
*tv = last_fdready;
*tv = last_select_ts;
if (err)
*err = last_fdready_err;
*err = last_select_ts_err;
}
/* ================================================== */
@@ -316,6 +318,7 @@ SCH_AddTimeoutByDelay(double delay, SCH_TimeoutHandler handler, SCH_ArbitraryArg
struct timeval now, then;
assert(initialised);
assert(delay >= 0.0);
LCL_ReadRawTime(&now);
UTI_AddDoubleToTimeval(&now, delay, &then);
@@ -337,6 +340,7 @@ SCH_AddTimeoutInClass(double min_delay, double separation, double randomness,
double new_min_delay;
assert(initialised);
assert(min_delay >= 0.0);
assert(class < SCH_NumberOfClasses);
if (randomness > 0.0) {
@@ -426,18 +430,26 @@ SCH_RemoveTimeout(SCH_TimeoutID id)
}
/* ================================================== */
/* The current time (now) has to be passed in from the
caller to avoid race conditions */
/* Try to dispatch any timeouts that have already gone by, and
keep going until all are done. (The earlier ones may take so
long to do that the later ones come around by the time they are
completed). */
static int
static void
dispatch_timeouts(struct timeval *now) {
TimerQueueEntry *ptr;
SCH_TimeoutHandler handler;
SCH_ArbitraryArgument arg;
int n_done = 0;
int n_done = 0, n_entries_on_start = n_timer_queue_entries;
while (1) {
LCL_ReadRawTime(now);
if (!(n_timer_queue_entries > 0 &&
UTI_CompareTimevals(now, &(timer_queue.next->tv)) >= 0)) {
break;
}
if ((n_timer_queue_entries > 0) &&
(UTI_CompareTimevals(now, &(timer_queue.next->tv)) >= 0)) {
ptr = timer_queue.next;
last_class_dispatch[ptr->class] = *now;
@@ -452,10 +464,17 @@ dispatch_timeouts(struct timeval *now) {
/* Increment count of timeouts handled */
++n_done;
/* If more timeouts were handled than there were in the timer queue on
start and there are now, assume some code is scheduling timeouts with
negative delays and abort. Make the actual limit higher in case the
machine is temporarily overloaded and dispatching the handlers takes
more time than was delay of a scheduled timeout. */
if (n_done > n_timer_queue_entries * 4 &&
n_done > n_entries_on_start * 4) {
LOG_FATAL(LOGF_Scheduler, "Possible infinite loop in scheduling");
}
}
return n_done;
}
/* ================================================== */
@@ -507,18 +526,50 @@ handle_slew(struct timeval *raw,
for (i = 0; i < SCH_NumberOfClasses; i++) {
UTI_AddDoubleToTimeval(&last_class_dispatch[i], -doffset, &last_class_dispatch[i]);
}
UTI_AddDoubleToTimeval(&last_select_ts_raw, -doffset, &last_select_ts_raw);
UTI_AddDoubleToTimeval(&last_select_ts, -doffset, &last_select_ts);
}
}
/* ================================================== */
/* Try to handle unexpected backward time jump */
static void
recover_backjump(struct timeval *raw, struct timeval *cooked, int timeout)
{
double diff, err;
UTI_DiffTimevalsToDouble(&diff, &last_select_ts_raw, raw);
if (n_timer_queue_entries > 0) {
UTI_DiffTimevalsToDouble(&err, &(timer_queue.next->tv), &last_select_ts_raw);
} else {
err = 0.0;
}
diff += err;
if (timeout) {
err = 1.0;
}
LOG(LOGS_WARN, LOGF_Scheduler, "Backward time jump detected! (correction %.1f +- %.1f seconds)", diff, err);
LCL_NotifyExternalTimeStep(raw, cooked, diff, err);
}
/* ================================================== */
void
SCH_MainLoop(void)
{
fd_set rd;
int status;
struct timeval tv, *ptv;
struct timeval now;
struct timeval now, cooked;
double err;
assert(initialised);
@@ -527,20 +578,15 @@ SCH_MainLoop(void)
/* Copy current set of read file descriptors */
memcpy((void *) &rd, (void *) &read_fds, sizeof(fd_set));
/* Try to dispatch any timeouts that have already gone by, and
keep going until all are done. (The earlier ones may take so
long to do that the later ones come around by the time they are
completed). */
do {
LCL_ReadRawTime(&now);
} while (dispatch_timeouts(&now) > 0);
/* Dispatch timeouts and fill now with current raw time */
dispatch_timeouts(&now);
/* Check whether there is a timeout and set it up */
if (n_timer_queue_entries > 0) {
UTI_DiffTimevals(&tv, &(timer_queue.next->tv), &now);
ptv = &tv;
assert(tv.tv_sec > 0 || tv.tv_usec > 0);
} else {
ptv = NULL;
@@ -555,12 +601,23 @@ SCH_MainLoop(void)
status = select(one_highest_fd, &rd, NULL, NULL, ptv);
LCL_ReadRawTime(&now);
LCL_CookTime(&now, &cooked, &err);
/* Check if time didn't jump backwards */
if (last_select_ts_raw.tv_sec > now.tv_sec + 1) {
recover_backjump(&now, &cooked, status == 0);
}
last_select_ts_raw = now;
last_select_ts = cooked;
last_select_ts_err = err;
if (status < 0) {
assert(need_to_exit);
} else if (status > 0) {
/* A file descriptor is ready to read */
LCL_ReadCookedTime(&last_fdready, &last_fdready_err);
dispatch_filehandlers(status, &rd);
} else {

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011
* Copyright (C) Miroslav Lichvar 2011-2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -28,6 +28,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "sources.h"
@@ -82,8 +84,8 @@ struct SRC_Instance_Record {
SST_Stats stats;
NTP_Leap leap_status; /* Leap status */
int index; /* Index back into the array of source */
unsigned long ref_id; /* The reference ID of this source
(i.e. its IP address, NOT the
uint32_t ref_id; /* The reference ID of this source
(i.e. from its IP address, NOT the
reference _it_ is sync'd to) */
IPAddr *ip_addr; /* Its IP address if NTP source */
@@ -181,7 +183,7 @@ void SRC_Finalise(void)
/* Function to create a new instance. This would be called by one of
the individual source-type instance creation routines. */
SRC_Instance SRC_CreateNewInstance(unsigned long ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr)
SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr)
{
SRC_Instance result;
@@ -368,8 +370,12 @@ SRC_UpdateReachability(SRC_Instance inst, int reachable)
void
SRC_ResetReachability(SRC_Instance inst)
{
/* This should be disabled until source selection is modified to keep
a peer selected even when not reachable */
#if 0
inst->reachability = 0;
SRC_UpdateReachability(inst, 0);
#endif
}
/* ================================================== */
@@ -414,15 +420,15 @@ source_to_string(SRC_Instance inst)
of sources we are holding.
Updates are only made to the local reference if a new source is selected
or match_addr is equal to the selected reference source address */
or match_refid is equal to the selected reference source refid */
void
SRC_SelectSource(unsigned long match_addr)
SRC_SelectSource(uint32_t match_refid)
{
int i, j, index, old_selected_index;
struct timeval now;
struct timeval now, ref_time;
double src_offset, src_offset_sd, src_frequency, src_skew;
double src_accrued_dispersion;
double src_root_delay, src_root_dispersion;
int n_endpoints, j1, j2;
double best_lo, best_hi;
int depth, best_depth;
@@ -430,7 +436,6 @@ SRC_SelectSource(unsigned long match_addr)
double distance, sel_src_distance;
int stratum, min_stratum;
struct SelectInfo *si;
double total_root_dispersion;
int n_badstats_sources;
int max_sel_reach, max_badstat_reach;
int max_score_index;
@@ -778,8 +783,8 @@ SRC_SelectSource(unsigned long match_addr)
/* Update score, but only for source pairs where one source
has a new sample */
if (sources[i]->ref_id == match_addr ||
sources[selected_source_index]->ref_id == match_addr) {
if (sources[i]->ref_id == match_refid ||
sources[selected_source_index]->ref_id == match_refid) {
sources[i]->sel_score *= sel_src_distance / distance;
@@ -798,7 +803,7 @@ SRC_SelectSource(unsigned long match_addr)
#if 0
LOG(LOGS_INFO, LOGF_Sources, "select score=%f refid=%lx match_refid=%lx status=%d dist=%f",
sources[i]->sel_score, sources[i]->ref_id, match_addr, sources[i]->status, distance);
sources[i]->sel_score, sources[i]->ref_id, match_refid, sources[i]->status, distance);
#endif
if (max_score < sources[i]->sel_score) {
@@ -835,32 +840,28 @@ SRC_SelectSource(unsigned long match_addr)
sources[selected_source_index]->status = SRC_SYNC;
/* Update local reference only when a new source was selected or a new
sample was received (i.e. match_addr is equal to selected ref_id) */
sample was received (i.e. match_refid is equal to selected refid) */
if (selected_source_index != old_selected_index ||
match_addr == sources[selected_source_index]->ref_id) {
match_refid == sources[selected_source_index]->ref_id) {
/* Now just use the statistics of the selected source for
trimming the local clock */
LCL_ReadCookedTime(&now, NULL);
SST_GetTrackingData(sources[selected_source_index]->stats, &now,
SST_GetTrackingData(sources[selected_source_index]->stats, &ref_time,
&src_offset, &src_offset_sd,
&src_accrued_dispersion,
&src_frequency, &src_skew);
total_root_dispersion = (src_accrued_dispersion +
sources[selected_source_index]->sel_info.root_dispersion);
&src_frequency, &src_skew,
&src_root_delay, &src_root_dispersion);
REF_SetReference(min_stratum, leap_status,
sources[selected_source_index]->ref_id,
sources[selected_source_index]->ip_addr,
&now,
&ref_time,
src_offset,
src_offset_sd,
src_frequency,
src_skew,
sources[selected_source_index]->sel_info.root_delay,
total_root_dispersion);
src_root_delay,
src_root_dispersion);
}
} else {
@@ -897,6 +898,17 @@ SRC_ReselectSource(void)
/* ================================================== */
void
SRC_SetReselectDistance(double distance)
{
if (reselect_distance != distance) {
reselect_distance = distance;
LOG(LOGS_INFO, LOGF_Sources, "New reselect distance %f", distance);
}
}
/* ================================================== */
double
SRC_PredictOffset(SRC_Instance inst, struct timeval *when)
{
@@ -1083,6 +1095,7 @@ SRC_ReportSource(int index, RPT_SourceReport *report, struct timeval *now)
case SRC_JITTERY:
report->state = RPT_JITTERY;
break;
case SRC_OK:
case SRC_BAD_STATS:
case SRC_UNREACHABLE:
report->state = RPT_UNREACH;
@@ -1097,6 +1110,23 @@ SRC_ReportSource(int index, RPT_SourceReport *report, struct timeval *now)
assert(0);
break;
}
switch (src->sel_option) {
case SRC_SelectNormal:
report->sel_option = RPT_NOSELECT;
break;
case SRC_SelectPrefer:
report->sel_option = RPT_PREFER;
break;
case SRC_SelectNoselect:
report->sel_option = RPT_NOSELECT;
break;
default:
assert(0);
}
report->reachability = src->reachability;
/* Call stats module to fill out estimates */
SST_DoSourceReport(src->stats, report, now);

View File

@@ -61,7 +61,7 @@ typedef enum {
/* Function to create a new instance. This would be called by one of
the individual source-type instance creation routines. */
extern SRC_Instance SRC_CreateNewInstance(unsigned long ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr);
extern SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr);
/* Function to get rid of a source when it is being unconfigured.
This may cause the current reference source to be reselected, if this
@@ -135,11 +135,14 @@ extern void SRC_ResetReachability(SRC_Instance inst);
reference source address. (This avoids updating the frequency
tracking for every sample from other sources - only the ones from
the selected reference make a difference) */
extern void SRC_SelectSource(unsigned long match_addr);
extern void SRC_SelectSource(uint32_t match_refid);
/* Force reselecting the best source */
extern void SRC_ReselectSource(void);
/* Set reselect distance */
extern void SRC_SetReselectDistance(double distance);
/* Predict the offset of the local clock relative to a given source at
a given local cooked time. Positive indicates local clock is FAST
relative to reference. */

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011
* Copyright (C) Miroslav Lichvar 2011-2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -26,6 +26,8 @@
analysis on the samples obtained from the sources,
to determined frequencies and error bounds. */
#include "config.h"
#include "sysincl.h"
#include "sourcestats.h"
@@ -56,7 +58,7 @@ static LOG_FileID logfileid;
struct SST_Stats_Record {
/* Reference ID and IP address of source, used for logging to statistics log */
unsigned long refid;
uint32_t refid;
IPAddr *ip_addr;
/* Number of samples currently stored. The samples are stored in circular
@@ -171,7 +173,7 @@ SST_Finalise(void)
/* This function creates a new instance of the statistics handler */
SST_Stats
SST_CreateInstance(unsigned long refid, IPAddr *addr)
SST_CreateInstance(uint32_t refid, IPAddr *addr)
{
SST_Stats inst;
inst = MallocNew(struct SST_Stats_Record);
@@ -237,10 +239,19 @@ SST_AccumulateSample(SST_Stats inst, struct timeval *sample_time,
{
int n, m;
/* Make room for the new sample */
if (inst->n_samples == MAX_SAMPLES) {
prune_register(inst, 1);
}
/* Make sure it's newer than the last sample */
if (inst->n_samples &&
UTI_CompareTimevals(&inst->sample_times[inst->last_sample], sample_time) >= 0) {
LOG(LOGS_WARN, LOGF_SourceStats, "Out of order sample detected, discarding history for %s",
inst->ip_addr ? UTI_IPToString(inst->ip_addr) : UTI_RefidToString(inst->refid));
prune_register(inst, inst->n_samples);
}
n = inst->last_sample = (inst->last_sample + 1) %
(MAX_SAMPLES * REGRESS_RUNS_RATIO);
m = n % MAX_SAMPLES;
@@ -384,7 +395,7 @@ SST_DoNewRegression(SST_Stats inst)
int best_start, times_back_start;
double est_intercept, est_slope, est_var, est_intercept_sd, est_slope_sd;
int i, j, nruns;
double min_distance;
double min_distance, mean_distance;
double sd_weight, sd;
double old_skew, old_freq, stress;
@@ -395,17 +406,19 @@ SST_DoNewRegression(SST_Stats inst)
offsets[i + inst->runs_samples] = inst->offsets[get_runsbuf_index(inst, i)];
}
for (i = 0, min_distance = DBL_MAX; i < inst->n_samples; i++) {
for (i = 0, mean_distance = 0.0, min_distance = DBL_MAX; i < inst->n_samples; i++) {
j = get_buf_index(inst, i);
peer_distances[i] = 0.5 * inst->peer_delays[j] + inst->peer_dispersions[j];
mean_distance += peer_distances[i];
if (peer_distances[i] < min_distance) {
min_distance = peer_distances[i];
}
}
mean_distance /= inst->n_samples;
/* And now, work out the weight vector */
sd = sqrt(inst->variance);
sd = mean_distance - min_distance;
if (sd > min_distance || sd <= 0.0)
sd = min_distance;
@@ -524,6 +537,14 @@ SST_GetFrequencyRange(SST_Stats inst,
skew = inst->skew;
*lo = freq - skew;
*hi = freq + skew;
/* This function is currently used only to determine the values of delta
and epsilon in the ntp_core module. Limit the skew to a reasonable maximum
to avoid failing the dispersion test too easily. */
if (skew > WORST_CASE_FREQ_BOUND) {
*lo = -WORST_CASE_FREQ_BOUND;
*hi = WORST_CASE_FREQ_BOUND;
}
}
/* ================================================== */
@@ -572,6 +593,8 @@ SST_GetSelectionData(SST_Stats inst, struct timeval *now,
LOG(LOGS_INFO, LOGF_SourceStats, "n=%d off=%f del=%f dis=%f var=%f pdist=%f avoff=%f avok=%d selok=%d",
inst->n_samples, *best_offset, *best_root_delay, *best_root_dispersion, *variance,
peer_distance, average_offset, average_ok, *select_ok);
#else
(void)average_ok;
#endif
return;
@@ -580,32 +603,30 @@ SST_GetSelectionData(SST_Stats inst, struct timeval *now,
/* ================================================== */
void
SST_GetTrackingData(SST_Stats inst, struct timeval *now,
SST_GetTrackingData(SST_Stats inst, struct timeval *ref_time,
double *average_offset, double *offset_sd,
double *accrued_dispersion,
double *frequency, double *skew)
double *frequency, double *skew,
double *root_delay, double *root_dispersion)
{
int i, j;
double peer_distance;
double elapsed_offset, elapsed_sample;
double elapsed_sample;
i = get_runsbuf_index(inst, inst->best_single_sample);
j = get_buf_index(inst, inst->best_single_sample);
*ref_time = inst->offset_time;
*average_offset = inst->estimated_offset;
*offset_sd = inst->estimated_offset_sd;
*frequency = inst->estimated_frequency;
*skew = inst->skew;
*root_delay = inst->root_delays[j];
peer_distance = inst->peer_dispersions[j] + 0.5 * inst->peer_delays[j];
UTI_DiffTimevalsToDouble(&elapsed_offset, now, &(inst->offset_time));
*average_offset = inst->estimated_offset + inst->estimated_frequency * elapsed_offset;
*offset_sd = inst->estimated_offset_sd + elapsed_offset * inst->skew;
UTI_DiffTimevalsToDouble(&elapsed_sample, now, &inst->sample_times[i]);
*accrued_dispersion = inst->skew * elapsed_sample;
UTI_DiffTimevalsToDouble(&elapsed_sample, &inst->offset_time, &inst->sample_times[i]);
*root_dispersion = inst->root_dispersions[j] + inst->skew * elapsed_sample;
#ifdef TRACEON
LOG(LOGS_INFO, LOGF_SourceStats, "n=%d freq=%f (%.3fppm) skew=%f (%.3fppm) pdist=%f avoff=%f offsd=%f accrdis=%f",
inst->n_samples, *frequency, 1.0e6* *frequency, *skew, 1.0e6* *skew, peer_distance, *average_offset, *offset_sd, *accrued_dispersion);
LOG(LOGS_INFO, LOGF_SourceStats, "n=%d freq=%f (%.3fppm) skew=%f (%.3fppm) avoff=%f offsd=%f disp=%f",
inst->n_samples, *frequency, 1.0e6* *frequency, *skew, 1.0e6* *skew, *average_offset, *offset_sd, *root_dispersion);
#endif
}
@@ -620,6 +641,9 @@ SST_SlewSamples(SST_Stats inst, struct timeval *when, double dfreq, double doffs
struct timeval *sample, prev;
double prev_offset, prev_freq;
if (!inst->n_samples)
return;
for (m = -inst->runs_samples; m < inst->n_samples; m++) {
i = get_runsbuf_index(inst, m);
sample = &(inst->sample_times[i]);
@@ -631,6 +655,8 @@ SST_SlewSamples(SST_Stats inst, struct timeval *when, double dfreq, double doffs
LOG(LOGS_INFO, LOGF_SourceStats, "i=%d old_st=[%s] new_st=[%s] old_off=%f new_off=%f",
i, UTI_TimevalToString(&prev), UTI_TimevalToString(sample),
prev_offset, inst->offsets[i]);
#else
(void)prev_offset;
#endif
}
@@ -648,6 +674,8 @@ SST_SlewSamples(SST_Stats inst, struct timeval *when, double dfreq, double doffs
UTI_TimevalToString(&prev), UTI_TimevalToString(&(inst->offset_time)),
prev_offset, inst->estimated_offset,
1.0e6*prev_freq, 1.0e6*inst->estimated_frequency);
#else
(void)prev; (void)prev_freq;
#endif
return;

View File

@@ -38,7 +38,7 @@ extern void SST_Initialise(void);
extern void SST_Finalise(void);
/* This function creates a new instance of the statistics handler */
extern SST_Stats SST_CreateInstance(unsigned long refid, IPAddr *addr);
extern SST_Stats SST_CreateInstance(uint32_t refid, IPAddr *addr);
/* This function deletes an instance of the statistics handler. */
extern void SST_DeleteInstance(SST_Stats inst);
@@ -89,10 +89,10 @@ SST_GetSelectionData(SST_Stats inst, struct timeval *now,
/* Get data needed when setting up tracking on this source */
extern void
SST_GetTrackingData(SST_Stats inst, struct timeval *now,
SST_GetTrackingData(SST_Stats inst, struct timeval *ref_time,
double *average_offset, double *offset_sd,
double *accrued_dispersion,
double *frequency, double *skew);
double *frequency, double *skew,
double *root_delay, double *root_dispersion);
/* Get parameters for using this source as the reference */
extern void

View File

@@ -50,7 +50,7 @@ typedef struct {
#define SRC_DEFAULT_MAXPOLL 10
#define SRC_DEFAULT_PRESEND_MINPOLL 0
#define SRC_DEFAULT_MAXDELAY 16.0
#define SRC_DEFAULT_MAXDELAYRATIO 16384.0
#define SRC_DEFAULT_MAXDELAYRATIO 0.0
#define SRC_DEFAULT_MAXDELAYDEVRATIO 10.0
#define SRC_DEFAULT_MINSTRATUM 0
#define SRC_DEFAULT_POLLTARGET 6

View File

@@ -24,6 +24,8 @@
Replacement strerror function for systems that don't have it
*/
#include "config.h"
#ifdef SUNOS
#include <errno.h>

2
sys.c
View File

@@ -25,6 +25,8 @@
in the various operating-system specific modules
*/
#include "config.h"
#include "sys.h"
#include "logging.h"

View File

@@ -4,7 +4,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) John G. Hasler 2009
* Copyright (C) Miroslav Lichvar 2009-2011
* Copyright (C) Miroslav Lichvar 2009-2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -27,6 +27,8 @@
*/
#include "config.h"
#ifdef LINUX
#include <sys/time.h>
@@ -104,8 +106,7 @@ static int version_patchlevel;
/* Flag indicating whether adjtimex() returns the remaining time adjustment
or not. If not we have to read the outstanding adjustment by setting it to
zero, examining the return value and setting the outstanding adjustment back
again. If 1, txc.modes equal to zero is used to read the time. If 2,
txc.modes is set to ADJ_OFFSET_SS_READ. */
again. */
static int have_readonly_adjtime;
@@ -114,6 +115,9 @@ static int have_readonly_adjtime;
adjustments. */
static int have_nanopll;
/* Flag indicating whether adjtimex() can step the clock */
static int have_setoffset;
/* ================================================== */
static void handle_end_of_slew(void *anything);
@@ -170,6 +174,9 @@ static SCH_TimeoutID slew_timeout_id;
a fast slew */
static double delta_total_tick;
/* Maximum length of one fast slew */
#define MAX_FASTSLEW_TIMEOUT (3600 * 24 * 7)
/* Max amount of time that we wish to slew by using adjtime (or its
equivalent). If more than this is outstanding, we alter the value
of tick instead, for a set period. Set this according to the
@@ -178,7 +185,7 @@ static double delta_total_tick;
#define MAX_ADJUST_WITH_ADJTIME (0.2)
/* Max amount of time that should be adjusted by kernel PLL */
#define MAX_ADJUST_WITH_NANOPLL (1.0e-5)
#define MAX_ADJUST_WITH_NANOPLL (0.5)
/* The amount by which we alter 'tick' when doing a large slew */
static int slew_delta_tick;
@@ -205,6 +212,18 @@ static double fast_slew_error;
/* The rate at which frequency and tick values are updated in kernel. */
static int tick_update_hz;
#define MIN_PLL_TIME_CONSTANT 0
#define MAX_PLL_TIME_CONSTANT 10
/* PLL time constant used when adjusting offset by PLL */
static long pll_time_constant;
/* Suggested offset correction rate (correction time * offset) */
static double correction_rate;
/* Kernel time constant shift */
static int shift_pll;
/* ================================================== */
/* These routines are used to estimate maximum error in offset correction */
@@ -265,9 +284,8 @@ update_nano_slew_error(long offset, int new)
if (offset == 0 && nano_slew_error == 0)
return;
/* maximum error in offset reported by adjtimex, assuming PLL constant 0
and SHIFT_PLL = 2 */
offset /= new ? 4 : 3;
/* maximum error in offset reported by adjtimex */
offset /= (1 << (shift_pll + pll_time_constant)) - (new ? 0 : 1);
if (offset < 0)
offset = -offset;
@@ -336,6 +354,27 @@ get_fast_slew_error(struct timeval *now)
return left > 0.0 ? fast_slew_error : 0.0;
}
/* ================================================== */
/* Select PLL time constant according to the suggested correction rate. */
static long
get_pll_constant(double offset)
{
long c;
double corr_time;
if (offset < 1e-9)
return MIN_PLL_TIME_CONSTANT;
corr_time = correction_rate / offset;
for (c = MIN_PLL_TIME_CONSTANT; c < MAX_PLL_TIME_CONSTANT; c++)
if (corr_time < 1 << (c + 1 + shift_pll))
break;
return c;
}
/* ================================================== */
/* This routine stops a fast slew, determines how long the slew has
been running for, and consequently how much adjustment has actually
@@ -380,7 +419,8 @@ stop_fast_slew(void)
}
/* ================================================== */
/* This routine reschedules fast slew timeout after frequency was changed */
/* This routine reschedules fast slew timeout according
to the current frequency and offset */
static void
adjust_fast_slew(double old_tick, double old_delta_tick)
@@ -401,8 +441,8 @@ adjust_fast_slew(double old_tick, double old_delta_tick)
dseconds = -offset_register * (current_total_tick + delta_total_tick) / delta_total_tick;
if (dseconds > 3600 * 24 * 7)
dseconds = 3600 * 24 * 7;
if (dseconds > MAX_FASTSLEW_TIMEOUT)
dseconds = MAX_FASTSLEW_TIMEOUT;
UTI_AddDoubleToTimeval(&tv, dseconds, &end_of_slew);
slew_start_tv = tv;
@@ -449,7 +489,7 @@ initiate_slew(void)
update_nano_slew_error(offset, 0);
offset = 0;
if (TMX_ApplyPLLOffset(offset) < 0) {
if (TMX_ApplyPLLOffset(offset, MIN_PLL_TIME_CONSTANT) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
nano_slewing = 0;
@@ -457,13 +497,23 @@ initiate_slew(void)
}
if (have_nanopll && fabs(offset_register) < MAX_ADJUST_WITH_NANOPLL) {
/* Use PLL with fixed frequency to do the shift */
/* Use the PLL with fixed frequency to do the shift. Until the kernel has a
support for linear offset adjustments with programmable rate this is the
best we can do. */
offset = 1.0e9 * -offset_register;
if (TMX_ApplyPLLOffset(offset) < 0) {
/* First adjustment after accrue_offset() sets the PLL time constant */
if (pll_time_constant < 0) {
pll_time_constant = get_pll_constant(fabs(offset_register));
}
assert(pll_time_constant >= MIN_PLL_TIME_CONSTANT &&
pll_time_constant <= MAX_PLL_TIME_CONSTANT);
if (TMX_ApplyPLLOffset(offset, pll_time_constant) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
offset_register = 0.0;
offset_register = 0.0; /* Don't keep the sub-nanosecond leftover */
nano_slewing = 1;
update_nano_slew_error(offset, 1);
} else if (fabs(offset_register) < MAX_ADJUST_WITH_ADJTIME) {
@@ -493,14 +543,22 @@ initiate_slew(void)
max_allowed_tick = nominal_tick + max_tick_bias;
if (offset_register > 0) {
if (current_tick <= min_allowed_tick) {
return;
}
slewing_tick = current_tick - slew_delta_tick;
if (slewing_tick <= min_allowed_tick) {
slewing_tick = min_allowed_tick + 1;
if (slewing_tick < min_allowed_tick) {
slewing_tick = min_allowed_tick;
}
} else {
if (current_tick >= max_allowed_tick) {
return;
}
slewing_tick = current_tick + slew_delta_tick;
if (slewing_tick >= max_allowed_tick) {
slewing_tick = max_allowed_tick - 1;
if (slewing_tick > max_allowed_tick) {
slewing_tick = max_allowed_tick;
}
}
@@ -509,6 +567,8 @@ initiate_slew(void)
delta_total_tick = (double) tick_adjust / 1.0e6;
dseconds = - offset_register * (current_total_tick + delta_total_tick) / delta_total_tick;
assert(dseconds > 0.0);
/* Now set the thing off */
if (gettimeofday(&T0, NULL) < 0) {
LOG_FATAL(LOGF_SysLinux, "gettimeofday() failed");
@@ -528,9 +588,8 @@ initiate_slew(void)
fast_slewing = 1;
slew_start_tv = T0;
/* Set up timeout for end of slew, limit to one week */
if (dseconds > 3600 * 24 * 7)
dseconds = 3600 * 24 * 7;
if (dseconds > MAX_FASTSLEW_TIMEOUT)
dseconds = MAX_FASTSLEW_TIMEOUT;
UTI_AddDoubleToTimeval(&T0, dseconds, &end_of_slew);
slew_timeout_id = SCH_AddTimeout(&end_of_slew, handle_end_of_slew, NULL);
@@ -576,16 +635,21 @@ abort_slew(void)
time) */
static void
accrue_offset(double offset)
accrue_offset(double offset, double corr_rate)
{
/* Add the new offset to the register */
offset_register += offset;
correction_rate = corr_rate;
/* Select a new time constant on the next adjustment */
pll_time_constant = -1;
if (!fast_slewing) {
initiate_slew();
} /* Otherwise, when the fast slew completes, any other stuff
in the offset register will be applied */
} else {
adjust_fast_slew(current_total_tick, delta_total_tick);
}
}
/* ================================================== */
@@ -601,23 +665,29 @@ apply_step_offset(double offset)
abort_slew();
}
if (gettimeofday(&old_time, NULL) < 0) {
LOG_FATAL(LOGF_SysLinux, "gettimeofday() failed");
if (have_setoffset) {
if (TMX_ApplyStepOffset(-offset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
} else {
if (gettimeofday(&old_time, NULL) < 0) {
LOG_FATAL(LOGF_SysLinux, "gettimeofday() failed");
}
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
if (settimeofday(&new_time, NULL) < 0) {
LOG_FATAL(LOGF_SysLinux, "settimeofday() failed");
}
if (gettimeofday(&old_time, NULL) < 0) {
LOG_FATAL(LOGF_SysLinux, "gettimeofday() failed");
}
UTI_DiffTimevalsToDouble(&err, &old_time, &new_time);
lcl_InvokeDispersionNotifyHandlers(fabs(err));
}
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
if (settimeofday(&new_time, NULL) < 0) {
LOG_FATAL(LOGF_SysLinux, "settimeofday() failed");
}
if (gettimeofday(&old_time, NULL) < 0) {
LOG_FATAL(LOGF_SysLinux, "gettimeofday() failed");
}
UTI_DiffTimevalsToDouble(&err, &old_time, &new_time);
lcl_InvokeDispersionNotifyHandlers(fabs(err));
initiate_slew();
}
@@ -638,32 +708,14 @@ set_frequency(double freq_ppm)
double scaled_freq; /* what adjtimex & the kernel use */
double old_total_tick;
int required_delta_tick;
int neg; /* True if estimate is that local clock runs slow,
i.e. positive frequency correction required */
if (freq_ppm < 0.0) {
neg = 1;
freq_ppm = -freq_ppm;
} else {
neg = 0;
}
required_delta_tick = our_round(freq_ppm / dhz);
required_freq = freq_ppm - dhz * (double) required_delta_tick;
required_freq = -(freq_ppm - dhz * required_delta_tick);
required_tick = nominal_tick - required_delta_tick;
scaled_freq = freq_scale * required_freq;
if (neg) {
/* Uncompensated local clock runs slow */
required_tick = nominal_tick + required_delta_tick;
scaled_freq = freq_scale * required_freq;
} else {
/* Uncompensated local clock runs fast */
required_tick = nominal_tick - required_delta_tick;
scaled_freq = -freq_scale * required_freq;
}
min_allowed_tick = nominal_tick - max_tick_bias + 5;
max_allowed_tick = nominal_tick + max_tick_bias - 5;
min_allowed_tick = nominal_tick - max_tick_bias;
max_allowed_tick = nominal_tick + max_tick_bias;
if (required_tick < min_allowed_tick || required_tick > max_allowed_tick) {
LOG(LOGS_WARN, LOGF_SysLinux, "Required tick %ld outside allowed range (%ld .. %ld)", required_tick, min_allowed_tick, max_allowed_tick);
@@ -709,15 +761,17 @@ read_frequency(void)
double tick_term;
double unscaled_freq;
double freq_term;
long tick;
if (TMX_GetFrequency(&unscaled_freq) < 0) {
if (TMX_GetFrequency(&unscaled_freq, &tick) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
/* Use current_tick here rather than txc.tick, otherwise we're
thrown off course when doing a fast slew (in which case, txc.tick
is nowhere near the nominal value) */
tick_term = dhz * (double)(nominal_tick - current_tick);
if (fast_slewing) {
tick -= slewing_tick - current_tick;
}
tick_term = dhz * (double)(nominal_tick - tick);
freq_term = unscaled_freq / freq_scale;
#if 0
@@ -754,29 +808,19 @@ get_offset_correction(struct timeval *raw,
if (!slow_slewing) {
offset = 0;
} else {
switch (have_readonly_adjtime) {
case 2:
if (TMX_GetOffsetLeft(&offset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
break;
case 0:
toffset = 0;
if (TMX_ApplyOffset(&toffset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
offset = toffset;
if (TMX_ApplyOffset(&toffset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
break;
case 1:
if (TMX_GetOffsetLeftOld(&offset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
break;
default:
assert(0);
if (have_readonly_adjtime) {
if (TMX_GetOffsetLeft(&offset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
} else {
toffset = 0;
if (TMX_ApplyOffset(&toffset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
offset = toffset;
if (TMX_ApplyOffset(&toffset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
}
if (offset == 0) {
@@ -869,6 +913,43 @@ guess_hz_and_shift_hz(int tick, int *hz, int *shift_hz)
return;
}
/* ================================================== */
static int
get_hz_and_shift_hz(int *hz, int *shift_hz)
{
#ifdef _SC_CLK_TCK
if ((*hz = sysconf(_SC_CLK_TCK)) < 1) {
return 0;
}
if (*hz == 100) {
*shift_hz = 7;
return 1;
}
for (*shift_hz = 1; (*hz >> *shift_hz) > 1; (*shift_hz)++)
;
return 1;
#else
return 0;
#endif
}
/* ================================================== */
static int
kernelvercmp(int major1, int minor1, int patch1,
int major2, int minor2, int patch2)
{
if (major1 != major2)
return major1 - major2;
if (minor1 != minor2)
return minor1 - minor2;
return patch1 - patch2;
}
/* ================================================== */
/* Compute the scaling to use on any frequency we set, according to
the vintage of the Linux kernel being used. */
@@ -883,20 +964,23 @@ get_version_specific_details(void)
int config_hz, set_config_hz; /* values of HZ from conf file */
int set_config_freq_scale;
double config_freq_scale;
double calculated_freq_scale;
struct tmx_params tmx_params;
struct utsname uts;
TMX_ReadCurrentParams(&tmx_params);
guess_hz_and_shift_hz(tmx_params.tick, &hz, &shift_hz);
if (!get_hz_and_shift_hz(&hz, &shift_hz)) {
TMX_ReadCurrentParams(&tmx_params);
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 {
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);
guess_hz_and_shift_hz(tmx_params.tick, &hz, &shift_hz);
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
}
}
CNF_GetLinuxHz(&set_config_hz, &config_hz);
@@ -912,10 +996,6 @@ get_version_specific_details(void)
max_tick_bias = nominal_tick / 10;
tick_update_hz = hz;
LOG(LOGS_INFO, LOGF_SysLinux, "set_config_hz=%d hz=%d shift_hz=%d basic_freq_scale=%.8f nominal_tick=%d slew_delta_tick=%d max_tick_bias=%d",
set_config_hz, hz, shift_hz, basic_freq_scale, nominal_tick, slew_delta_tick, max_tick_bias);
/* The basic_freq_scale comes from:
* the kernel increments the usec counter HZ times per second (if the timer
interrupt period were perfect)
@@ -946,7 +1026,9 @@ get_version_specific_details(void)
if (uname(&uts) < 0) {
LOG_FATAL(LOGF_SysLinux, "Cannot uname(2) to get kernel version, sorry.");
}
if (sscanf(uts.release, "%d.%d.%d", &major, &minor, &patch) != 3) {
patch = 0;
if (sscanf(uts.release, "%d.%d.%d", &major, &minor, &patch) < 2) {
LOG_FATAL(LOGF_SysLinux, "Cannot read information from uname, sorry");
}
@@ -956,101 +1038,60 @@ get_version_specific_details(void)
version_minor = minor;
version_patchlevel = patch;
have_nanopll = 0;
switch (major) {
case 1:
/* Does Linux v1.x even support HZ!=100? */
switch (minor) {
case 2:
if (patch == 13) {
freq_scale = (hz==100) ? (128.0 / 100.0) : basic_freq_scale ; /* I _think_! */
have_readonly_adjtime = 1;
} else {
LOG_FATAL(LOGF_SysLinux, "Kernel version not supported yet, sorry.");
}
break;
case 3:
/* I guess the change from the 1.2.x scaling to the 2.0.x
scaling must have happened during 1.3 development. I
haven't a clue where though, until someone looks it
up. */
LOG_FATAL(LOGF_SysLinux, "Kernel version not supported yet, sorry.");
break;
default:
LOG_FATAL(LOGF_SysLinux, "Kernel version not supported yet, sorry.");
break;
}
break;
case 2:
switch (minor) {
case 0:
if (patch < 32) {
freq_scale = (hz==100) ? (128.0 / 125.0) : basic_freq_scale;
have_readonly_adjtime = 1;
} else if (patch >= 32) {
freq_scale = (hz==100) ? (128.0 / 128.125) : basic_freq_scale;
/* The functionality in kernel/time.c in the kernel source
was modified with regard to what comes back in the
txc.offset field on return from adjtimex. If txc.modes
was ADJ_OFFSET_SINGLESHOT on entry, the outstanding
adjustment is returned, however the running offset will
be modified to the passed value. */
have_readonly_adjtime = 0;
}
break;
case 1:
/* I know that earlier 2.1 kernels were like 2.0.31, hence
the settings below. However, the 2.0.32 behaviour may
have been added late in the 2.1 series, however I have no
idea at which patch level. Leave it like this until
someone supplies some info. */
freq_scale = (hz==100) ? (128.0 / 125.0) : basic_freq_scale;
have_readonly_adjtime = 0; /* For safety ! */
break;
case 2:
case 3:
case 4:
case 5:
case 6:
if (minor < 6 || patch < 27) {
/* These seem to be like 2.0.32 */
freq_scale = (hz==100) ? (128.0 / 128.125) : basic_freq_scale;
have_readonly_adjtime = 0;
break;
}
if (patch < 33) {
/* Tickless kernels before 2.6.33 accumulated ticks only in
half-second intervals. */
tick_update_hz = 2;
}
/* Let's be optimistic that these will be the same until proven
otherwise :-) */
case 7:
case 8:
/* These don't seem to need scaling */
freq_scale = 1.0;
have_readonly_adjtime = 2;
have_nanopll = 1;
break;
default:
LOG_FATAL(LOGF_SysLinux, "Kernel version not supported yet, sorry.");
}
break;
default:
LOG_FATAL(LOGF_SysLinux, "Kernel's major version not supported yet, sorry");
break;
if (kernelvercmp(major, minor, patch, 2, 2, 0) < 0) {
LOG_FATAL(LOGF_SysLinux, "Kernel version not supported, sorry.");
}
if (kernelvercmp(major, minor, patch, 2, 6, 27) < 0) {
freq_scale = (hz == 100) ? (128.0 / 128.125) : basic_freq_scale;
} else {
/* These don't seem to need scaling */
freq_scale = 1.0;
if (kernelvercmp(major, minor, patch, 2, 6, 33) < 0) {
/* Tickless kernels before 2.6.33 accumulated ticks only in
half-second intervals */
tick_update_hz = 2;
}
}
/* ADJ_OFFSET_SS_READ support. It's available since 2.6.24,
but was buggy until 2.6.28. */
if (kernelvercmp(major, minor, patch, 2, 6, 28) < 0) {
have_readonly_adjtime = 0;
} else {
have_readonly_adjtime = 1;
}
/* ADJ_NANO support */
if (kernelvercmp(major, minor, patch, 2, 6, 27) < 0) {
have_nanopll = 0;
} else {
have_nanopll = 1;
}
/* ADJ_SETOFFSET support */
if (kernelvercmp(major, minor, patch, 2, 6, 39) < 0) {
have_setoffset = 0;
} else {
have_setoffset = 1;
}
/* PLL time constant changed in 2.6.31 */
if (kernelvercmp(major, minor, patch, 2, 6, 31) < 0) {
shift_pll = 4;
} else {
shift_pll = 2;
}
/* Override freq_scale if it appears in conf file */
CNF_GetLinuxFreqScale(&set_config_freq_scale, &config_freq_scale);
calculated_freq_scale = freq_scale;
if (set_config_freq_scale) freq_scale = config_freq_scale;
LOG(LOGS_INFO, LOGF_SysLinux, "calculated_freq_scale=%.8f freq_scale=%.8f",
calculated_freq_scale, freq_scale);
if (set_config_freq_scale) {
freq_scale = config_freq_scale;
}
LOG(LOGS_INFO, LOGF_SysLinux, "hz=%d shift_hz=%d freq_scale=%.8f nominal_tick=%d slew_delta_tick=%d max_tick_bias=%d shift_pll=%d",
hz, shift_hz, freq_scale, nominal_tick, slew_delta_tick, max_tick_bias, shift_pll);
}
/* ================================================== */
@@ -1060,25 +1101,19 @@ void
SYS_Linux_Initialise(void)
{
long offset;
double freq;
offset_register = 0.0;
fast_slewing = 0;
get_version_specific_details();
current_tick = nominal_tick;
current_total_tick = 1.0 / dhz;
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, apply_step_offset,
get_offset_correction, set_leap);
offset = 0;
if (TMX_ApplyOffset(&offset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
if (have_readonly_adjtime == 2 && (TMX_GetOffsetLeft(&offset) < 0 || offset)) {
if (have_readonly_adjtime && (TMX_GetOffsetLeft(&offset) < 0 || offset)) {
LOG(LOGS_INFO, LOGF_SysLinux, "adjtimex() doesn't support ADJ_OFFSET_SS_READ");
have_readonly_adjtime = 0;
}
@@ -1088,7 +1123,20 @@ SYS_Linux_Initialise(void)
have_nanopll = 0;
}
if (have_setoffset && TMX_TestStepOffset() < 0) {
LOG(LOGS_INFO, LOGF_SysLinux, "adjtimex() doesn't support ADJ_SETOFFSET");
have_setoffset = 0;
}
TMX_SetSync(CNF_GetRTCSync());
/* Read current kernel frequency */
TMX_GetFrequency(&freq, &current_tick);
current_total_tick = (current_tick + freq / freq_scale / dhz) / 1.0e6;
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, apply_step_offset,
get_offset_correction, set_leap);
}
/* ================================================== */
@@ -1104,16 +1152,6 @@ SYS_Linux_Finalise(void)
/* ================================================== */
void
SYS_Linux_GetKernelVersion(int *major, int *minor, int *patchlevel)
{
*major = version_major;
*minor = version_minor;
*patchlevel = version_patchlevel;
}
/* ================================================== */
#ifdef FEAT_LINUXCAPS
void
SYS_Linux_DropRoot(char *user)
@@ -1154,7 +1192,9 @@ SYS_Linux_DropRoot(char *user)
cap_free(cap);
#if 0
LOG(LOGS_INFO, LOGF_SysLinux, "Privileges dropped to user %s", user);
#endif
}
#endif
@@ -1183,7 +1223,9 @@ 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
}
}
}
@@ -1207,7 +1249,9 @@ 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
}
}
}

View File

@@ -31,8 +31,6 @@ extern void SYS_Linux_Initialise(void);
extern void SYS_Linux_Finalise(void);
extern void SYS_Linux_GetKernelVersion(int *major, int *minor, int *patchlevel);
extern void SYS_Linux_DropRoot(char *user);
extern void SYS_Linux_MemLockAll(int LockAll);

View File

@@ -25,6 +25,8 @@
Driver file for the NetBSD operating system.
*/
#include "config.h"
#ifdef __NetBSD__
#include <kvm.h>
@@ -197,7 +199,7 @@ stop_adjust(void)
slew backwards */
static void
accrue_offset(double offset)
accrue_offset(double offset, double corr_rate)
{
stop_adjust();
offset_register += offset;

View File

@@ -24,6 +24,8 @@
Driver file for Solaris operating system
*/
#include "config.h"
#ifdef SOLARIS
#include <kvm.h>
@@ -210,7 +212,7 @@ stop_adjust(void)
slew backwards */
static void
accrue_offset(double offset)
accrue_offset(double offset, double corr_rate)
{
stop_adjust();
offset_register += offset;

View File

@@ -24,6 +24,8 @@
Driver file for the SunOS 4.1.x operating system.
*/
#include "config.h"
#ifdef SUNOS
#include <kvm.h>
@@ -214,7 +216,7 @@ stop_adjust(void)
slew backwards */
static void
accrue_offset(double offset)
accrue_offset(double offset, double corr_rate)
{
stop_adjust();
offset_register += offset;

View File

@@ -25,6 +25,8 @@
*/
#include "config.h"
#include "conf.h"
#include "local.h"
#include "memory.h"

77
util.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009
* Copyright (C) Miroslav Lichvar 2009, 2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -25,10 +25,12 @@
Various utility functions
*/
#include "config.h"
#include "sysincl.h"
#include "util.h"
#include "md5.h"
#include "hash.h"
/* ================================================== */
@@ -238,7 +240,7 @@ UTI_TimestampToString(NTP_int64 *ts)
/* ================================================== */
char *
UTI_RefidToString(unsigned long ref_id)
UTI_RefidToString(uint32_t ref_id)
{
unsigned int i, j, c;
char buf[5], *result;
@@ -331,19 +333,27 @@ UTI_StringToIP(const char *addr, IPAddr *ip)
/* ================================================== */
unsigned long
uint32_t
UTI_IPToRefid(IPAddr *ip)
{
MD5_CTX ctx;
static int MD5_hash = -1;
unsigned char buf[16];
switch (ip->family) {
case IPADDR_INET4:
return ip->addr.in4;
case IPADDR_INET6:
MD5Init(&ctx);
MD5Update(&ctx, (unsigned const char *) ip->addr.in6, sizeof (ip->addr.in6));
MD5Final(&ctx);
return ctx.digest[0] << 24 | ctx.digest[1] << 16 | ctx.digest[2] << 8 | ctx.digest[3];
if (MD5_hash < 0) {
MD5_hash = HSH_GetHashId("MD5");
assert(MD5_hash >= 0);
}
if (HSH_Hash(MD5_hash, (unsigned const char *)ip->addr.in6, sizeof
(ip->addr.in6), NULL, 0, buf, 16) != 16) {
assert(0);
return 0;
};
return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
}
return 0;
}
@@ -610,3 +620,52 @@ UTI_FdSetCloexec(int fd)
}
/* ================================================== */
int
UTI_GenerateNTPAuth(int hash_id, const unsigned char *key, int key_len,
const unsigned char *data, int data_len, unsigned char *auth, int auth_len)
{
return HSH_Hash(hash_id, key, key_len, data, data_len, auth, auth_len);
}
/* ================================================== */
int
UTI_CheckNTPAuth(int hash_id, const unsigned char *key, int key_len,
const unsigned char *data, int data_len, const unsigned char *auth, int auth_len)
{
unsigned char buf[MAX_HASH_LENGTH];
return UTI_GenerateNTPAuth(hash_id, key, key_len, data, data_len,
buf, sizeof (buf)) == auth_len && !memcmp(buf, auth, auth_len);
}
/* ================================================== */
int
UTI_DecodePasswordFromText(char *key)
{
int i, j, len = strlen(key);
char buf[3], *p;
if (!strncmp(key, "ASCII:", 6)) {
memmove(key, key + 6, len - 6);
return len - 6;
} else if (!strncmp(key, "HEX:", 4)) {
if ((len - 4) % 2)
return 0;
for (i = 0, j = 4; j + 1 < len; i++, j += 2) {
buf[0] = key[j], buf[1] = key[j + 1], buf[2] = '\0';
key[i] = strtol(buf, &p, 16);
if (p != buf + 2)
return 0;
}
return i;
} else {
/* assume ASCII */
return len;
}
}

13
util.h
View File

@@ -32,6 +32,7 @@
#include "addressing.h"
#include "ntp.h"
#include "candm.h"
#include "hash.h"
/* Convert a timeval into a floating point number of seconds */
extern void UTI_TimevalToDouble(struct timeval *a, double *b);
@@ -71,13 +72,13 @@ extern char *UTI_TimevalToString(struct timeval *tv);
extern char *UTI_TimestampToString(NTP_int64 *ts);
/* Convert ref_id into a temporary string, for diagnostics */
extern char *UTI_RefidToString(unsigned long ref_id);
extern char *UTI_RefidToString(uint32_t ref_id);
/* Convert an IP address to string, for diagnostics */
extern char *UTI_IPToString(IPAddr *ip);
extern int UTI_StringToIP(const char *addr, IPAddr *ip);
extern unsigned long UTI_IPToRefid(IPAddr *ip);
extern uint32_t UTI_IPToRefid(IPAddr *ip);
extern void UTI_IPHostToNetwork(IPAddr *src, IPAddr *dest);
extern void UTI_IPNetworkToHost(IPAddr *src, IPAddr *dest);
extern int UTI_CompareIPs(IPAddr *a, IPAddr *b, IPAddr *mask);
@@ -101,6 +102,14 @@ extern Float UTI_FloatHostToNetwork(double x);
/* Set FD_CLOEXEC on descriptor */
extern void UTI_FdSetCloexec(int fd);
extern int UTI_GenerateNTPAuth(int hash_id, const unsigned char *key, int key_len,
const unsigned char *data, int data_len, unsigned char *auth, int auth_len);
extern int UTI_CheckNTPAuth(int hash_id, const unsigned char *key, int key_len,
const unsigned char *data, int data_len, const unsigned char *auth, int auth_len);
/* Decode password encoded in ASCII or HEX */
extern int UTI_DecodePasswordFromText(char *key);
#if defined (INLINE_UTILITIES)
#define INLINE_STATIC inline static
#include "util.c"

View File

@@ -1 +0,0 @@
DEVELOPMENT

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2002
* Copyright (C) Miroslav Lichvar 2011
* Copyright (C) Miroslav Lichvar 2011-2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -29,6 +29,8 @@
*/
#include "config.h"
#ifdef LINUX
#define _LOOSE_KERNEL_NAMES
@@ -84,24 +86,14 @@ TMX_SetFrequency(double *freq, long tick)
}
int
TMX_GetFrequency(double *freq)
TMX_GetFrequency(double *freq, long *tick)
{
struct timex txc;
int result;
txc.modes = 0; /* pure read */
result = adjtimex(&txc);
*freq = txc.freq / (double)(1 << SHIFT_USEC);
return result;
}
int
TMX_GetOffsetLeftOld(long *offset)
{
struct timex txc;
int result;
txc.modes = 0; /* pure read */
result = adjtimex(&txc);
*offset = txc.offset;
*tick = txc.tick;
return result;
}
@@ -215,13 +207,13 @@ TMX_EnableNanoPLL(void)
}
int
TMX_ApplyPLLOffset(long offset)
TMX_ApplyPLLOffset(long offset, long constant)
{
struct timex txc;
txc.modes = ADJ_OFFSET | ADJ_TIMECONST | ADJ_NANO;
txc.offset = offset;
txc.constant = 0;
txc.constant = constant;
return adjtimex(&txc);
}
@@ -237,5 +229,53 @@ TMX_GetPLLOffsetLeft(long *offset)
return result;
}
int
TMX_TestStepOffset(void)
{
struct timex txc;
/* Zero maxerror and check it's reset to a maximum after ADJ_SETOFFSET.
This seems to be the only way how to verify that the kernel really
supports the ADJ_SETOFFSET mode as it doesn't return an error on unknown
mode. */
txc.modes = ADJ_MAXERROR;
txc.maxerror = 0;
if (adjtimex(&txc) < 0 || txc.maxerror != 0)
return -1;
txc.modes = ADJ_SETOFFSET;
txc.time.tv_sec = 0;
txc.time.tv_usec = 0;
if (adjtimex(&txc) < 0 || txc.maxerror < 100000)
return -1;
return 0;
}
int
TMX_ApplyStepOffset(double offset)
{
struct timex txc;
txc.modes = ADJ_SETOFFSET;
if (offset >= 0) {
txc.time.tv_sec = offset;
} else {
txc.time.tv_sec = offset - 1;
}
/* ADJ_NANO changes the status even with ADJ_SETOFFSET, use it only when
STA_NANO is already enabled */
if (status & STA_PLL) {
txc.modes |= ADJ_NANO;
txc.time.tv_usec = 1e9 * (offset - txc.time.tv_sec);
} else {
txc.time.tv_usec = 1e6 * (offset - txc.time.tv_sec);
}
return adjtimex(&txc);
}
#endif

View File

@@ -67,15 +67,16 @@ struct tmx_params {
int TMX_SetTick(long tick);
int TMX_ApplyOffset(long *offset);
int TMX_SetFrequency(double *freq, long tick);
int TMX_GetFrequency(double *freq);
int TMX_GetOffsetLeftOld(long *offset);
int TMX_GetFrequency(double *freq, long *tick);
int TMX_GetOffsetLeft(long *offset);
int TMX_ReadCurrentParams(struct tmx_params *params);
int TMX_SetLeap(int leap);
int TMX_SetSync(int sync);
int TMX_EnableNanoPLL(void);
int TMX_ApplyPLLOffset(long offset);
int TMX_ApplyPLLOffset(long offset, long constant);
int TMX_GetPLLOffsetLeft(long *offset);
int TMX_TestStepOffset(void);
int TMX_ApplyStepOffset(double offset);
#endif /* GOT_WRAP_ADJTIMEX_H */