Compare commits

...

120 Commits

Author SHA1 Message Date
Miroslav Lichvar
9dc7ea7c62 Update NEWS 2011-01-28 13:21:56 +01:00
Miroslav Lichvar
546a3cdd50 Update credits 2011-01-28 12:57:03 +01:00
Miroslav Lichvar
e8c5d15690 Remove CVS headers 2011-01-28 12:56:09 +01:00
Miroslav Lichvar
e63cba05b2 Update copyright 2011-01-27 13:05:26 +01:00
Miroslav Lichvar
e8fe1dc415 Ignore reselectdist for refclocks 2011-01-25 17:51:19 +01:00
Miroslav Lichvar
9cf08fc780 Make importance of stratum in source selection configurable
Instead of always selecting the source with minimum stratum, add weighted
stratum to the distance when comparing selectable sources. The weight
can be configured with new stratumweight directive and can be set to
zero to ignore stratum completely, by default 1.0.
2011-01-25 17:40:46 +01:00
Miroslav Lichvar
b712b3a979 Disable variance source test for now
It seems it triggers even with one source alone if it's close and
accurate or polling interval is long enough. It would need to include
max_clock_error.
2011-01-25 17:40:46 +01:00
Miroslav Lichvar
a931b2eece Add outlyer source status to cmdmon protocol
This is not used yet.
2011-01-25 17:40:46 +01:00
Miroslav Lichvar
2e74beebbf Print sources with bad stats in client as unreachable 2011-01-25 17:40:46 +01:00
Miroslav Lichvar
db510a9558 Select source with minimum distance using a scoring system
Each source has a score against currently selected source which is
updated (multiplied by ratio of their distances) when one of the two
sources has a new sample. When the score reaches a limit, the source
will be selected. This should allow to slowly select the source with
minimum distance without frequent reselecting.

To avoid switching between sources with very variable distances (e.g. on
LAN or when upstream server uses a longer polling interval), sources
that are currently not selected are penalized by a fixed distance. This
can be configured with new reselectdist directive (100 microseconds by
default).
2011-01-25 17:40:37 +01:00
Miroslav Lichvar
222198acf3 Set status on doffset and dfreq commands 2011-01-19 15:29:49 +01:00
Miroslav Lichvar
bc4d5df94e Reply with status invalid instead of bad length on invalid command 2011-01-19 14:44:10 +01:00
Miroslav Lichvar
9d35b5deac Don't leak descriptors to sendmail 2011-01-18 18:07:46 +01:00
Miroslav Lichvar
59c68d240c Don't forget to shift last class dispatch timevals on step 2010-12-20 14:12:47 +01:00
Miroslav Lichvar
930a41b845 Don't send packet in last auto_offline transmit timeout 2010-12-17 18:09:10 +01:00
Miroslav Lichvar
323f0d187e Fix switching offline auto_offline source to online 2010-12-17 18:09:10 +01:00
Miroslav Lichvar
0078705bbe Enforce timeout class separation from last dispatched timeout 2010-12-17 16:09:12 +01:00
Miroslav Lichvar
3b3ca4afdc Use enum for scheduler timeout classes 2010-12-17 15:38:23 +01:00
Miroslav Lichvar
1d6b94b458 Fix crash when timeout is removed from its handler
Remove the timeout before dispatching the handler, and allow
calling SCH_RemoveTimeout() with nonexistent id.
2010-12-17 14:52:39 +01:00
Miroslav Lichvar
30c038c3c3 Make unsynchronised entry in tracking log on start 2010-12-17 13:22:57 +01:00
Miroslav Lichvar
05e002cd42 Delay selecting source on start
On start, when servers are reachable and use the same polling interval,
wait for them to have the same reachability register (which corresponds
to the number of samples in sourcestats) before selecting one.
2010-12-17 13:22:57 +01:00
Miroslav Lichvar
7f6ed73145 Don't update local reference unnecessarily
Local reference is now updated only when a new source is selected or
match_addr is equal to the selected source, match_addr 0 is no longer
treated specially.
2010-12-17 13:22:57 +01:00
Miroslav Lichvar
0c4968ec51 Track reachability in sources module
Add new flag to source struct to indicate when source is selectable
(packets with good headers are received) and use a reachability
register for last 8 samples instead of the reachable flag. Source
drivers now provide only reachability updates.
2010-12-17 13:22:29 +01:00
Miroslav Lichvar
ff69e86559 Apply jitter test only on NTP sources for now
With refclocks it seems to fail easily, users would have to set the delay
option appropriately.
2010-12-16 18:35:39 +01:00
Miroslav Lichvar
98f79404d6 Allow selecting source only when last regression was successful 2010-12-15 17:48:30 +01:00
Miroslav Lichvar
eec438a614 Fix jitter test in source selection
Distance should be compared to square root of variance.
2010-12-15 14:25:40 +01:00
Miroslav Lichvar
c88801065f Divide regression weights by stddev instead of minimum distance
This improves accuracy with large but stable network delays.
2010-12-14 17:00:53 +01:00
Miroslav Lichvar
833022b745 Add small randomness to spacing between samples for one server 2010-12-09 16:06:42 +01:00
Miroslav Lichvar
d1b820e7e3 Shorten initial delay and sampling separation to 0.2 seconds 2010-12-09 15:14:05 +01:00
Miroslav Lichvar
4373918a2f Fix separation of timeouts scheduled for exactly the same time 2010-12-09 14:34:29 +01:00
Miroslav Lichvar
6e96b4ba33 Add reselect command 2010-12-07 16:47:58 +01:00
Miroslav Lichvar
2d326bfc48 Require password for clients command 2010-12-07 16:47:58 +01:00
Miroslav Lichvar
a6988b2a79 Update chronyc help text 2010-12-07 16:47:57 +01:00
Miroslav Lichvar
8b93e1a780 Slowly back off sampling rate when selected source loses connectivity 2010-12-07 16:47:57 +01:00
Miroslav Lichvar
4e318c1abc Require valid_header before accumulating sample
Split test7 into two and to accumulate the sample require that all tests
pass, except the one which checks packet stratum is not higher than ours.

Also, don't mark the source as unreachable when only test4c fails.
2010-12-07 16:47:57 +01:00
Miroslav Lichvar
3cb6840d2d Fix log file names in documentation 2010-12-07 16:47:57 +01:00
Miroslav Lichvar
6ed5a65064 Add maxdelaydevratio command 2010-12-07 16:47:57 +01:00
Miroslav Lichvar
b977c95be4 Add test for ratio of increase in delay to stddev
Require that the ratio of the increase in delay from the minimum one in
the stats data register to the standard deviation of the offsets in the
register is less than maxdelaydevratio or the difference between
measured offset and predicted offset is larger than the increase in
delay. In the allowed delay increase is included also skew and maximum
clock frequency error.

maxdelaydevratio is 10.0 by default.
2010-12-07 16:47:57 +01:00
Miroslav Lichvar
feb8811f37 Cache minimum peer delay in sourcestats 2010-12-03 17:25:50 +01:00
Miroslav Lichvar
0de82a70a6 Keep only absolute values of peer delays in sourcestats
This saves some fabs() calls.
2010-12-03 13:17:09 +01:00
Miroslav Lichvar
cc3a8918f0 Include maximum clock frequency error in our dispersion
Add maxclockerror directive to set the stability of the clock (10 ppm by
default) and include it in our dispersion.
2010-12-03 13:15:14 +01:00
Miroslav Lichvar
63ef2badd6 Fix printing of NP and NR over 99 in sourcestats 2010-12-01 14:32:26 +01:00
Miroslav Lichvar
e98080b8bb Use only 3 chars from refclock driver name in default refid 2010-11-30 18:18:28 +01:00
Miroslav Lichvar
bed5b72cbe Add polltarget command 2010-10-14 15:08:35 +02:00
Miroslav Lichvar
7ab2c0e4a5 Add logbanner directive 2010-10-13 17:50:22 +02:00
Miroslav Lichvar
7a6ee1d729 Base poll adjustment on number of sourcestats samples
Instead of following skew changes, adjust polling interval so that the
number of measurements used in the regression algorithm remains close to
a target value. It can be configured with a new polltarget option
(6 by default).
2010-10-13 16:49:28 +02:00
Miroslav Lichvar
d9596334c3 Move default source parameters to macros 2010-10-13 12:58:26 +02:00
Miroslav Lichvar
16676ae726 Add -m option to allow multiple commands on command line 2010-10-04 15:53:35 +02:00
Miroslav Lichvar
fd3702f973 Add retries and timeout commands 2010-10-04 15:00:07 +02:00
Miroslav Lichvar
d674d23b45 Adjust chronyc timeout
Start at 1 second and increase it exponentially with maximum number of
attempts 3.
2010-10-04 13:16:52 +02:00
Miroslav Lichvar
5b8835f46b Support prefer and noselect options in chronyc 2010-08-26 10:29:58 +02:00
Miroslav Lichvar
ddb2cf3b8b Merge code for adding NTP server and peer in cmdmon 2010-08-26 09:35:57 +02:00
Miroslav Lichvar
f924862e89 Add prefer and noselect options 2010-08-25 18:32:40 +02:00
Miroslav Lichvar
061d497df0 Fix crash when reloading history with zero samples 2010-08-25 18:32:40 +02:00
Miroslav Lichvar
3a222336d7 Fix reloading sample histories with refclocks 2010-08-25 18:10:35 +02:00
Miroslav Lichvar
78300d018a Add minstratum command 2010-08-25 17:43:17 +02:00
Miroslav Lichvar
e95676f65f Document minstratum option 2010-08-25 17:43:15 +02:00
Benny Lyne Amorsen
c8fe69c956 Add minstratum option
Stratum in received packets is raised to the configured minimum.
2010-08-25 12:46:14 +02:00
Miroslav Lichvar
fe4b661fe7 Add -n option to allow using syslog without forking 2010-08-19 17:21:11 +02:00
Miroslav Lichvar
5344028c40 Use 5% critical region for number of runs
This results in more samples used in regression and slightly improved
response with high jitters.
2010-08-17 17:52:19 +02:00
Miroslav Lichvar
e591e3622b Extend runs test
Double the number of samples that are used in the runs test. E.g. with 64
samples in regression the runs test will be tried over the 64 samples and
up to 64 previous samples. The minimum number of samples in now 4.

This improves the response with low-mid jitters by about 50%.
2010-08-17 16:40:25 +02:00
Miroslav Lichvar
d8fc5fee0a Run configure tests with LDFLAGS 2010-08-17 12:31:03 +02:00
Miroslav Lichvar
eeb73b3670 Fix updating of best_single_sample 2010-08-16 16:44:49 +02:00
Miroslav Lichvar
2f2e524bc6 Don't use timezone parameter in gettimeofday and settimeofday calls 2010-08-12 14:43:26 +02:00
Miroslav Lichvar
6b0198c2d7 Replace all CROAK calls with assert or LOG_FATAL
Remove croak() and use assert() or LOG_FATAL() everywhere. Hopefully
the problems with debugging mentioned in the croak() comment are long gone.
2010-08-12 14:30:05 +02:00
Miroslav Lichvar
2a64b75893 Regenerate critical values for number of runs
Generate more values to allow regression with 128 samples. Possibly a
different approach was used to generate the values, or the previous table
was actually using 11% critical region and had an extra value in the
12th place.
2010-08-11 18:50:23 +02:00
Miroslav Lichvar
034e172033 Assert number of points in regress functions 2010-08-11 18:25:32 +02:00
Miroslav Lichvar
1faeb45063 Update offset correction errors only when needed 2010-08-11 17:16:16 +02:00
Miroslav Lichvar
fa84496423 Fix updating of nano slew offset correction error 2010-08-11 16:57:19 +02:00
Miroslav Lichvar
a3d47ffc81 Store sourcestats samples in circular buffer
The samples now don't have to be moved when pruning the register.
2010-08-10 16:39:52 +02:00
Miroslav Lichvar
d841c86a6e Cleanup sourcestats code a bit 2010-08-10 15:35:17 +02:00
Miroslav Lichvar
3b4e4b785d Change length of resid buffer to MAX_POINTS 2010-08-06 14:51:37 +02:00
Miroslav Lichvar
7ba6b617a1 Remove weights from sourcestats record
Weights are calculated before each regression call, no need to store them.
2010-08-06 14:39:09 +02:00
Miroslav Lichvar
100f732e20 Remove SST_DoUpdateRegression
The function is not used anywhere and it requires weights to be stored
sourcestats.
2010-08-06 14:36:56 +02:00
Miroslav Lichvar
cb28aeeacc Add nanosecond slewing to Linux driver
For offset adjustments below 10 microseconds use kernel PLL with
locked frequency and 1s time constant.
2010-08-06 11:50:35 +02:00
Miroslav Lichvar
7994b31de4 Reset adjtime offset on start 2010-08-05 13:27:52 +02:00
Miroslav Lichvar
6dcf3238f6 Clarify some cmdmon warning messages 2010-06-14 09:47:07 +02:00
Miroslav Lichvar
f6320e7050 Don't hang in our_round
The routine could loop infinitely when rounding a large value, replace
it with our_lround.
2010-06-07 14:19:58 +02:00
Miroslav Lichvar
597bb80d18 Set minimum allowed skew to 1e-12 2010-05-26 16:55:49 +02:00
Miroslav Lichvar
9775f3a030 Read chrony.conf before checking/writing pid file
This fixes the pidfile directive.
2010-05-20 16:10:51 +02:00
Miroslav Lichvar
a080d00352 Add rtcsync directive
The directive enables the 11 minute kernel mode. It cannot be used
when the normal RTC tracking is enabled.
2010-05-14 14:41:11 +02:00
Miroslav Lichvar
5fb0a9d53b Rehash NTP source table after removing source
This is needed to avoid breaking a probe sequence and losing another
source. It is costly, but it's not expected to happen frequently.
2010-05-13 18:29:00 +02:00
Miroslav Lichvar
40d82675bd Make use of UTI_AdjustTimeval in slew handlers 2010-05-07 18:52:05 +02:00
Miroslav Lichvar
f851e1f90e Fix RTC slew handler
The frequency adjustment needs to be done in the opposite direction.
2010-05-07 18:51:35 +02:00
Miroslav Lichvar
73d775c8b4 Don't use AI_ADDRCONFIG hint
We want to get IPv4/6 addresses even if the local system currently has
no IPv4/6 address configured.
2010-04-28 19:15:35 +02:00
Miroslav Lichvar
97f3e9404a Change online status also for unresolved sources 2010-04-28 17:18:03 +02:00
Miroslav Lichvar
83da131e99 Retry name resolving before marking sources online 2010-04-28 15:45:05 +02:00
Miroslav Lichvar
7973aef7b7 Don't log network is unreachable errors 2010-04-27 15:56:48 +02:00
Miroslav Lichvar
9a3bdcc20b Fix name resolving when IPv6 support is disabled 2010-04-27 14:35:28 +02:00
Miroslav Lichvar
aa91c608f4 Add delayed name resolving for servers and peers
Resolving is retried in increasing intervals (maximum is one hour)
until it succeeds or fails with a non-temporary error.

Unresolved sources are included in the activity report as offline
sources and the online command can be used to retry it immediately.

This could be improved by resolving in a separate thread/process
to avoid blocking.
2010-04-27 14:35:28 +02:00
Miroslav Lichvar
3d260d41b3 Don't retry resolving in DNS_Name2IPAddress
Instead of retrying to resolve it in the function and blocking for a
long time, return a TryAgain status and let the caller retry it later if
necessary.
2010-04-27 14:35:28 +02:00
Miroslav Lichvar
2458325c09 Merge NSR/NCR server and peer functions 2010-04-27 14:35:27 +02:00
Miroslav Lichvar
ab68a9d1d3 Set maxupdateskew to 1000 ppm by default
This will prevent from using unreliable frequency estimate on iburst
when starting without drift file.
2010-04-27 14:35:27 +02:00
Miroslav Lichvar
93b5b08bed Add iburst server option 2010-04-27 14:35:27 +02:00
Miroslav Lichvar
be4369936b Clamp tick value before calling adjtimex
If tick is outside allowed adjtimex range, clamp it and log a warning
instead of aborting.
2010-04-27 14:35:27 +02:00
Miroslav Lichvar
1a7415a6ab Return actual frequency in drv_set_freq functions
This is needed to keep sourcestats accurate when the actual frequency is
different from the requested frequency due to clamping (or possibly
rounding in future system drivers).
2010-04-27 14:35:27 +02:00
Miroslav Lichvar
c15db71f9e Add dispersion after Linux makestep 2010-04-27 14:35:27 +02:00
Miroslav Lichvar
74cb1c877c Mark source unreachable after offline burst 2010-04-27 14:35:27 +02:00
Miroslav Lichvar
a949ab6935 Increase burst polling interval
To avoid getting KoD RATE from NTP server (triggering discard minimum 1)
when burst sampling, increase polling interval to 2 seconds.
2010-04-27 14:35:27 +02:00
Miroslav Lichvar
f0fd7099c0 Stop burst sampling when received KoD RATE 2010-04-27 14:35:27 +02:00
Miroslav Lichvar
e0009f9f40 Update drift file at most once per hour
Instead of writing to the file on every reference update, update it
on first update, on exit and otherwise only once per hour.
2010-04-27 14:35:27 +02:00
Miroslav Lichvar
14d2576924 Remove absolute frequency from handler parameters
None of the current handlers really need it and with temperature
compensation enabled it would be necessary to undo the compensation
before passing it to the handlers.
2010-04-27 14:35:27 +02:00
Miroslav Lichvar
c386d11765 Add temperature compensation
A new tempcomp directive can be used to specify a file for reading
current temperature, update interval and compensation coefficients. The
clock frequency corrections are applied in local module and are invisible
in upper layers. The measurements and corrections can be logged to
tempcomp.log file.
2010-04-27 14:35:11 +02:00
Miroslav Lichvar
f12bc10917 Add fallback drifts
Fallback drifts are long-term averages of the system clock drift
calculated over exponentially increasing intervals. They are used when
the clock is unsynchronised to avoid quickly drifting away from true
time if there was a short-term deviation in drift before the
synchronisation was lost.
2010-04-27 14:27:05 +02:00
Miroslav Lichvar
99d18abf59 Fix frequency accumulation 2010-04-21 13:59:37 +02:00
Miroslav Lichvar
bc29c84610 Fix possible memory leak in mkdir_and_parents() 2010-04-13 15:16:49 +02:00
Miroslav Lichvar
e78e65ef22 Refactor file logging 2010-04-13 15:16:41 +02:00
Håkan Johansson
f9103531c4 Avoid large times in chronyc sources / sourcestats overflowing lines
Main trouble was double values too large to be represented as ints being
converted to -INT_MAX and then passing the < 9999 cut.
2010-04-07 14:26:41 +02:00
Miroslav Lichvar
2ea87490f4 Mark offline sources unreachable 2010-04-02 15:55:58 +02:00
Miroslav Lichvar
5fb5551c36 Add refclock precision 2010-03-02 14:23:54 +01:00
Miroslav Lichvar
b9b0326d15 Reduce noise in refclock sample dispersions
Use the estimated dispersion only if it's higher than long-term average.
This should improve performance with short polling intervals.
2010-03-02 14:23:50 +01:00
Miroslav Lichvar
97f2f16fd6 Log also filtered samples 2010-03-02 13:19:33 +01:00
Miroslav Lichvar
fc1514db04 Adjust refclock filter parameters
Drop only about 40 percent of samples, change default length to 64,
require at least 4 samples between polls (or full filter for lengths
below 4).
2010-03-02 13:19:33 +01:00
Miroslav Lichvar
7fb0598b50 Make linear fit in refclock dispersion calculation
This should improve reaction to sudden temperature changes with
very precise refclocks and/or long polling intervals.
2010-03-02 13:19:02 +01:00
Miroslav Lichvar
fd375ca55b Estimate offset correction error in Linux driver 2010-02-18 14:17:16 +01:00
Miroslav Lichvar
0f70959d8e Add dispersion notification handlers 2010-02-16 18:51:37 +01:00
Miroslav Lichvar
8cb6fcad7e Include offset correction error in dispersion 2010-02-16 18:38:46 +01:00
Miroslav Lichvar
20d898d182 Prepare for handling offset correction error 2010-02-16 17:46:42 +01:00
Miroslav Lichvar
10c9a7d4b7 Don't set system precision to log2 based value 2010-02-16 17:46:42 +01:00
Miroslav Lichvar
441e42c276 Fix stratum with locked PPS refclock and local stratum 2010-02-16 17:46:42 +01:00
89 changed files with 4041 additions and 2108 deletions

View File

@@ -1,9 +1,5 @@
##################################################
#
# $Header: /cvs/src/chrony/Makefile.in,v 1.48 2003/09/19 22:48:26 richard Exp $
#
# =======================================================================
#
# chronyd/chronyc - Programs for keeping computer clocks accurate.
#
# Copyright (C) Richard P. Curnow 1997-2003
@@ -46,7 +42,7 @@ OBJS = util.o sched.o regress.o local.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
refclock_pps.o tempcomp.o
EXTRA_OBJS=@EXTRA_OBJECTS@

33
NEWS
View File

@@ -1,3 +1,36 @@
New in version 1.25
===================
* Improve accuracy with NTP sources
* Improve accuracy with reference clocks
* Improve polling interval adjustment
* Improve stability with temporary asymmetric delays
* Improve source selection
* Add delayed server name resolving
* Add temperature compensation
* Add nanosecond slewing to Linux driver
* Add fallback drifts
* Add iburst, minstratum, maxdelaydevratio, polltarget,
prefer, noselect options
* Add rtcsync directive to enable Linux 11-minute mode
* Add reselectdist, stratumweight, logbanner, maxclockerror directives
* Add -n option to not detach daemon from terminal
* Fix pidfile directive
* Fix name resolving with disabled IPv6 support
* Fix reloading sample histories with reference clocks
* Fix crash with auto_offline option
* Fix online command on auto_offline sources
* 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
* 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
* Add -m option to allow multiple commands on command line
New in version 1.24
===================

13
README
View File

@@ -144,6 +144,9 @@ Acknowledgements
The following people have provided patches and other major contributions
to the program :
Benny Lyne Amorsen <benny@amorsen.dk>
Patch to add minstratum option
Andrew Bishop <amb@gedanken.demon.co.uk>
Fixes for bugs in logging when in daemon mode
Fixes for compiler warnings
@@ -198,6 +201,9 @@ Liam Hatton <me@liamhatton.com>
Jachym Holecek <jakym@volny.cz>
Patch to make Linux real time clock work with devfs
Håkan Johansson <f96hajo@chalmers.se>
Patch to avoid large values in sources and sourcestats output
Jim Knoble <jmknoble@pobox.com>
Fixes for compiler warnings
@@ -209,7 +215,12 @@ Miroslav Lichvar <mlichvar@redhat.com>
IPv6 support
Linux capabilities support
Leap second support
Various bug fixes and improvements
Improved source selection
Improved sample history trimming
Improved polling interval adjustment
Improved stability with temporary asymmetric delays
Temperature compensation
Many other bug fixes and improvements
Victor Moroz <vim@prv.adlum.ru>
Patch to support Linux with HZ!=100

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/acquire.c,v 1.24 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -168,6 +164,9 @@ prepare_socket(int family)
LOG_FATAL(LOGF_Acquire, "Could not open socket : %s", strerror(errno));
}
/* Close on exec */
UTI_FdSetCloexec(sock_fd);
if (port_number == 0) {
/* Don't bother binding this socket - we're not fussed what port
number it gets */
@@ -248,7 +247,6 @@ probe_source(SourceRecord *src)
int version = 3;
NTP_Mode my_mode = MODE_CLIENT;
struct timeval cooked;
double local_time_err;
union sockaddr_in46 his_addr;
int sock_fd;
socklen_t addrlen;
@@ -300,7 +298,7 @@ probe_source(SourceRecord *src)
}
LCL_ReadCookedTime(&cooked, &local_time_err);
LCL_ReadCookedTime(&cooked, NULL);
UTI_TimevalToInt64(&cooked, &pkt.transmit_ts);
if (sendto(sock_fd, (void *) &pkt, NTP_NORMAL_PACKET_SIZE,
@@ -449,7 +447,7 @@ read_from_socket(void *anything)
his_addr_len = sizeof(his_addr);
/* Get timestamp */
SCH_GetFileReadyTime(&now);
SCH_GetFileReadyTime(&now, NULL);
sock_fd = (long)anything;
status = recvfrom (sock_fd, (char *)&msg, message_length, flags,

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/acquire.h,v 1.9 2002/02/28 23:27:07 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/addressing.h,v 1.7 2002/02/28 23:27:08 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/addrfilt.c,v 1.8 2002/02/28 23:27:08 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/addrfilt.h,v 1.6 2002/02/28 23:27:08 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/broadcast.c,v 1.3 2002/02/28 23:27:08 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -78,12 +74,11 @@ timeout_handler(void *arbitrary)
unsigned long our_ref_id;
struct timeval our_ref_time;
double our_root_delay, our_root_dispersion;
double local_time_err;
struct timeval local_transmit;
version = 3;
LCL_ReadCookedTime(&local_transmit, &local_time_err);
LCL_ReadCookedTime(&local_transmit, NULL);
REF_GetReferenceParams(&local_transmit,
&are_we_synchronised, &leap_status,
&our_stratum,
@@ -116,13 +111,13 @@ timeout_handler(void *arbitrary)
message.receive_ts.hi = 0UL;
message.receive_ts.lo = 0UL;
LCL_ReadCookedTime(&local_transmit, &local_time_err);
LCL_ReadCookedTime(&local_transmit, NULL);
UTI_TimevalToInt64(&local_transmit, &message.transmit_ts);
NIO_SendNormalPacket(&message, &d->addr);
/* Requeue timeout. Don't care if interval drifts gradually, so just do it
* at the end. */
SCH_AddTimeoutInClass((double) d->interval, 1.0,
SCH_AddTimeoutInClass((double) d->interval, 1.0, 0.02,
SCH_NtpBroadcastClass,
timeout_handler, (void *) d);
@@ -149,7 +144,7 @@ BRD_AddDestination(IPAddr *addr, unsigned short port, int interval)
destinations[n_destinations].addr.port = port;
destinations[n_destinations].interval = interval;
SCH_AddTimeoutInClass((double) interval, 1.0,
SCH_AddTimeoutInClass((double) interval, 1.0, 0.0,
SCH_NtpBroadcastClass,
timeout_handler, (void *)(destinations + n_destinations));

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/broadcast.h,v 1.2 2002/02/28 23:27:08 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

42
candm.h
View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/candm.h,v 1.40 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -86,7 +82,11 @@
#define REQ_MANUAL_DELETE 42
#define REQ_MAKESTEP 43
#define REQ_ACTIVITY 44
#define N_REQUEST_TYPES 45
#define REQ_MODIFY_MINSTRATUM 45
#define REQ_MODIFY_POLLTARGET 46
#define REQ_MODIFY_MAXDELAYDEVRATIO 47
#define REQ_RESELECT 48
#define N_REQUEST_TYPES 49
/* Special utoken value used to log on with first exchange being the
password. (This time value has long since gone by) */
@@ -162,6 +162,24 @@ typedef struct {
int32_t EOR;
} REQ_Modify_Maxdelayratio;
typedef struct {
IPAddr address;
Float new_max_delay_dev_ratio;
int32_t EOR;
} REQ_Modify_Maxdelaydevratio;
typedef struct {
IPAddr address;
int32_t new_min_stratum;
int32_t EOR;
} REQ_Modify_Minstratum;
typedef struct {
IPAddr address;
int32_t new_poll_target;
int32_t EOR;
} REQ_Modify_Polltarget;
typedef struct {
Float new_max_update_skew;
int32_t EOR;
@@ -215,6 +233,9 @@ typedef struct {
/* Flags used in NTP source requests */
#define REQ_ADDSRC_ONLINE 0x1
#define REQ_ADDSRC_AUTOOFFLINE 0x2
#define REQ_ADDSRC_IBURST 0x4
#define REQ_ADDSRC_PREFER 0x8
#define REQ_ADDSRC_NOSELECT 0x10
typedef struct {
IPAddr ip_addr;
@@ -314,6 +335,10 @@ typedef struct {
int32_t EOR;
} REQ_Activity;
typedef struct {
int32_t EOR;
} REQ_Reselect;
/* ================================================== */
#define PKT_TYPE_CMD_REQUEST 1
@@ -369,6 +394,9 @@ typedef struct {
REQ_Dump dump;
REQ_Modify_Maxdelay modify_maxdelay;
REQ_Modify_Maxdelayratio modify_maxdelayratio;
REQ_Modify_Maxdelaydevratio modify_maxdelaydevratio;
REQ_Modify_Minstratum modify_minstratum;
REQ_Modify_Polltarget modify_polltarget;
REQ_Modify_Maxupdateskew modify_maxupdateskew;
REQ_Logon logon;
REQ_Settime settime;
@@ -396,6 +424,7 @@ typedef struct {
REQ_ManualDelete manual_delete;
REQ_MakeStep make_step;
REQ_Activity activity;
REQ_Reselect reselect;
} data; /* Command specific parameters */
} CMD_Request;
@@ -463,7 +492,8 @@ typedef struct {
#define RPY_SD_ST_UNREACH 1
#define RPY_SD_ST_FALSETICKER 2
#define RPY_SD_ST_JITTERY 3
#define RPY_SD_ST_OTHER 4
#define RPY_SD_ST_CANDIDATE 4
#define RPY_SD_ST_OUTLYER 5
typedef struct {
IPAddr ip_addr;

View File

@@ -1046,6 +1046,9 @@ Information messages and warnings will be logged to syslog.
The command line options supported are as follows:
@table @code
@item -n
When run in this mode, the program will not detach itself from the
terminal.
@item -d
When run in this mode, the program will not detach itself from the
terminal, and all messages will be sent to the terminal instead of to
@@ -1175,17 +1178,20 @@ directives can occur in any order in the file.
* 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
* initstepslew directive:: Trim the system clock on boot-up.
* keyfile directive:: Specify location of file containing keys
* 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
* log directive:: Make daemon log certain sets of information
* logbanner directive:: Specify how often is banner written to log files
* logchange directive:: Generate syslog messages if large offsets occur
* 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
* 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
* noclientlog directive:: Prevent chronyd from gathering data about clients
* clientloglimit directive:: Set client log memory limit
@@ -1193,12 +1199,16 @@ directives can occur in any order in the file.
* pidfile directive:: Specify the file where chronyd's pid is written
* port directive:: Set port to use for NTP packets
* refclock directive:: Specify a reference clock
* reselectdist directive:: Set improvement in distance needed to reselect a source
* rtcdevice directive:: Specify name of enhanced RTC device (if not /dev/rtc)
* rtcfile directive:: Specify the file where real-time clock data is stored
* rtconutc directive:: Specify that the real time clock keeps UTC not local time
* rtcsync directive:: Specify that RTC should be automatically synchronised by kernel
* server directive:: Specify an NTP server
* sched_priority directive:: Require real-time scheduling and specify a priority for it.
* stratumweight directive:: Specify how important is stratum when selecting source
* lock_all directive:: Require that chronyd be locked into RAM.
* tempcomp directive:: Specify temperature sensor and compensation coefficients
@end menu
@c }}}
@@ -1563,6 +1573,34 @@ If this command is present, it indicates that @code{chronyd} should save
the measurement history for each of its time sources recorded whenever
the program exits. (See the dumpdir command above).
@c }}}
@c {{{ fallbackdrift
@node fallbackdrift directive
@subsection fallbackdrift
Fallback drifts are long-term averages of the system clock drift
calculated over exponentially increasing intervals. They are used
when the clock is unsynchronised to avoid quickly drifting away from
true time if there was a short-term deviation in drift before the
synchronisation was lost.
The directive specifies the minimum and maximum interval for how long
the system clock has to be unsynchronised to switch between fallback
drifts. They are defined as a power of 2 (in seconds). The syntax is
as follows
@example
fallbackdrift 16 19
@end example
In this example, the minimum interval is 16 (18 hours) and maximum
interval is 19 (6 days). The system clock frequency will be set to
the first fallback 18 hours after the synchronisation was lost, to the
second after 36 hours, etc. This might be a good setting to cover
daily and weekly temperature fluctuations.
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 {{{ initstepslew
@node initstepslew directive
@subsection initstepslew
@@ -1759,8 +1797,11 @@ rate, and any slews made, to a file called tracking.log.
This option logs information about the system's real-time clock.
@item refclocks
This option logs the raw reference clock measurements to a file
called refclocks.log.
This option logs the raw and filtered reference clock measurements to
a file called refclocks.log.
@item tempcomp
This option logs the temperature measurements and system rate
compensations to a file called tempcomp.log.
@end table
The files are written to the directory specified by the logdir
@@ -1778,6 +1819,7 @@ log measurements statistics tracking
* tracking log:: The format of the tracking log
* RTC log:: The format of the RTC log
* refclocks log:: The format of the refclocks log
* tempcomp log:: The format of the tempcomp log
@end menu
@c }}}
@c {{{ measurements.log
@@ -1788,7 +1830,7 @@ An example line (which actually appears as a single line in the file)
from the measurements log file is shown below.
@example
1998-07-22 05:40:50 158.152.1.76 N 8 1111 11 1111 10 10 1 \
2010-12-22 05:40:50 158.152.1.76 N 8 1111 111 1111 10 10 1.0 \
-4.966e-03 2.296e-01 1.577e-05 1.615e-01 7.446e-03
@end example
@@ -1797,7 +1839,7 @@ values from the example line above) :
@enumerate 1
@item
Date [1998-07-22]
Date [2010-12-22]
@item
Hour:Minute:Second [05:40:50]. Note that the date/time pair is
expressed in UTC, not the local time zone.
@@ -1813,8 +1855,8 @@ Stratum of remote computer. [2]
@item
RFC1305 tests 1 through 4 (1=pass, 0=fail) [1111]
@item
Tests for maximum delay and maximum delay ratio, against user defined
parameters (1=pass, 0=fail) [11]
Tests for maximum delay, maximum delay ratio and maximum delay dev ratio,
against defined parameters (1=pass, 0=fail) [111]
@item
RFC1305 tests 5 through 8 (1=pass, 0=fail) [1111]
@item
@@ -1823,8 +1865,8 @@ Local poll [10]
Remote poll [10]
@item
`Score' (an internal score within each polling level used to decide when
to increase or decrease the polling level. This is adjusted based on
changes to the variance of the measurements obtained from the source). [1]
to increase or decrease the polling level. This is adjusted based on number
of measurements currently being used for the regression algorithm). [1.0]
@item
The estimated local clock error (`theta' in RFC1305). Positive indicates that the local clock is slow. [-4.966e-03].
@item
@@ -1845,7 +1887,7 @@ meanings of the columns.
@subsubsection Statistics log file format
An example line (which actually appears as a single line in the file)
from the measurements log file is shown below.
from the statistics log file is shown below.
@example
1998-07-22 05:40:50 158.152.1.76 6.261e-03 -3.247e-03 \
@@ -1909,7 +1951,7 @@ meanings of the columns.
@subsubsection Tracking log file format
An example line (which actually appears as a single line in the file)
from the measurements log file is shown below.
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
@@ -2002,7 +2044,7 @@ An example line (which actually appears as a single line in the file)
from the refclocks log file is shown below.
@example
2009-11-30 14:33:27.000000 PPS2 7 N 1 4.900000e-07 -6.741777e-07
2009-11-30 14:33:27.000000 PPS2 7 N 1 4.900000e-07 -6.741777e-07 1.000e-06
@end example
The columns are as follows (the quantities in square brackets are the
@@ -2017,24 +2059,68 @@ date/time pair is expressed in UTC, not the local time zone.
@item
Reference ID of refclock from which measurement comes. [PPS2]
@item
Sequence number of driver poll within one polling interval. [7]
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]
@item
Flag indicating whether the sample comes from PPS source. (1 for yes,
0 for no). [1]
0 for no, or @code{-} for filtered sample). [1]
@item
Local clock error measured by refclock driver. [4.900000e-07]
Local clock error measured by refclock driver, or @code{-} for
filtered sample. [4.900000e-07]
@item
Local clock error with applied corrections. Positive indicates
that the local clock is slow. [-6.741777e-07]
@item
Assumed dispersion of the sample. [1.000e-06]
@end enumerate
A banner is periodically written to the log file to indicate the
meanings of the columns.
@c }}}
@c {{{ tempcomp.log
@node tempcomp log
@subsubsection Tempcomp log file format
An example line (which actually appears as a single line in the file)
from the tempcomp log file is shown below.
@example
2010-04-19 10:39:48 2.8000e+04 3.6600e-01
@end example
The columns are as follows (the quantities in square brackets are the
values from the example line above) :
@enumerate 1
@item
Date [2010-04-19]
@item
Hour:Minute:Second [10:39:48]. Note that the
date/time pair is expressed in UTC, not the local time zone.
@item
Temperature read from tempcomp file. [2.8000e+04]
@item
Applied compensation in ppm, positive means the system clock is
running faster than it would be without the compensation. [3.6600e-01]
@end enumerate
A banner is periodically written to the log file to indicate the
meanings of the columns.
@c }}}
@c }}}
@c {{{ logbanner
@node logbanner directive
@subsection logbanner
A banner is periodically written to the log files enabled by the
@code{log} directive to indicate the meanings of the columns.
The @code{logbanner} directive specifies after how many entries in the
log file should be the banner written. The default is 32, and 0 can be
used to disable it entirely.
@c }}}
@c {{{ logchange
@node logchange directive
@@ -2126,6 +2212,25 @@ idea of the two commands is that the @code{manual} command controls the
manual clock driver's behaviour, whereas the @code{settime} command
allows samples of manually entered time to be provided).
@c }}}
@c {{{ maxclockerror
@node maxclockerror directive
@subsection maxclockerror
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.
The syntax is
@example
maxclockerror <error-in-ppm>
@end example
Typical values for <error-in-ppm> might be 10 for a low quality clock
to 0.1 for a high quality clock using a temperature compensated
crystal oscillator.
@c }}}
@c {{{ maxupdateskew
@node maxupdateskew directive
@subsection maxupdateskew
@@ -2139,6 +2244,7 @@ loss rate is not very reliable.
The @code{maxupdateskew} parameter allows the threshold for determining
whether an estimate may be so unreliable that it should not be used.
By default, the threshold is 1000 ppm.
The syntax is
@@ -2285,9 +2391,11 @@ driver name and the number of the refclock are used as refid. Each
refclock has to use an unique refid.
@item filter
This option sets the length of the median filter which is used to
reduce noise. With each poll about half of the stored samples are
reduce noise. With each poll about 40 percent of the stored samples is
discarded and one final sample is calculated as average of the
remaining samples. The default is 15.
remaining samples. If the length is 4 or above, at least 4 samples
have to be collected between polls. For lengths below 4, the filter
has to be full. The default is 64.
@item rate
PPS signal frequency (in Hz). This option only controls how the
received pulses are aligned. To actually receive more than one
@@ -2309,8 +2417,31 @@ to be inaccurate (in seconds). Increasing the value is useful to
avoid having no majority in the source selection algorithm or to make
the algorithm prefer other refclocks. The default is 1e-9 (1
nanosecond).
@item precision
Refclock precision (in seconds). The default is 1e-6 (1 microsecond)
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.
@end table
@c }}}
@c {{{ reselectdist
@node reselectdist directive
@subsection reselectdist
When @code{chronyd} selects synchronisation source from available sources, it
will prefer the one with minimum synchronisation distance. However, to
avoid frequent reselecting when there are sources with similar distance, a
fixed distance is added to the distance for sources that are currently not
selected. This can be set with the @code{reselectdist} option. By default, the
distance is 100 microseconds.
The syntax is
@example
reselectdist <dist-in-seconds>
@end example
@c }}}
@c {{{ rtcdevice
@node rtcdevice directive
@@ -2384,6 +2515,17 @@ If the @code{rtconutc} directive appears, it means the RTC is required
to keep UTC. The directive takes no arguments. It is equivalent to
specifying the @code{-u} switch to the Linux @file{/sbin/clock} program.
@c }}}
@c {{{ rtcsync
@node rtcsync directive
@subsection rtcsync
The @code{rtcsync} directive will enable a kernel mode where the
system time is copied to the real time clock (RTC) every 11 minutes.
This directive is supported only on Linux and cannot be used when the
normal RTC tracking is enabled, i.e. when the @code{rtcfile} directive
is used.
@c }}}
@c {{{ sched_priority
@node sched_priority directive
@subsection sched_priority
@@ -2402,6 +2544,26 @@ resource requirements are modest, but it should result in lower and
more consistent latency since Chronyd will not need to wait for the
scheduler to get around to running it. You should not use this unless
you really need it. The sched_setscheduler man page has more details.
@c }}}
@c {{{ stratumweight
@node stratumweight directive
@subsection stratumweight
The @code{stratumweight} directive sets how much distance should be added
per stratum to the synchronisation distance when @code{chronyd} selects
the synchronisation source from available sources.
The syntax is
@example
stratumweight <dist-in-seconds>
@end example
By default, it is 1 second. This usually means that sources with lower stratum
will be preferred to sources with higher stratum even when their distance is
significantly worse. Setting @code{stratumweight} to 0 makes @code{chronyd}
ignore stratum when selecting the source.
@c }}}
@c {{{ lock_all
@node lock_all directive
@@ -2471,6 +2633,12 @@ measurements that it has buffered. If a measurement has a round trip
delay that is greater than the maxdelayratio times the minimum delay, it
will be rejected.
@item maxdelaydevratio
If a measurement has ratio of the increase in round-trip delay from
the minimum delay amongst the previous measurements to the standard
deviation of the previous measurements that is greater than
maxdelaydevratio, it will be rejected. The default is 10.0.
@item presend
If the timing measurements being made by @code{chronyd} are the only
network data passing between two computers, you may find that some
@@ -2524,7 +2692,74 @@ chrony when disconnecting the dial-up link. (It will still be necessary to use
chronyc's @code{online} (@pxref{online command}) command when the link has been
established, to enable measurements to start.)
@item iburst
On start, make four measurements over a short duration (rather than
the usual periodic measurements).
@item minstratum
When the synchronisation source is selected from available sources, sources
with lower stratum are normally preferred. This option can be used to increase
stratum of the source to the specified minimum, so @code{chronyd} will avoid
selecting that source. This is useful with low stratum sources that are known
to be unrealiable or inaccurate and which should be used only when other
sources are unreachable.
@item polltarget
Target number of measurements to use for the regression algorithm which
@code{chronyd} will try to maintain by adjusting polling interval between
@code{minpoll} and @code{maxpoll}. A higher target makes @code{chronyd} prefer
shorter polling intervals. The default is 6 and a useful range is 6 to 60.
@item prefer
Prefer this source over sources without prefer option.
@item noselect
Never select this source. This is particularly useful for monitoring.
@end table
@c }}}
@c {{{ tempcomp
@node tempcomp directive
@subsection tempcomp
Normally, changes in rate of drift of the system clock are caused mainly by
changes in temperature of the crystal oscillator on the mainboard.
If there are available temperature measurements from a sensor close to the
oscillator, @code{tempcomp} directive can be used to compensate for the changes
in rate and possibly improve clock accuracy.
Whether it will really help depends on many factors, including resolution of
the sensor, noise in measurements, time source polling interval, compensation
update interval, how good are the temperature coefficients, and how close is
the sensor to the oscillator. The frequency reported in tracking.log should
be more stable and the offsets should be smaller.
The directive has six parameters: path to the file which contains current
temperature in text format, update interval (in seconds), and temperature
coefficients T0, k0, k1, k2.
The frequency compensation is calculated (in ppm) as
@code{k0 + (T - T0) * k1 + (T - T0)^2 * k2}
The result has to be between -10 ppm and 10 ppm, otherwise the measurement is
considered to be faulty and will be ignored. The k0 coefficient can be used to
get the results in that range.
Valid measurements and calculated corrections are logged to tempcomp.log file if
enabled with @code{log tempcomp} directive.
An example of use is
@example
tempcomp /sys/class/hwmon/hwmon1/device/temp2_input 30 26000 0.0 0.000183 0.0
@end example
The measured temperature will be read from the file in Linux sysfs filesystem
every 30 seconds. When the temperature is 26 degress (26000), the system clock
frequency will not be adjusted. When it is 27 degrees (27000), the clock will
be set to run 0.183ppm faster than it would be without the compensation, etc.
@c }}}
@c }}}
@c {{{ S:Running chronyc
@@ -2587,6 +2822,9 @@ This option disables resolving IP addresses to hostnames.
With this option hostnames will be resolved only to IPv4 addresses.
@item -6
With this option hostnames will be resolved only to IPv6 addresses.
@item -m
With this option multiple commands can be specified on the command line.
Each argument will be interpreted as a whole command.
@end table
@c }}}
@c {{{ SS:Security with chronyc
@@ -2624,7 +2862,6 @@ password:
@itemize @bullet
@item @code{activity}
@item @code{clients}
@item @code{dns}
@item @code{exit}
@item @code{help}
@@ -2674,17 +2911,23 @@ interface.
* manual command:: Enable/disable/configure options for settime
* maxdelay command:: Set max measurement delay for a source
* maxdelayratio command:: Set max measurement delay for a source as ratio
* maxdelaydevratio command:: Set max measurement delay for a source as ratio to deviation
* maxpoll command:: Set maximum polling interval for a source
* maxupdateskew command:: Set safety threshold for clock gain/loss rate
* minpoll command:: Set minimum polling interval for a source
* minstratum command:: Set minimum stratum for a source
* offline command:: Warn that connectivity to a source will be lost
* online command:: Warn that connectivity to a source has been restored
* password command:: Provide password needed for most commands
* polltarget command:: Set poll target for a source
* quit command:: Exit from chronyc
* reselect command:: Reselect synchronisation source
* retries command:: Set maximum number of retries
* rtcdata command:: Display RTC parameters
* settime command:: Provide a manual input of the current time
* sources command:: Display information about the current set of sources
* sourcestats command:: Display the rate & offset estimation performance of sources
* timeout command:: Set initial response timeout
* tracking command:: Display system clock performance
* trimrtc command:: Correct the RTC time to the current system time
* writertc command:: Write the RTC parameters to file.
@@ -3234,6 +3477,22 @@ address @code{2001:db8::1} to be double the retained minimum.
As for @code{maxdelay}, any measurement whose network delay is too large
will be discarded.
@c }}}
@c {{{ maxdelaydevratio
@node maxdelaydevratio command
@subsubsection maxdelaydevratio
This allows the @code{maxdelaydevratio} option for one of the sources to be
modified, in the same way as specifying the @code{maxdelaydevratio} option
for the @code{server} directive in the configuration file (@pxref{server
directive}).
The following examples illustrate the syntax
@example
maxdelaydevratio foo.bar.com 0.1
maxdelaydevratio 1.2.3.4 1.0
maxdelaydevratio 2001:db8::1 100.0
@end example
@c }}}
@c {{{ maxpoll
@node maxpoll command
@subsubsection maxpoll
@@ -3302,6 +3561,35 @@ to 32 seconds.
Note that the new minimum polling interval only takes effect after the
next measurement has been made.
@c }}}
@c {{{ minstratum
@node minstratum command
@subsubsection minstratum
The @code{minstratum} command is used to modify the minimum stratum
for one of the current set of sources. It is equivalent to the
@code{minstratum} option in the @code{server} directive in the
configuration file (@pxref{server directive}).
The syntax is as follows
@example
minstratum <host> <new-min-stratum>
@end example
where the host can be specified as either a machine name or
IP address.
An example is
@example
minpoll foo.bar.com 5
@end example
which sets the minimum stratum for the host @code{foo.bar.com}
to 5.
Note that the new minimum stratum only takes effect after the
next measurement has been made.
@c }}}
@c {{{ offline
@node offline command
@subsubsection offline
@@ -3414,12 +3702,57 @@ The password is any string of characters not containing whitespace. It
has to match @code{chronyd's} currently defined command key (@pxref{commandkey
directive}).
@c }}}
@c {{{ polltarget
@node polltarget command
@subsubsection polltarget
The @code{polltarget} command is used to modify the poll target for
one of the current set of sources. It is equivalent to the
@code{polltarget} option in the @code{server} directive in the
configuration file (@pxref{server directive}).
The syntax is as follows
@example
polltarget <host> <new-poll-target>
@end example
where the host can be specified as either a machine name or
IP address.
An example is
@example
polltarget foo.bar.com 12
@end example
which sets the poll target for the host @code{foo.bar.com}
to 12.
@c }}}
@c {{{ quit
@node quit command
@subsubsection quit
The quit command exits from chronyc and returns the user to the shell
(same as the exit command).
@c }}}
@c {{{ reselect command
@node reselect command
@subsubsection reselect
To avoid excessive switching between sources, @code{chronyd} may stay
synchronised to a source even when it is not currently the best one among the
available sources.
The @code{reselect} command can be used to force @code{chronyd} to
reselect the best synchronisation source.
@c }}}
@c {{{ retries
@node retries command
@subsubsection retries
The @code{retries} command sets the maximum number of retries for
@code{chronyc} requests before giving up. The response timeout is controlled
by @code{timeout} command (@pxref{timeout command}).
The default is 2.
@c }}}
@c {{{ rtcdata
@node rtcdata command
@subsubsection rtcdata
@@ -3657,6 +3990,16 @@ This is the estimated sample standard deviation.
@end table
@c }}}
@c {{{ timeout
@node timeout command
@subsubsection timeout
The @code{timeout} command sets the initial timeout for @code{chronyc} requests
in milliseconds. If no response is received from @code{chronyd}, the timeout is
doubled and the request is resent. The maximum number of retries is configured
with the @code{retries} command (@pxref{retries command}).
The default is 1000 milliseconds.
@c }}}
@c {{{ tracking
@node tracking command
@subsubsection tracking

View File

@@ -35,8 +35,12 @@ struct timex {
int :32; int :32; int :32; int :32;
};
#define ADJ_OFFSET 0x0001 /* time offset */
#define ADJ_FREQUENCY 0x0002 /* frequency offset */
#define ADJ_MAXERROR 0x0004 /* maximum time error */
#define ADJ_STATUS 0x0010 /* clock status */
#define ADJ_TIMECONST 0x0020 /* pll time constant */
#define ADJ_NANO 0x2000 /* select nanosecond resolution */
#define ADJ_TICK 0x4000 /* tick value */
#define ADJ_OFFSET_SINGLESHOT 0x8001 /* old-fashioned adjtime */
#define ADJ_OFFSET_SS_READ 0xa001 /* read-only adjtime */
@@ -59,6 +63,7 @@ struct timex {
#define STA_PPSERROR 0x0800 /* PPS signal calibration error (ro) */
#define STA_CLOCKERR 0x1000 /* clock hardware fault (ro) */
#define STA_NANO 0x2000 /* resolution (0 = us, 1 = ns) (ro) */
/* This doesn't seem to be in any include files !! */

View File

@@ -38,6 +38,10 @@ resolve hostnames only to IPv4 addresses
\fB\-6\fR
resolve hostnames only to IPv6 addresses
.TP
\fB\-m\fR
allow multiple commands to be specified on the command line. Each argument
will be interpreted as a whole command.
.TP
\fIcommand\fR
specify command. If no command is given, chronyc will read commands
interactively.

View File

@@ -45,6 +45,10 @@ Linux.
This option will lock chronyd into RAM so that it will never be paged out.
This mode is only supported on Linux.
.TP
.B \-n
When run in this mode, the program will not detach itself from the
terminal.
.TP
.B \-d
When run in this mode, the program will not detach itself from the
terminal, and all messages will be sent to the terminal instead of

327
client.c
View File

@@ -1,13 +1,9 @@
/*
$Header: /cvs/src/chrony/client.c,v 1.68 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009
* Copyright (C) Miroslav Lichvar 2009-2011
*
* 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
@@ -150,7 +146,7 @@ open_io(const char *hostname, int port)
IPAddr ip;
/* Note, this call could block for a while */
if (!DNS_Name2IPAddress(hostname, &ip, 0)) {
if (DNS_Name2IPAddress(hostname, &ip) != DNS_Success) {
fprintf(stderr, "Could not get IP address for %s\n", hostname);
exit(1);
}
@@ -330,7 +326,7 @@ read_address_integer(char *line, IPAddr *address, int *value)
fprintf(stderr, "Invalid syntax for address value\n");
ok = 0;
} else {
if (!DNS_Name2IPAddress(hostname, address, 0)) {
if (DNS_Name2IPAddress(hostname, address) != DNS_Success) {
fprintf(stderr, "Could not get address for hostname\n");
ok = 0;
} else {
@@ -355,7 +351,7 @@ read_address_double(char *line, IPAddr *address, double *value)
fprintf(stderr, "Invalid syntax for address value\n");
ok = 0;
} else {
if (!DNS_Name2IPAddress(hostname, address, 0)) {
if (DNS_Name2IPAddress(hostname, address) != DNS_Success) {
fprintf(stderr, "Could not get address for hostname\n");
ok = 0;
} else {
@@ -436,6 +432,28 @@ process_cmd_maxdelay(CMD_Request *msg, char *line)
/* ================================================== */
static int
process_cmd_maxdelaydevratio(CMD_Request *msg, char *line)
{
IPAddr address;
double max_delay_dev_ratio;
int ok;
if (read_address_double(line, &address, &max_delay_dev_ratio)) {
UTI_IPHostToNetwork(&address, &msg->data.modify_maxdelaydevratio.address);
msg->data.modify_maxdelayratio.new_max_delay_ratio = UTI_FloatHostToNetwork(max_delay_dev_ratio);
msg->command = htons(REQ_MODIFY_MAXDELAYDEVRATIO);
ok = 1;
} else {
ok = 0;
}
return ok;
}
/* ================================================== */
static int
process_cmd_maxdelayratio(CMD_Request *msg, char *line)
{
@@ -458,6 +476,50 @@ process_cmd_maxdelayratio(CMD_Request *msg, char *line)
/* ================================================== */
static int
process_cmd_minstratum(CMD_Request *msg, char *line)
{
IPAddr address;
int min_stratum;
int ok;
if (read_address_integer(line, &address, &min_stratum)) {
UTI_IPHostToNetwork(&address, &msg->data.modify_minstratum.address);
msg->data.modify_minstratum.new_min_stratum = htonl(min_stratum);
msg->command = htons(REQ_MODIFY_MINSTRATUM);
ok = 1;
} else {
ok = 0;
}
return ok;
}
/* ================================================== */
static int
process_cmd_polltarget(CMD_Request *msg, char *line)
{
IPAddr address;
int poll_target;
int ok;
if (read_address_integer(line, &address, &poll_target)) {
UTI_IPHostToNetwork(&address, &msg->data.modify_polltarget.address);
msg->data.modify_polltarget.new_poll_target = htonl(poll_target);
msg->command = htons(REQ_MODIFY_POLLTARGET);
ok = 1;
} else {
ok = 0;
}
return ok;
}
/* ================================================== */
static int
process_cmd_maxupdateskew(CMD_Request *msg, char *line)
{
@@ -621,7 +683,7 @@ parse_allow_deny(CMD_Request *msg, char *line)
if (*q == '\n') *q = 0;
q++;
}
if (!DNS_Name2IPAddress(p, &ip, 0)) {
if (DNS_Name2IPAddress(p, &ip) != DNS_Success) {
fprintf(stderr, "Could not read address\n");
return 0;
} else {
@@ -795,7 +857,7 @@ accheck_getaddr(char *line, IPAddr *addr)
if (*q == '\n') *q = 0;
q++;
}
if (!DNS_Name2IPAddress(p, &ip, 0)) {
if (DNS_Name2IPAddress(p, &ip) != DNS_Success) {
return 0;
} else {
*addr = ip;
@@ -902,6 +964,28 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
status = CPS_ParseNTPSourceAdd(line, &data);
switch (status) {
case CPS_Success:
/* Don't retry name resolving */
if (data.ip_addr.family == IPADDR_UNSPEC) {
Free(data.name);
fprintf(stderr, "Invalid host/IP address\n");
break;
}
if (data.params.min_stratum != SRC_DEFAULT_MINSTRATUM) {
fprintf(stderr, "Option minstratum not supported\n");
break;
}
if (data.params.poll_target != SRC_DEFAULT_POLLTARGET) {
fprintf(stderr, "Option polltarget not supported\n");
break;
}
if (data.params.max_delay_dev_ratio != SRC_DEFAULT_MAXDELAYDEVRATIO) {
fprintf(stderr, "Option maxdelaydevratio not supported\n");
break;
}
msg->data.ntp_source.port = htonl((unsigned long) data.port);
UTI_IPHostToNetwork(&data.ip_addr, &msg->data.ntp_source.ip_addr);
msg->data.ntp_source.minpoll = htonl(data.params.minpoll);
@@ -912,7 +996,10 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
msg->data.ntp_source.max_delay_ratio = UTI_FloatHostToNetwork(data.params.max_delay_ratio);
msg->data.ntp_source.flags = htonl(
(data.params.online ? REQ_ADDSRC_ONLINE : 0) |
(data.params.auto_offline ? REQ_ADDSRC_AUTOOFFLINE : 0));
(data.params.auto_offline ? REQ_ADDSRC_AUTOOFFLINE : 0) |
(data.params.iburst ? REQ_ADDSRC_IBURST : 0) |
(data.params.sel_option == SRC_SelectPrefer ? REQ_ADDSRC_PREFER : 0) |
(data.params.sel_option == SRC_SelectNoselect ? REQ_ADDSRC_NOSELECT : 0));
result = 1;
break;
@@ -934,6 +1021,9 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
case CPS_BadPresend:
fprintf(stderr, "Unreadable presend value\n");
break;
case CPS_BadMaxdelaydevratio:
fprintf(stderr, "Unreadable max delay dev ratio value\n");
break;
case CPS_BadMaxdelayratio:
fprintf(stderr, "Unreadable max delay ratio value\n");
break;
@@ -943,6 +1033,12 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
case CPS_BadKey:
fprintf(stderr, "Unreadable key value\n");
break;
case CPS_BadMinstratum:
fprintf(stderr, "Unreadable minstratum value\n");
break;
case CPS_BadPolltarget:
fprintf(stderr, "Unreadable polltarget value\n");
break;
}
return result;
@@ -981,7 +1077,7 @@ process_cmd_delete(CMD_Request *msg, char *line)
fprintf(stderr, "Invalid syntax for address\n");
ok = 0;
} else {
if (!DNS_Name2IPAddress(hostname, &address, 0)) {
if (DNS_Name2IPAddress(hostname, &address) != DNS_Success) {
fprintf(stderr, "Could not get address for hostname\n");
ok = 0;
} else {
@@ -1007,7 +1103,6 @@ process_cmd_password(CMD_Request *msg, char *line)
{
char *p, *q;
char *password;
struct timezone tz;
struct timeval now;
p = line;
@@ -1041,7 +1136,7 @@ process_cmd_password(CMD_Request *msg, char *line)
*p = 0;
}
if (gettimeofday(&now, &tz) < 0) {
if (gettimeofday(&now, NULL) < 0) {
printf("500 - Could not read time of day\n");
return 0;
} else {
@@ -1123,12 +1218,16 @@ give_help(void)
printf("manual list : Show previous settime entries\n");
printf("maxdelay <address> <new-max-delay> : Modify maximum round-trip valid sample delay for source\n");
printf("maxdelayratio <address> <new-max-ratio> : Modify max round-trip delay ratio for source\n");
printf("maxpoll <address> <new-minpoll> : Modify maximum polling interval of source\n");
printf("maxdelaydevratio <address> <new-max-ratio> : Modify max round-trip delay dev ratio for source\n");
printf("maxpoll <address> <new-maxpoll> : Modify maximum polling interval of source\n");
printf("maxupdateskew <new-max-skew> : Modify maximum skew for a clock frequency update to be made\n");
printf("minpoll <address> <new-minpoll> : Modify minimum polling interval of source\n");
printf("minstratum <address> <new-min-stratum> : Modify minimum stratum of source\n");
printf("offline [<mask>/<masked-address>] : Set sources in subnet to offline status\n");
printf("online [<mask>/<masked-address>] : Set sources in subnet to online status\n");
printf("password [<new-password>] : Set command authentication password\n");
printf("polltarget <address> <new-poll-target> : Modify poll target of source\n");
printf("reselect : Reselect synchronisation source\n");
printf("rtcdata : Print current RTC performance parameters\n");
printf("settime <date/time (e.g. Nov 21, 1997 16:30:05 or 16:30:05)> : Manually set the daemon time\n");
printf("sources [-v] : Display information about current sources\n");
@@ -1139,6 +1238,8 @@ give_help(void)
printf("\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");
printf("retries <n> : Set maximum number of retries\n");
printf("exit|quit : Leave the program\n");
printf("help : Generate this help\n");
printf("\n");
@@ -1150,8 +1251,8 @@ static unsigned long sequence = 0;
static unsigned long utoken = 0;
static unsigned long token = 0;
#define MAX_ATTEMPTS 5
static int max_retries = 2;
static int initial_timeout = 1000;
/* This is the core protocol module. Complete particular fields in
the outgoing packet, send it, wait for a response, handle retries,
@@ -1170,8 +1271,8 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
int read_length;
int expected_length;
int command_length;
struct timeval timeout;
int timeout_seconds;
struct timeval tv;
int timeout;
int n_attempts;
fd_set rdfd, wrfd, exfd;
@@ -1185,8 +1286,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
request->utoken = htonl(utoken);
request->token = htonl(token);
timeout_seconds = 2;
timeout = initial_timeout;
n_attempts = 0;
@@ -1205,6 +1305,8 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
}
command_length = PKL_CommandLength(request);
assert(command_length > 0);
#if 0
printf("Sent command length=%d bytes\n", command_length);
#endif
@@ -1222,17 +1324,17 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
/* Increment this for next time */
++ request->attempt;
timeout.tv_sec = timeout_seconds;
timeout.tv_usec = 0;
tv.tv_sec = timeout / 1000;
tv.tv_usec = timeout % 1000 * 1000;
timeout *= 2;
timeout_seconds += 1;
FD_ZERO(&rdfd);
FD_ZERO(&wrfd);
FD_ZERO(&exfd);
FD_SET(sock_fd, &rdfd);
select_status = select(sock_fd + 1, &rdfd, &wrfd, &exfd, &timeout);
select_status = select(sock_fd + 1, &rdfd, &wrfd, &exfd, &tv);
if (select_status < 0) {
#if 0
@@ -1241,7 +1343,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
} else if (select_status == 0) {
/* Timeout must have elapsed, try a resend? */
n_attempts ++;
if (n_attempts == MAX_ATTEMPTS) {
if (n_attempts > max_retries) {
return 0;
}
@@ -1264,7 +1366,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
going to a dead port - but only if the daemon machine is
running Linux (Solaris doesn't return anything) */
n_attempts++;
if (n_attempts == MAX_ATTEMPTS) {
if (n_attempts > max_retries) {
return 0;
}
} else {
@@ -1293,7 +1395,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
if (bad_length || bad_sender || bad_sequence) {
n_attempts++;
if (n_attempts == MAX_ATTEMPTS) {
if (n_attempts > max_retries) {
return 0;
}
continue;
@@ -1309,7 +1411,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
if (bad_header) {
n_attempts++;
if (n_attempts == MAX_ATTEMPTS) {
if (n_attempts > max_retries) {
return 0;
}
continue;
@@ -1483,21 +1585,26 @@ print_seconds(unsigned long s)
static void
print_nanoseconds(double s)
{
unsigned long ms, ns;
s = fabs(s);
ns = s * 1e9 + 0.5;
ms = s * 1e3 + 0.5;
if (ns <= 9999) {
printf("%4ldns", ns);
} else if (ns <= 9999499) {
printf("%4ldus", (ns + 500) / 1000);
} else if (ms <= 9999) {
printf("%4ldms", ms);
} else if (ms <= 999949) {
printf("%3ld.%01lds", (ms + 50) / 1000, ((ms + 50) / 100) % 10);
if (s < 9999.5e-9) {
printf("%4.0fns", s * 1e9);
} else if (s < 9999.5e-6) {
printf("%4.0fus", s * 1e6);
} else if (s < 9999.5e-3) {
printf("%4.0fms", s * 1e3);
} else if (s < 999.5) {
printf("%5.1fs", s);
} else if (s < 99999.5) {
printf("%5.0fs", s);
} else if (s < 99999.5 * 60) {
printf("%5.0fm", s / 60);
} else if (s < 99999.5 * 3600) {
printf("%5.0fh", s / 3600);
} else if (s < 99999.5 * 3600 * 24) {
printf("%5.0fd", s / (3600 * 24));
} else {
printf("%5lds", (ms + 500) / 1000);
printf("%5.0fy", s / (3600 * 24 * 365));
}
}
@@ -1506,26 +1613,40 @@ print_nanoseconds(double s)
static void
print_signed_nanoseconds(double s)
{
long ms, ns, sign;
double x;
if (s >= 0.0) {
ns = s * 1e9 + 0.5;
ms = s * 1e3 + 0.5;
sign = 1;
x = fabs(s);
if (x < 9999.5e-9) {
printf("%+5.0fns", s * 1e9);
} else if (x < 9999.5e-6) {
printf("%+5.0fus", s * 1e6);
} else if (x < 9999.5e-3) {
printf("%+5.0fms", s * 1e3);
} else if (x < 999.5) {
printf("%+6.1fs", s);
} else if (x < 99999.5) {
printf("%+6.0fs", s);
} else if (x < 99999.5 * 60) {
printf("%+6.0fm", s / 60);
} else if (x < 99999.5 * 3600) {
printf("%+6.0fh", s / 3600);
} else if (x < 99999.5 * 3600 * 24) {
printf("%+6.0fd", s / (3600 * 24));
} else {
ns = -s * 1e9 + 0.5;
ms = -s * 1e3 + 0.5;
sign = -1;
printf("%+6.0fy", s / (3600 * 24 * 365));
}
}
if (ns <= 9999) {
printf("%+5ldns", ns * sign);
} else if (ns <= 9999499) {
printf("%+5ldus", (ns + 500) / 1000 * sign);
} else if (ms <= 9999) {
printf("%+5ldms", ms * sign);
/* ================================================== */
static void
print_freq_ppm(double f)
{
if (fabs(f) < 99999.5) {
printf("%10.3f", f);
} else {
printf("%+6lds", (ms + 500) / 1000 * sign);
printf("%10.0f", f);
}
}
@@ -1614,6 +1735,8 @@ process_cmd_sources(char *line)
printf("="); break;
case RPY_SD_MD_REF:
printf("#"); break;
default:
printf(" ");
}
switch (state) {
case RPY_SD_ST_SYNC:
@@ -1624,8 +1747,12 @@ process_cmd_sources(char *line)
printf("x"); break;
case RPY_SD_ST_JITTERY:
printf("~"); break;
case RPY_SD_ST_OTHER:
case RPY_SD_ST_CANDIDATE:
printf("+"); break;
case RPY_SD_ST_OUTLYER:
printf("-"); break;
default:
printf(" ");
}
printf(" %-25s %2d %2d ", hostname_buf, stratum, poll);
@@ -1711,9 +1838,13 @@ process_cmd_sourcestats(char *line)
hostname_buf[25] = 0;
}
printf("%-25s %2lu %2lu ", hostname_buf, n_samples, n_runs);
printf("%-25s %3lu %3lu ", hostname_buf, n_samples, n_runs);
print_seconds(span_seconds);
printf(" %10.3f %10.3f ", resid_freq_ppm, skew_ppm);
printf(" ");
print_freq_ppm(resid_freq_ppm);
printf(" ");
print_freq_ppm(skew_ppm);
printf(" ");
print_signed_nanoseconds(est_offset);
printf(" ");
print_nanoseconds(sd);
@@ -2246,6 +2377,14 @@ process_cmd_activity(const char *line)
/* ================================================== */
static void
process_cmd_reselect(CMD_Request *msg, char *line)
{
msg->command = htons(REQ_RESELECT);
}
/* ================================================== */
static int
process_cmd_dns(const char *line)
{
@@ -2268,6 +2407,38 @@ process_cmd_dns(const char *line)
/* ================================================== */
static int
process_cmd_timeout(const char *line)
{
int timeout;
timeout = atoi(line);
if (timeout < 100) {
fprintf(stderr, "Timeout %d is too short\n", timeout);
return 0;
}
initial_timeout = timeout;
return 1;
}
/* ================================================== */
static int
process_cmd_retries(const char *line)
{
int retries;
retries = atoi(line);
if (retries < 0) {
fprintf(stderr, "Invalid maximum number of retries\n");
return 0;
}
max_retries = retries;
return 1;
}
/* ================================================== */
static int
process_line(char *line, int *quit)
{
@@ -2305,12 +2476,18 @@ process_line(char *line, int *quit)
do_normal_submit = process_cmd_maxpoll(&tx_message, p+7);
} else if (!strncmp(p, "dump", 4)) {
process_cmd_dump(&tx_message, p+4);
} else if (!strncmp(p, "maxdelaydevratio", 16)) {
do_normal_submit = process_cmd_maxdelaydevratio(&tx_message, p+16);
} else if (!strncmp(p, "maxdelayratio", 13)) {
do_normal_submit = process_cmd_maxdelayratio(&tx_message, p+13);
} else if (!strncmp(p, "maxdelay", 8)) {
do_normal_submit = process_cmd_maxdelay(&tx_message, p+8);
} else if (!strncmp(p, "maxupdateskew", 13)) {
do_normal_submit = process_cmd_maxupdateskew(&tx_message, p+13);
} else if (!strncmp(p, "minstratum", 10)) {
do_normal_submit = process_cmd_minstratum(&tx_message, p+10);
} else if (!strncmp(p, "polltarget", 10)) {
do_normal_submit = process_cmd_polltarget(&tx_message, p+10);
} else if (!strncmp(p, "settime", 7)) {
do_normal_submit = 0;
ret = process_cmd_settime(p+7);
@@ -2381,9 +2558,17 @@ 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, "reselect", 8)) {
process_cmd_reselect(&tx_message, p+8);
} else if (!strncmp(p, "dns ", 4)) {
ret = process_cmd_dns(p+4);
do_normal_submit = 0;
} else if (!strncmp(p, "timeout", 7)) {
ret = process_cmd_timeout(p+7);
do_normal_submit = 0;
} else if (!strncmp(p, "retries", 7)) {
ret = process_cmd_retries(p+7);
do_normal_submit = 0;
} else if (!strncmp(p, "help", 4)) {
do_normal_submit = 0;
give_help();
@@ -2412,7 +2597,7 @@ process_line(char *line, int *quit)
/* ================================================== */
static int
process_args(int argc, char **argv)
process_args(int argc, char **argv, int multi)
{
int total_length, i, ret, quit;
char *line;
@@ -2423,15 +2608,25 @@ process_args(int argc, char **argv)
}
line = (char *) malloc((2 + total_length) * sizeof(char));
line[0] = 0;
for (i = 0; i < argc; i++) {
line[0] = '\0';
if (multi) {
strcat(line, argv[i]);
} else {
for (; i < argc; i++) {
strcat(line, argv[i]);
if (i + 1 < argc)
strcat(line, " ");
}
}
strcat(line, "\n");
ret = process_line(line, &quit);
if (!ret)
break;
}
free(line);
@@ -2459,7 +2654,7 @@ main(int argc, char **argv)
char *line;
const char *progname = argv[0];
const char *hostname = "localhost";
int quit = 0, ret = 1;
int quit = 0, ret = 1, multi = 0;
int port = DEFAULT_CANDM_PORT;
/* Parse command line options */
@@ -2474,6 +2669,8 @@ main(int argc, char **argv)
if (*argv) {
port = atoi(*argv);
}
} else if (!strcmp(*argv, "-m")) {
multi = 1;
} else if (!strcmp(*argv, "-n")) {
no_dns = 1;
} else if (!strcmp(*argv, "-4")) {
@@ -2486,7 +2683,7 @@ main(int argc, char **argv)
printf("chronyc (chrony) version %s\n", PROGRAM_VERSION_STRING);
exit(0);
} else if (!strncmp(*argv, "-", 1)) {
fprintf(stderr, "Usage : %s [-h <hostname>] [-p <port-number>] [-n] [-4|-6] [command]\n", progname);
fprintf(stderr, "Usage : %s [-h <hostname>] [-p <port-number>] [-n] [-4|-6] [-m] [command]\n", progname);
exit(1);
} else {
break; /* And process remainder of line as a command */
@@ -2504,7 +2701,7 @@ main(int argc, char **argv)
open_io(hostname, port);
if (argc > 0) {
ret = process_args(argc, argv);
ret = process_args(argc, argv, multi);
} else {
do {
line = read_line();

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/clientlog.c,v 1.11 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/clientlog.h,v 1.9 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

230
cmdmon.c
View File

@@ -1,13 +1,9 @@
/*
$Header: /cvs/src/chrony/cmdmon.c,v 1.55 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009
* Copyright (C) Miroslav Lichvar 2009-2011
*
* 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
@@ -152,13 +148,17 @@ static int permissions[] = {
PERMIT_OPEN, /* RTCREPORT */
PERMIT_AUTH, /* TRIMRTC */
PERMIT_AUTH, /* CYCLELOGS */
PERMIT_OPEN, /* SUBNETS_ACCESSED */
PERMIT_OPEN, /* CLIENT_ACCESSES (by subnet) */
PERMIT_OPEN, /* CLIENT_ACCESSES_BY_INDEX */
PERMIT_AUTH, /* SUBNETS_ACCESSED */
PERMIT_AUTH, /* CLIENT_ACCESSES (by subnet) */
PERMIT_AUTH, /* CLIENT_ACCESSES_BY_INDEX */
PERMIT_OPEN, /* MANUAL_LIST */
PERMIT_AUTH, /* MANUAL_DELETE */
PERMIT_AUTH, /* MAKESTEP */
PERMIT_OPEN /* ACTIVITY */
PERMIT_OPEN, /* ACTIVITY */
PERMIT_AUTH, /* MODIFY_MINSTRATUM */
PERMIT_AUTH, /* MODIFY_POLLTARGET */
PERMIT_AUTH, /* MODIFY_MAXDELAYDEVRATIO */
PERMIT_AUTH /* RESELECT */
};
/* ================================================== */
@@ -195,6 +195,9 @@ prepare_socket(int family)
return -1;
}
/* Close on exec */
UTI_FdSetCloexec(sock_fd);
/* Allow reuse of port number */
if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on_off, sizeof(on_off)) < 0) {
LOG(LOGS_ERR, LOGF_CmdMon, "Could not set reuseaddr socket options");
@@ -261,16 +264,10 @@ prepare_socket(int family)
void
CAM_Initialise(void)
{
if (initialised) {
CROAK("Shouldn't be initialised");
}
assert(!initialised);
initialised = 1;
if ((sizeof(permissions)/sizeof(permissions[0])) != N_REQUEST_TYPES) {
CROAK("Permissions table size wrong");
}
assert(sizeof (permissions) / sizeof (permissions[0]) == N_REQUEST_TYPES);
utoken = (unsigned long) time(NULL);
@@ -908,6 +905,59 @@ handle_modify_maxdelayratio(CMD_Request *rx_message, CMD_Reply *tx_message)
/* ================================================== */
static void
handle_modify_maxdelaydevratio(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_maxdelaydevratio.address, &address);
status = NSR_ModifyMaxdelaydevratio(&address,
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelaydevratio.new_max_delay_dev_ratio));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
static void
handle_modify_minstratum(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_minpoll.address, &address);
status = NSR_ModifyMinstratum(&address,
ntohl(rx_message->data.modify_minstratum.new_min_stratum));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
static void
handle_modify_polltarget(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_polltarget.address, &address);
status = NSR_ModifyPolltarget(&address,
ntohl(rx_message->data.modify_polltarget.new_poll_target));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
static void
handle_modify_maxupdateskew(CMD_Request *rx_message, CMD_Reply *tx_message)
{
@@ -991,10 +1041,9 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
{
RPT_SourceReport report;
struct timeval now_corr;
double local_clock_err;
/* Get data */
LCL_ReadCookedTime(&now_corr, &local_clock_err);
LCL_ReadCookedTime(&now_corr, NULL);
if (SRC_ReportSource(ntohl(rx_message->data.source_data.index), &report, &now_corr)) {
switch (SRC_GetType(ntohl(rx_message->data.source_data.index))) {
case SRC_NTP:
@@ -1024,8 +1073,8 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
case RPT_JITTERY:
tx_message->data.source_data.state = htons(RPY_SD_ST_JITTERY);
break;
case RPT_OTHER:
tx_message->data.source_data.state = htons(RPY_SD_ST_OTHER);
case RPT_CANDIDATE:
tx_message->data.source_data.state = htons(RPY_SD_ST_CANDIDATE);
break;
}
switch (report.mode) {
@@ -1216,7 +1265,7 @@ handle_cmdaccheck(CMD_Request *rx_message, CMD_Reply *tx_message)
/* ================================================== */
static void
handle_add_server(CMD_Request *rx_message, CMD_Reply *tx_message)
handle_add_source(NTP_Source_Type type, CMD_Request *rx_message, CMD_Reply *tx_message)
{
NTP_Remote_Address rem_addr;
SourceParameters params;
@@ -1231,9 +1280,18 @@ handle_add_server(CMD_Request *rx_message, CMD_Reply *tx_message)
params.authkey = ntohl(rx_message->data.ntp_source.authkey);
params.online = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_ONLINE ? 1 : 0;
params.auto_offline = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_AUTOOFFLINE ? 1 : 0;
params.iburst = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_IBURST ? 1 : 0;
params.sel_option = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_PREFER ? SRC_SelectPrefer :
ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_NOSELECT ? SRC_SelectNoselect : SRC_SelectNormal;
params.max_delay = UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay);
params.max_delay_ratio = UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay_ratio);
status = NSR_AddServer(&rem_addr, &params);
/* not transmitted in cmdmon protocol yet */
params.min_stratum = SRC_DEFAULT_MINSTRATUM;
params.poll_target = SRC_DEFAULT_POLLTARGET;
params.max_delay_dev_ratio = SRC_DEFAULT_MAXDELAYDEVRATIO;
status = NSR_AddSource(&rem_addr, type, &params);
switch (status) {
case NSR_Success:
tx_message->status = htons(STT_SUCCESS);
@@ -1248,47 +1306,7 @@ handle_add_server(CMD_Request *rx_message, CMD_Reply *tx_message)
tx_message->status = htons(STT_INVALIDAF);
break;
case NSR_NoSuchSource:
CROAK("Impossible");
break;
}
}
/* ================================================== */
static void
handle_add_peer(CMD_Request *rx_message, CMD_Reply *tx_message)
{
NTP_Remote_Address rem_addr;
SourceParameters params;
NSR_Status status;
UTI_IPNetworkToHost(&rx_message->data.ntp_source.ip_addr, &rem_addr.ip_addr);
rem_addr.local_ip_addr.family = IPADDR_UNSPEC;
rem_addr.port = (unsigned short)(ntohl(rx_message->data.ntp_source.port));
params.minpoll = ntohl(rx_message->data.ntp_source.minpoll);
params.maxpoll = ntohl(rx_message->data.ntp_source.maxpoll);
params.presend_minpoll = ntohl(rx_message->data.ntp_source.presend_minpoll);
params.authkey = ntohl(rx_message->data.ntp_source.authkey);
params.online = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_ONLINE ? 1 : 0;
params.auto_offline = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_AUTOOFFLINE ? 1 : 0;
params.max_delay = UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay);
params.max_delay_ratio = UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay_ratio);
status = NSR_AddPeer(&rem_addr, &params);
switch (status) {
case NSR_Success:
tx_message->status = htons(STT_SUCCESS);
break;
case NSR_AlreadyInUse:
tx_message->status = htons(STT_SOURCEALREADYKNOWN);
break;
case NSR_TooManySources:
tx_message->status = htons(STT_TOOMANYSOURCES);
break;
case NSR_InvalidAF:
tx_message->status = htons(STT_INVALIDAF);
break;
case NSR_NoSuchSource:
CROAK("Impossible");
assert(0);
break;
}
}
@@ -1316,7 +1334,7 @@ handle_del_source(CMD_Request *rx_message, CMD_Reply *tx_message)
case NSR_TooManySources:
case NSR_AlreadyInUse:
case NSR_InvalidAF:
CROAK("Impossible");
assert(0);
break;
}
}
@@ -1348,6 +1366,7 @@ handle_dfreq(CMD_Request *rx_message, CMD_Reply *tx_message)
dfreq = UTI_FloatNetworkToHost(rx_message->data.dfreq.dfreq);
LCL_AccumulateDeltaFrequency(dfreq * 1.0e-6);
LOG(LOGS_INFO, LOGF_CmdMon, "Accumulated delta freq of %.3fppm", dfreq);
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -1362,6 +1381,7 @@ handle_doffset(CMD_Request *rx_message, CMD_Reply *tx_message)
doffset = (double) sec + 1.0e-6 * (double) usec;
LOG(LOGS_INFO, LOGF_CmdMon, "Accumulated delta offset of %.6f seconds", doffset);
LCL_AccumulateOffset(doffset);
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -1394,9 +1414,8 @@ handle_sourcestats(CMD_Request *rx_message, CMD_Reply *tx_message)
int status;
RPT_SourcestatsReport report;
struct timeval now_corr;
double local_clock_err;
LCL_ReadCookedTime(&now_corr, &local_clock_err);
LCL_ReadCookedTime(&now_corr, NULL);
status = SRC_ReportSourcestats(ntohl(rx_message->data.sourcestats.index),
&report, &now_corr);
@@ -1461,11 +1480,7 @@ handle_trimrtc(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_cyclelogs(CMD_Request *rx_message, CMD_Reply *tx_message)
{
NCR_CycleLogFile();
SST_CycleLogFile();
REF_CycleLogFile();
RTC_CycleLogFile();
RCL_CycleLogFile();
LOG_CycleLogFiles();
tx_message->status = htons(STT_SUCCESS);
return;
@@ -1512,7 +1527,7 @@ handle_subnets_accessed(CMD_Request *rx_message, CMD_Reply *tx_message)
tx_message->status = htons(STT_INACTIVE);
return;
default:
CROAK("Impossible");
assert(0);
break;
}
}
@@ -1531,9 +1546,8 @@ handle_client_accesses(CMD_Request *rx_message, CMD_Reply *tx_message)
IPAddr ip;
int i;
struct timeval now;
double local_time_error;
LCL_ReadCookedTime(&now, &local_time_error);
LCL_ReadCookedTime(&now, NULL);
nc = ntohl(rx_message->data.client_accesses.n_clients);
tx_message->status = htons(STT_SUCCESS);
@@ -1568,7 +1582,7 @@ handle_client_accesses(CMD_Request *rx_message, CMD_Reply *tx_message)
tx_message->status = htons(STT_INACTIVE);
return;
default:
CROAK("Impossible");
assert(0);
break;
}
}
@@ -1585,9 +1599,8 @@ handle_client_accesses_by_index(CMD_Request *rx_message, CMD_Reply *tx_message)
unsigned long first_index, n_indices, last_index, n_indices_in_table;
int i, j;
struct timeval now;
double local_time_error;
LCL_ReadCookedTime(&now, &local_time_error);
LCL_ReadCookedTime(&now, NULL);
first_index = ntohl(rx_message->data.client_accesses_by_index.first_index);
n_indices = ntohl(rx_message->data.client_accesses_by_index.n_indices);
@@ -1621,7 +1634,7 @@ handle_client_accesses_by_index(CMD_Request *rx_message, CMD_Reply *tx_message)
tx_message->status = htons(STT_INACTIVE);
return;
default:
CROAK("Impossible");
assert(0);
break;
}
}
@@ -1698,6 +1711,16 @@ handle_activity(CMD_Request *rx_message, CMD_Reply *tx_message)
/* ================================================== */
static void
handle_reselect(CMD_Request *rx_message, CMD_Reply *tx_message)
{
SRC_ReselectSource();
tx_message->status = htons(STT_SUCCESS);
return;
}
/* ================================================== */
#if 0
/* ================================================== */
@@ -1742,7 +1765,6 @@ read_from_cmd_socket(void *anything)
unsigned long rx_attempt;
struct timeval now;
struct timeval cooked_now;
double local_clock_err;
flags = 0;
rx_message_length = sizeof(rx_message);
@@ -1760,9 +1782,10 @@ read_from_cmd_socket(void *anything)
read_length = status;
expected_length = PKL_CommandLength(&rx_message);
rx_command = ntohs(rx_message.command);
LCL_ReadRawTime(&now);
LCL_ReadCookedTime(&cooked_now, &local_clock_err);
LCL_CookTime(&now, &cooked_now, NULL);
tx_message.version = PROTO_VERSION_NUMBER;
tx_message.pkt_type = PKT_TYPE_CMD_REPLY;
@@ -1822,7 +1845,7 @@ read_from_cmd_socket(void *anything)
if (rx_message.version != PROTO_VERSION_NUMBER) {
tx_message.status = htons(STT_NOHOSTACCESS);
if (!LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_CmdMon, "Read packet with protocol version %d (expected %d) from %s:%hu", rx_message.version, PROTO_VERSION_NUMBER, UTI_IPToString(&remote_ip), remote_port);
LOG(LOGS_WARN, LOGF_CmdMon, "Read command packet with protocol version %d (expected %d) from %s:%hu", rx_message.version, PROTO_VERSION_NUMBER, UTI_IPToString(&remote_ip), remote_port);
}
if (allowed)
CLG_LogCommandAccess(&remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec);
@@ -1834,9 +1857,21 @@ read_from_cmd_socket(void *anything)
return;
}
if (rx_command >= N_REQUEST_TYPES) {
if (!LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_CmdMon, "Read command packet with invalid command %d from %s:%hu", rx_command, UTI_IPToString(&remote_ip), remote_port);
}
if (allowed)
CLG_LogCommandAccess(&remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec);
tx_message.status = htons(STT_INVALID);
transmit_reply(&tx_message, &where_from);
return;
}
if (read_length != expected_length) {
if (!LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_CmdMon, "Read incorrectly sized packet from %s:%hu", UTI_IPToString(&remote_ip), remote_port);
LOG(LOGS_WARN, LOGF_CmdMon, "Read incorrectly sized command packet from %s:%hu", UTI_IPToString(&remote_ip), remote_port);
}
if (allowed)
CLG_LogCommandAccess(&remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec);
@@ -1864,8 +1899,6 @@ read_from_cmd_socket(void *anything)
return;
}
rx_command = ntohs(rx_message.command);
/* OK, we have a valid message. Now dispatch on message type and process it. */
/* Do authentication stuff and command tokens here. Well-behaved
@@ -1991,10 +2024,9 @@ read_from_cmd_socket(void *anything)
tx_message.token = htonl(tx_message_token);
/* If command type is invalid, send back reply */
if (rx_command >= N_REQUEST_TYPES) {
tx_message.status = htons(STT_INVALID);
tx_message.reply = htons(RPY_NULL);
/* This should be already handled */
assert(0);
} else {
allowed = 0;
@@ -2018,7 +2050,7 @@ read_from_cmd_socket(void *anything)
allowed = 1;
break;
default:
CROAK("Impossible");
assert(0);
}
if (allowed) {
@@ -2060,6 +2092,10 @@ read_from_cmd_socket(void *anything)
handle_modify_maxdelayratio(&rx_message, &tx_message);
break;
case REQ_MODIFY_MAXDELAYDEVRATIO:
handle_modify_maxdelaydevratio(&rx_message, &tx_message);
break;
case REQ_MODIFY_MAXUPDATESKEW:
handle_modify_maxupdateskew(&rx_message, &tx_message);
break;
@@ -2151,11 +2187,11 @@ read_from_cmd_socket(void *anything)
break;
case REQ_ADD_SERVER:
handle_add_server(&rx_message, &tx_message);
handle_add_source(NTP_SERVER, &rx_message, &tx_message);
break;
case REQ_ADD_PEER:
handle_add_peer(&rx_message, &tx_message);
handle_add_source(NTP_PEER, &rx_message, &tx_message);
break;
case REQ_DEL_SOURCE:
@@ -2222,6 +2258,18 @@ read_from_cmd_socket(void *anything)
handle_activity(&rx_message, &tx_message);
break;
case REQ_RESELECT:
handle_reselect(&rx_message, &tx_message);
break;
case REQ_MODIFY_MINSTRATUM:
handle_modify_minstratum(&rx_message, &tx_message);
break;
case REQ_MODIFY_POLLTARGET:
handle_modify_polltarget(&rx_message, &tx_message);
break;
default:
/* Ignore message */
break;

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/cmdmon.h,v 1.8 2002/02/28 23:27:09 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/cmdparse.c,v 1.12 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -33,6 +29,7 @@
#include "sysincl.h"
#include "cmdparse.h"
#include "memory.h"
#include "nameserv.h"
#define MAXLEN 2047
@@ -46,23 +43,34 @@ 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 = 123;
src->params.minpoll = 6;
src->params.maxpoll = 10;
src->params.presend_minpoll = 0;
src->port = SRC_DEFAULT_PORT;
src->params.minpoll = SRC_DEFAULT_MINPOLL;
src->params.maxpoll = SRC_DEFAULT_MAXPOLL;
src->params.presend_minpoll = SRC_DEFAULT_PRESEND_MINPOLL;
src->params.authkey = INACTIVE_AUTHKEY;
src->params.max_delay = 16.0;
src->params.max_delay_ratio = 16384.0;
src->params.max_delay = SRC_DEFAULT_MAXDELAY;
src->params.max_delay_ratio = SRC_DEFAULT_MAXDELAYRATIO;
src->params.max_delay_dev_ratio = SRC_DEFAULT_MAXDELAYDEVRATIO;
src->params.online = 1;
src->params.auto_offline = 0;
src->params.iburst = 0;
src->params.min_stratum = SRC_DEFAULT_MINSTRATUM;
src->params.poll_target = SRC_DEFAULT_POLLTARGET;
src->params.sel_option = SRC_SelectNormal;
result = CPS_Success;
ok = 0;
if (sscanf(line, "%" SMAXLEN "s%n", hostname, &n) == 1) {
if (DNS_Name2IPAddress(hostname, &src->ip_addr, 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;
}
}
@@ -112,6 +120,14 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
} else {
line += n;
}
} else if (!strncasecmp(cmd, "maxdelaydevratio", 16)) {
if (sscanf(line, "%lf%n", &src->params.max_delay_dev_ratio, &n) != 1) {
result = CPS_BadMaxdelaydevratio;
ok = 0;
done = 1;
} else {
line += n;
}
/* This MUST come before the following one ! */
} else if (!strncasecmp(cmd, "maxdelayratio", 13)) {
if (sscanf(line, "%lf%n", &src->params.max_delay_ratio, &n) != 1) {
@@ -143,6 +159,33 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
} else if (!strncasecmp(cmd, "auto_offline", 12)) {
src->params.auto_offline = 1;
} else if (!strncasecmp(cmd, "iburst", 6)) {
src->params.iburst = 1;
} else if (!strncasecmp(cmd, "minstratum", 10)) {
if (sscanf(line, "%d%n", &src->params.min_stratum, &n) != 1) {
result = CPS_BadMinstratum;
ok = 0;
done = 1;
} else {
line += n;
}
} else if (!strncasecmp(cmd, "polltarget", 10)) {
if (sscanf(line, "%d%n", &src->params.poll_target, &n) != 1) {
result = CPS_BadPolltarget;
ok = 0;
done = 1;
} else {
line += n;
}
} else if (!strncasecmp(cmd, "noselect", 8)) {
src->params.sel_option = SRC_SelectNoselect;
} else if (!strncasecmp(cmd, "prefer", 6)) {
src->params.sel_option = SRC_SelectPrefer;
} else {
result = CPS_BadOption;
ok = 0;
@@ -154,6 +197,13 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
} while (!done);
}
if (ok && src->ip_addr.family == IPADDR_UNSPEC) {
n = strlen(hostname);
src->name = MallocArray(char, n + 1);
strncpy(src->name, hostname, n);
src->name[n] = '\0';
}
return result;
}

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/cmdparse.h,v 1.7 2002/02/28 23:27:09 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -42,13 +38,17 @@ typedef enum {
CPS_BadMinpoll,
CPS_BadMaxpoll,
CPS_BadPresend,
CPS_BadMaxdelaydevratio,
CPS_BadMaxdelayratio,
CPS_BadMaxdelay,
CPS_BadKey
CPS_BadKey,
CPS_BadMinstratum,
CPS_BadPolltarget
} CPS_Status;
typedef struct {
IPAddr ip_addr;
char *name;
unsigned short port;
SourceParameters params;
} CPS_NTP_Source;

277
conf.c
View File

@@ -1,13 +1,9 @@
/*
$Header: /cvs/src/chrony/conf.c,v 1.45 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009
* Copyright (C) Miroslav Lichvar 2009-2011
*
* 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
@@ -74,8 +70,12 @@ static void parse_dumponexit(const char *);
static void parse_keyfile(const char *);
static void parse_rtcfile(const char *);
static void parse_log(const char *);
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_reselectdist(const char *);
static void parse_stratumweight(const char *);
static void parse_peer(const char *);
static void parse_acquisitionport(const char *);
static void parse_port(const char *);
@@ -90,8 +90,10 @@ static void parse_cmdallow(const char *);
static void parse_cmddeny(const char *);
static void parse_cmdport(const char *);
static void parse_rtconutc(const char *);
static void parse_rtcsync(const char *);
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_logchange(const char *);
static void parse_mailonchange(const char *);
@@ -104,6 +106,7 @@ static void parse_linux_hz(const char *);
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 *);
/* ================================================== */
/* Configuration variables */
@@ -115,7 +118,11 @@ static char *keys_file = NULL;
static char *drift_file = NULL;
static char *rtc_file = NULL;
static unsigned long command_key_id;
static double max_update_skew = DBL_MAX;
static double max_update_skew = 1000.0;
static double max_clock_error = 10; /* in ppm */
static double reselect_distance = 1e-4;
static double stratum_weight = 1.0;
static int cmd_port = -1;
@@ -124,7 +131,9 @@ static int do_log_statistics = 0;
static int do_log_tracking = 0;
static int do_log_rtc = 0;
static int do_log_refclocks = 0;
static int do_log_tempcomp = 0;
static int do_dump_on_exit = 0;
static int log_banner = 32;
static char *logdir = ".";
static char *dumpdir = ".";
@@ -147,6 +156,9 @@ static int enable_manual=0;
incl. daylight saving). */
static int rtc_on_utc = 0;
/* Flag set if the RTC should be automatically synchronised by kernel */
static int rtc_sync = 0;
/* Limit and threshold for clock stepping */
static int make_step_limit = 0;
static double make_step_threshold = 0.0;
@@ -166,6 +178,10 @@ static int no_client_log = 0;
/* Limit memory allocated for the clients log */
static unsigned long client_log_limit = 524288;
/* Minimum and maximum fallback drift intervals */
static int fb_drift_min = 0;
static int fb_drift_max = 0;
/* IP addresses for binding the NTP socket to. UNSPEC family means INADDR_ANY
will be used */
static IPAddr bind_address4, bind_address6;
@@ -178,6 +194,11 @@ static IPAddr bind_cmd_address4, bind_cmd_address6;
* chronyds being started. */
static char *pidfile = "/var/run/chronyd.pid";
/* Temperature sensor, update interval and compensation coefficients */
static char *tempcomp_file = NULL;
static double tempcomp_interval;
static double tempcomp_T0, tempcomp_k0, tempcomp_k1, tempcomp_k2;
/* Boolean for whether the Linux HZ value has been overridden, and the
* new value. */
static int set_linux_hz = 0;
@@ -208,11 +229,13 @@ static const Command commands[] = {
{"driftfile", 9, parse_driftfile},
{"keyfile", 7, parse_keyfile},
{"rtcfile", 7, parse_rtcfile},
{"logbanner", 9, parse_logbanner},
{"logdir", 6, parse_logdir},
{"log", 3, parse_log},
{"dumponexit", 10, parse_dumponexit},
{"dumpdir", 7, parse_dumpdir},
{"maxupdateskew", 13, parse_maxupdateskew},
{"maxclockerror", 13, parse_maxclockerror},
{"commandkey", 10, parse_commandkey},
{"initstepslew", 12, parse_initstepslew},
{"local", 5, parse_local},
@@ -223,8 +246,10 @@ static const Command commands[] = {
{"cmddeny", 7, parse_cmddeny},
{"cmdport", 7, parse_cmdport},
{"rtconutc", 8, parse_rtconutc},
{"rtcsync", 7, parse_rtcsync},
{"noclientlog", 11, parse_noclientlog},
{"clientloglimit", 14, parse_clientloglimit},
{"fallbackdrift", 13, parse_fallbackdrift},
{"makestep", 8, parse_makestep},
{"logchange", 9, parse_logchange},
{"mailonchange", 12, parse_mailonchange},
@@ -233,6 +258,9 @@ static const Command commands[] = {
{"rtcdevice", 9, parse_rtcdevice},
{"pidfile", 7, parse_pidfile},
{"broadcast", 9, parse_broadcast},
{"tempcomp", 8, parse_tempcomp},
{"reselectdist", 12, parse_reselectdist},
{"stratumweight", 13, parse_stratumweight},
{"linux_hz", 8, parse_linux_hz},
{"linux_freq_scale", 16, parse_linux_freq_scale},
{"sched_priority", 14, parse_sched_priority},
@@ -246,15 +274,9 @@ static int line_number;
/* ================================================== */
typedef enum {
SERVER, PEER
} NTP_Source_Type;
typedef struct {
NTP_Source_Type type;
IPAddr ip_addr;
unsigned short port;
SourceParameters params;
CPS_NTP_Source params;
} NTP_Source;
#define MAX_NTP_SOURCES 64
@@ -345,23 +367,14 @@ CNF_ReadFile(const char *filename)
static void
parse_source(const char *line, NTP_Source_Type type)
{
int i;
NTP_Source s;
CPS_Status status;
CPS_NTP_Source params;
s.type = type;
status = CPS_ParseNTPSourceAdd(line, &params);
ntp_sources[n_ntp_sources].type = type;
status = CPS_ParseNTPSourceAdd(line, &ntp_sources[n_ntp_sources].params);
switch (status) {
case CPS_Success:
s.port = params.port;
s.ip_addr = params.ip_addr;
s.params = params.params;
i = n_ntp_sources++;
ntp_sources[i] = s;
n_ntp_sources++;
break;
case CPS_BadOption:
LOG(LOGS_WARN, LOGF_Configure, "Unrecognized subcommand at line %d", line_number);
@@ -381,6 +394,9 @@ parse_source(const char *line, NTP_Source_Type type)
case CPS_BadPresend:
LOG(LOGS_WARN, LOGF_Configure, "Unreadable presend value at line %d", line_number);
break;
case CPS_BadMaxdelaydevratio:
LOG(LOGS_WARN, LOGF_Configure, "Unreadable max delay dev ratio value at line %d", line_number);
break;
case CPS_BadMaxdelayratio:
LOG(LOGS_WARN, LOGF_Configure, "Unreadable max delay ratio value at line %d", line_number);
break;
@@ -390,6 +406,12 @@ parse_source(const char *line, NTP_Source_Type type)
case CPS_BadKey:
LOG(LOGS_WARN, LOGF_Configure, "Unreadable key value at line %d", line_number);
break;
case CPS_BadMinstratum:
LOG(LOGS_WARN, LOGF_Configure, "Unreadable minstratum value at line %d", line_number);
break;
case CPS_BadPolltarget:
LOG(LOGS_WARN, LOGF_Configure, "Unreadable polltarget value at line %d", line_number);
break;
}
return;
@@ -419,7 +441,7 @@ parse_lockall(const char *line)
static void
parse_server(const char *line)
{
parse_source(line, SERVER);
parse_source(line, NTP_SERVER);
}
/* ================================================== */
@@ -427,7 +449,7 @@ parse_server(const char *line)
static void
parse_peer(const char *line)
{
parse_source(line, PEER);
parse_source(line, NTP_PEER);
}
/* ================================================== */
@@ -437,10 +459,11 @@ parse_refclock(const char *line)
{
int i, n, poll, dpoll, filter_length, pps_rate;
unsigned long ref_id, lock_ref_id;
double offset, delay;
double offset, delay, precision;
const char *tmp;
char name[5], cmd[10 + 1], *param;
unsigned char ref[5];
SRC_SelectOption sel_option;
i = n_refclock_sources;
if (i >= MAX_RCL_SOURCES)
@@ -448,12 +471,14 @@ parse_refclock(const char *line)
poll = 4;
dpoll = 0;
filter_length = 15;
filter_length = 64;
pps_rate = 0;
offset = 0.0;
delay = 1e-9;
precision = 0.0;
ref_id = 0;
lock_ref_id = 0;
sel_option = SRC_SelectNormal;
if (sscanf(line, "%4s%n", name, &n) != 1) {
LOG(LOGS_WARN, LOGF_Configure, "Could not read refclock driver name at line %d", line_number);
@@ -507,6 +532,15 @@ parse_refclock(const char *line)
} else if (!strncasecmp(cmd, "delay", 5)) {
if (sscanf(line, "%lf%n", &delay, &n) != 1)
break;
} else if (!strncasecmp(cmd, "precision", 9)) {
if (sscanf(line, "%lf%n", &precision, &n) != 1)
break;
} else if (!strncasecmp(cmd, "noselect", 8)) {
n = 0;
sel_option = SRC_SelectNoselect;
} else if (!strncasecmp(cmd, "prefer", 6)) {
n = 0;
sel_option = SRC_SelectPrefer;
} else {
LOG(LOGS_WARN, LOGF_Configure, "Unknown refclock parameter %s at line %d", cmd, line_number);
break;
@@ -522,6 +556,8 @@ parse_refclock(const char *line)
refclock_sources[i].pps_rate = pps_rate;
refclock_sources[i].offset = offset;
refclock_sources[i].delay = delay;
refclock_sources[i].precision = precision;
refclock_sources[i].sel_option = sel_option;
refclock_sources[i].ref_id = ref_id;
refclock_sources[i].lock_ref_id = lock_ref_id;
@@ -566,6 +602,36 @@ parse_maxupdateskew(const char *line)
/* ================================================== */
static void
parse_maxclockerror(const char *line)
{
if (sscanf(line, "%lf", &max_clock_error) != 1) {
LOG(LOGS_WARN, LOGF_Configure, "Could not read max clock error at line %d in file", line_number);
}
}
/* ================================================== */
static void
parse_reselectdist(const char *line)
{
if (sscanf(line, "%lf", &reselect_distance) != 1) {
LOG(LOGS_WARN, LOGF_Configure, "Could not read reselect distance at line %d in file", line_number);
}
}
/* ================================================== */
static void
parse_stratumweight(const char *line)
{
if (sscanf(line, "%lf", &stratum_weight) != 1) {
LOG(LOGS_WARN, LOGF_Configure, "Could not read stratum weight at line %d in file", line_number);
}
}
/* ================================================== */
static void
parse_driftfile(const char *line)
{
@@ -621,6 +687,16 @@ parse_rtcdevice(const char *line)
/* ================================================== */
static void
parse_logbanner(const char *line)
{
if (sscanf(line, "%d", &log_banner) != 1) {
LOG(LOGS_WARN, LOGF_Configure, "Could not read logbanner number at line %d in file", line_number);
}
}
/* ================================================== */
static void
parse_logdir(const char *line)
{
@@ -668,6 +744,9 @@ parse_log(const char *line)
} else if (!strncmp(line, "refclocks", 9)) {
do_log_refclocks = 1;
line += 9;
} else if (!strncmp(line, "tempcomp", 8)) {
do_log_tempcomp = 1;
line += 8;
} else {
break;
}
@@ -736,7 +815,7 @@ parse_initstepslew(const char *line)
}
while (*p) {
if (sscanf(p, "%" SHOSTNAME_LEN "s%n", hostname, &n) == 1) {
if (DNS_Name2IPAddress(hostname, &ip_addr, 1)) {
if (DNS_Name2IPAddress(hostname, &ip_addr) == DNS_Success) {
init_srcs_ip[n_init_srcs] = ip_addr;
++n_init_srcs;
}
@@ -777,6 +856,14 @@ parse_rtconutc(const char *line)
/* ================================================== */
static void
parse_rtcsync(const char *line)
{
rtc_sync = 1;
}
/* ================================================== */
static void
parse_noclientlog(const char *line)
{
@@ -800,6 +887,16 @@ parse_clientloglimit(const char *line)
/* ================================================== */
static void
parse_fallbackdrift(const char *line)
{
if (sscanf(line, "%d %d", &fb_drift_min, &fb_drift_max) != 2) {
LOG(LOGS_WARN, LOGF_Configure, "Could not read fallback drift intervals at line %d", line_number);
}
}
/* ================================================== */
static void
parse_makestep(const char *line)
{
@@ -934,7 +1031,7 @@ parse_allow_deny(const char *line, AllowDeny *list, int allow)
}
} else {
if (DNS_Name2IPAddress(p, &ip_addr, 1)) {
if (DNS_Name2IPAddress(p, &ip_addr) == DNS_Success) {
new_node = MallocNew(AllowDeny);
new_node->allow = allow;
new_node->all = all;
@@ -1093,6 +1190,34 @@ parse_broadcast(const char *line)
/* ================================================== */
static void
parse_tempcomp(const char *line)
{
const char *tmp;
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 tempcomp filename at line %d", line_number);
return;
}
if (sscanf(line, "%lf %lf %lf %lf %lf", &tempcomp_interval, &tempcomp_T0, &tempcomp_k0, &tempcomp_k1, &tempcomp_k2) != 5) {
LOG(LOGS_WARN, LOGF_Configure, "Could not read tempcomp interval or coefficients at line %d", line_number);
return;
}
tempcomp_file = MallocArray(char, 1 + line - tmp);
strncpy(tempcomp_file, tmp, line - tmp);
tempcomp_file[line - tmp] = '\0';
}
/* ================================================== */
static void
parse_linux_hz(const char *line)
{
@@ -1135,20 +1260,16 @@ CNF_AddSources(void) {
int i;
for (i=0; i<n_ntp_sources; i++) {
server.ip_addr = ntp_sources[i].ip_addr;
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].port;
server.port = ntp_sources[i].params.port;
switch (ntp_sources[i].type) {
case SERVER:
NSR_AddServer(&server, &ntp_sources[i].params);
break;
case PEER:
NSR_AddPeer(&server, &ntp_sources[i].params);
break;
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);
}
}
return;
@@ -1205,6 +1326,14 @@ CNF_GetDriftFile(void)
/* ================================================== */
int
CNF_GetLogBanner(void)
{
return log_banner;
}
/* ================================================== */
char *
CNF_GetLogDir(void)
{
@@ -1252,6 +1381,7 @@ CNF_GetLogRtc(void)
}
/* ================================================== */
int
CNF_GetLogRefclocks(void)
{
@@ -1260,6 +1390,14 @@ CNF_GetLogRefclocks(void)
/* ================================================== */
int
CNF_GetLogTempComp(void)
{
return do_log_tempcomp;
}
/* ================================================== */
char *
CNF_GetKeysFile(void)
{
@@ -1308,6 +1446,30 @@ CNF_GetMaxUpdateSkew(void)
/* ================================================== */
double
CNF_GetMaxClockError(void)
{
return max_clock_error;
}
/* ================================================== */
double
CNF_GetReselectDistance(void)
{
return reselect_distance;
}
/* ================================================== */
double
CNF_GetStratumWeight(void)
{
return stratum_weight;
}
/* ================================================== */
int
CNF_GetManualEnabled(void)
{
@@ -1344,6 +1506,14 @@ CNF_GetRTCOnUTC(void)
/* ================================================== */
int
CNF_GetRTCSync(void)
{
return rtc_sync;
}
/* ================================================== */
void
CNF_GetMakeStep(int *limit, double *threshold)
{
@@ -1419,6 +1589,15 @@ CNF_GetClientLogLimit(void)
/* ================================================== */
void
CNF_GetFallbackDrifts(int *min, int *max)
{
*min = fb_drift_min;
*max = fb_drift_max;
}
/* ================================================== */
void
CNF_GetBindAddress(int family, IPAddr *addr)
{
@@ -1484,3 +1663,17 @@ CNF_GetLockMemory(void)
{
return lock_memory;
}
/* ================================================== */
void
CNF_GetTempComp(char **file, double *interval, double *T0, double *k0, double *k1, double *k2)
{
*file = tempcomp_file;
*interval = tempcomp_interval;
*T0 = tempcomp_T0;
*k0 = tempcomp_k0;
*k1 = tempcomp_k1;
*k2 = tempcomp_k2;
}

15
conf.h
View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/conf.h,v 1.25 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -48,11 +44,13 @@ extern unsigned short CNF_GetNTPPort(void);
extern char *CNF_GetDriftFile(void);
extern char *CNF_GetLogDir(void);
extern char *CNF_GetDumpDir(void);
extern int CNF_GetLogBanner(void);
extern int CNF_GetLogMeasurements(void);
extern int CNF_GetLogStatistics(void);
extern int CNF_GetLogTracking(void);
extern int CNF_GetLogRtc(void);
extern int CNF_GetLogRefclocks(void);
extern int CNF_GetLogTempComp(void);
extern char *CNF_GetKeysFile(void);
extern char *CNF_GetRtcFile(void);
extern unsigned long CNF_GetCommandKey(void);
@@ -60,11 +58,13 @@ extern int CNF_GetDumpOnExit(void);
extern int CNF_GetManualEnabled(void);
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_GetLogChange(int *enabled, double *threshold);
extern void CNF_GetMailOnChange(int *enabled, double *threshold, char **user);
extern int CNF_GetNoClientLog(void);
extern unsigned long CNF_GetClientLogLimit(void);
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);
@@ -73,6 +73,11 @@ 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_GetReselectDistance(void);
extern double CNF_GetStratumWeight(void);
extern int CNF_AllowLocalReference(int *stratum);
extern void CNF_SetupAccessRestrictions(void);
@@ -80,4 +85,6 @@ extern void CNF_SetupAccessRestrictions(void);
extern int CNF_GetSchedPriority(void);
extern int CNF_GetLockMemory(void);
extern void CNF_GetTempComp(char **file, double *interval, double *T0, double *k0, double *k1, double *k2);
#endif /* GOT_CONF_H */

6
configure vendored
View File

@@ -29,6 +29,8 @@ else
CCWARNFLAGS=""
fi
MYLDFLAGS="${LDFLAGS}"
# ======================================================================
# FUNCTIONS
@@ -51,7 +53,7 @@ test_code () {
echo "return 0; }"
) > docheck.c
${MYCC} ${MYCFLAGS} ${MYCPPFLAGS} $cflags -o docheck docheck.c $ldflags >/dev/null 2>&1
$MYCC $MYCFLAGS $MYCPPFLAGS $cflags -o docheck docheck.c $ldflags $MYLDFLAGS >/dev/null 2>&1
if [ $? -eq 0 ]
then
printf "Yes\n"
@@ -465,7 +467,7 @@ sed -e "s%@EXTRA_OBJECTS@%${EXTRA_OBJECTS}%;\
s%@CCWARNFLAGS@%${CCWARNFLAGS}%;\
s%@CPPFLAGS@%${CPPFLAGS}%;\
s%@LIBS@%${LIBS}%;\
s%@LDFLAGS@%${LDFLAGS}%;\
s%@LDFLAGS@%${MYLDFLAGS}%;\
s%@EXTRA_LIBS@%${EXTRA_LIBS}%;\
s%@SYSDEFS@%${SYSDEFS}%;\
s%@EXTRA_DEFS@%${EXTRA_DEFS}%;\

View File

@@ -1,5 +1,4 @@
#######################################################################
# $Header: /cvs/src/chrony/examples/chrony.keys.example,v 1.1 2002/01/31 00:00:08 richard Exp $
#
# This is an example chrony keys file. You should copy it to /etc/chrony.keys
# after editing it to set up the key(s) you want to use. In most situations,

4
keys.c
View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/keys.c,v 1.12 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

4
keys.h
View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/keys.h,v 1.8 2002/02/28 23:27:10 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

183
local.c
View File

@@ -1,12 +1,9 @@
/*
$Header: /cvs/src/chrony/local.c,v 1.21 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -34,6 +31,7 @@
#include <assert.h>
#include <stddef.h>
#include "conf.h"
#include "local.h"
#include "localp.h"
#include "memory.h"
@@ -45,6 +43,9 @@
/* Variable to store the current frequency, in ppm */
static double current_freq_ppm;
/* Temperature compensation, in ppm */
static double temp_comp_ppm;
/* ================================================== */
/* Store the system dependent drivers */
@@ -88,6 +89,8 @@ static DispersionNotifyListEntry dispersion_notify_list;
static int precision_log;
static double precision_quantum;
static double max_clock_error;
/* ================================================== */
/* Define the number of increments of the system clock that we want
@@ -101,16 +104,15 @@ static void
calculate_sys_precision(void)
{
struct timeval tv, old_tv, first_tv;
struct timezone tz;
int dusec, best_dusec;
int iters;
gettimeofday(&old_tv, &tz);
gettimeofday(&old_tv, NULL);
first_tv = old_tv;
best_dusec = 1000000; /* Assume we must be better than a second */
iters = 0;
do {
gettimeofday(&tv, &tz);
gettimeofday(&tv, NULL);
dusec = 1000000*(tv.tv_sec - old_tv.tv_sec) + (tv.tv_usec - old_tv.tv_usec);
old_tv = tv;
if (dusec > 0) {
@@ -120,17 +122,16 @@ calculate_sys_precision(void)
iters++;
}
} while (iters < NITERS);
if (!(best_dusec > 0)) {
CROAK("best_dusec should be positive");
}
assert(best_dusec > 0);
precision_quantum = best_dusec * 1.0e-6;
precision_log = 0;
while (best_dusec < 500000) {
precision_log--;
best_dusec *= 2;
}
precision_quantum = 1.0 / (double)(1<<(-precision_log));
return;
}
@@ -153,8 +154,11 @@ LCL_Initialise(void)
/* This ought to be set from the system driver layer */
current_freq_ppm = 0.0;
temp_comp_ppm = 0.0;
calculate_sys_precision();
max_clock_error = CNF_GetMaxClockError() * 1e-6;
}
/* ================================================== */
@@ -185,6 +189,14 @@ LCL_GetSysPrecisionAsQuantum(void)
/* ================================================== */
double
LCL_GetMaxClockError(void)
{
return max_clock_error;
}
/* ================================================== */
void
LCL_AddParameterChangeHandler(LCL_ParameterChangeHandler handler, void *anything)
{
@@ -193,7 +205,7 @@ LCL_AddParameterChangeHandler(LCL_ParameterChangeHandler handler, void *anything
/* Check that the handler is not already registered */
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
if (!(ptr->handler != handler || ptr->anything != anything)) {
CROAK("a handler is already registered");
assert(0);
}
}
@@ -231,9 +243,7 @@ void LCL_RemoveParameterChangeHandler(LCL_ParameterChangeHandler handler, void *
}
}
if (!ok) {
CROAK("did not find a matching handler");
}
assert(ok);
/* Unlink entry from the list */
ptr->next->prev = ptr->prev;
@@ -254,7 +264,7 @@ LCL_AddDispersionNotifyHandler(LCL_DispersionNotifyHandler handler, void *anythi
/* Check that the handler is not already registered */
for (ptr = dispersion_notify_list.next; ptr != &dispersion_notify_list; ptr = ptr->next) {
if (!(ptr->handler != handler || ptr->anything != anything)) {
CROAK("a handler is already registered");
assert(0);
}
}
@@ -292,9 +302,7 @@ void LCL_RemoveDispersionNotifyHandler(LCL_DispersionNotifyHandler handler, void
}
}
if (!ok) {
CROAK("no matching handler found");
}
assert(ok);
/* Unlink entry from the list */
ptr->next->prev = ptr->prev;
@@ -312,13 +320,9 @@ void LCL_RemoveDispersionNotifyHandler(LCL_DispersionNotifyHandler handler, void
void
LCL_ReadRawTime(struct timeval *result)
{
struct timezone tz;
if (!(gettimeofday(result, &tz) >= 0)) {
CROAK("Could not get time of day");
if (gettimeofday(result, NULL) < 0) {
LOG_FATAL(LOGF_Local, "gettimeofday() failed");
}
return;
}
/* ================================================== */
@@ -327,30 +331,29 @@ void
LCL_ReadCookedTime(struct timeval *result, double *err)
{
struct timeval raw;
double correction;
LCL_ReadRawTime(&raw);
/* For now, cheat and set the error to zero in all cases.
*/
*err = 0.0;
/* Call system specific driver to get correction */
(*drv_offset_convert)(&raw, &correction);
UTI_AddDoubleToTimeval(&raw, correction, result);
return;
LCL_CookTime(&raw, result, err);
}
/* ================================================== */
double
LCL_GetOffsetCorrection(struct timeval *raw)
void
LCL_CookTime(struct timeval *raw, struct timeval *cooked, double *err)
{
double correction;
(*drv_offset_convert)(raw, &correction);
return correction;
LCL_GetOffsetCorrection(raw, &correction, err);
UTI_AddDoubleToTimeval(raw, correction, cooked);
}
/* ================================================== */
void
LCL_GetOffsetCorrection(struct timeval *raw, double *correction, double *err)
{
/* Call system specific driver to get correction */
(*drv_offset_convert)(raw, correction, err);
}
/* ================================================== */
@@ -359,7 +362,16 @@ LCL_GetOffsetCorrection(struct timeval *raw)
double
LCL_ReadAbsoluteFrequency(void)
{
return (*drv_read_freq)();
double freq;
freq = (*drv_read_freq)();
/* Undo temperature compensation */
if (temp_comp_ppm != 0.0) {
freq = (freq + temp_comp_ppm) / (1.0 - 1.0e-6 * temp_comp_ppm);
}
return freq;
}
/* ================================================== */
@@ -371,22 +383,25 @@ LCL_SetAbsoluteFrequency(double afreq_ppm)
{
ChangeListEntry *ptr;
struct timeval raw, cooked;
double correction;
double dfreq;
/* Apply temperature compensation */
if (temp_comp_ppm != 0.0) {
afreq_ppm = afreq_ppm * (1.0 - 1.0e-6 * temp_comp_ppm) - temp_comp_ppm;
}
/* Call the system-specific driver for setting the frequency */
(*drv_set_freq)(afreq_ppm);
afreq_ppm = (*drv_set_freq)(afreq_ppm);
dfreq = 1.0e-6 * (afreq_ppm - current_freq_ppm) / (1.0 - 1.0e-6 * current_freq_ppm);
dfreq = (afreq_ppm - current_freq_ppm) / (1.0e6 + current_freq_ppm);
LCL_ReadRawTime(&raw);
(drv_offset_convert)(&raw, &correction);
UTI_AddDoubleToTimeval(&raw, correction, &cooked);
LCL_CookTime(&raw, &cooked, NULL);
/* Dispatch to all handlers */
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
(ptr->handler)(&raw, &cooked, dfreq, afreq_ppm, 0.0, 0, ptr->anything);
(ptr->handler)(&raw, &cooked, dfreq, 0.0, 0, ptr->anything);
}
current_freq_ppm = afreq_ppm;
@@ -400,25 +415,26 @@ LCL_AccumulateDeltaFrequency(double dfreq)
{
ChangeListEntry *ptr;
struct timeval raw, cooked;
double correction;
double old_freq_ppm;
old_freq_ppm = current_freq_ppm;
/* Work out new absolute frequency. Note that absolute frequencies
are handled in units of ppm, whereas the 'dfreq' argument is in
terms of the gradient of the (offset) v (local time) function. */
current_freq_ppm = (1.0 - dfreq) * current_freq_ppm +
(1.0e6 * dfreq);
current_freq_ppm = (1.0 + dfreq) * current_freq_ppm + 1.0e6 * dfreq;
/* Call the system-specific driver for setting the frequency */
(*drv_set_freq)(current_freq_ppm);
current_freq_ppm = (*drv_set_freq)(current_freq_ppm);
dfreq = (current_freq_ppm - old_freq_ppm) / (1.0e6 + old_freq_ppm);
LCL_ReadRawTime(&raw);
(drv_offset_convert)(&raw, &correction);
UTI_AddDoubleToTimeval(&raw, correction, &cooked);
LCL_CookTime(&raw, &cooked, NULL);
/* Dispatch to all handlers */
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
(ptr->handler)(&raw, &cooked, dfreq, current_freq_ppm, 0.0, 0, ptr->anything);
(ptr->handler)(&raw, &cooked, dfreq, 0.0, 0, ptr->anything);
}
}
@@ -430,20 +446,18 @@ LCL_AccumulateOffset(double offset)
{
ChangeListEntry *ptr;
struct timeval raw, cooked;
double correction;
/* In this case, the cooked time to be passed to the notify clients
has to be the cooked time BEFORE the change was made */
LCL_ReadRawTime(&raw);
(drv_offset_convert)(&raw, &correction);
UTI_AddDoubleToTimeval(&raw, correction, &cooked);
LCL_CookTime(&raw, &cooked, NULL);
(*drv_accrue_offset)(offset);
/* Dispatch to all handlers */
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
(ptr->handler)(&raw, &cooked, 0.0, current_freq_ppm, offset, 0, ptr->anything);
(ptr->handler)(&raw, &cooked, 0.0, offset, 0, ptr->anything);
}
}
@@ -455,20 +469,18 @@ LCL_ApplyStepOffset(double offset)
{
ChangeListEntry *ptr;
struct timeval raw, cooked;
double correction;
/* In this case, the cooked time to be passed to the notify clients
has to be the cooked time BEFORE the change was made */
LCL_ReadRawTime(&raw);
(drv_offset_convert)(&raw, &correction);
UTI_AddDoubleToTimeval(&raw, correction, &cooked);
LCL_CookTime(&raw, &cooked, NULL);
(*drv_apply_step_offset)(offset);
/* Dispatch to all handlers */
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
(ptr->handler)(&raw, &cooked, 0.0, current_freq_ppm, offset, 1, ptr->anything);
(ptr->handler)(&raw, &cooked, 0.0, offset, 1, ptr->anything);
}
}
@@ -480,22 +492,19 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset)
{
ChangeListEntry *ptr;
struct timeval raw, cooked;
double correction;
double old_freq_ppm;
LCL_ReadRawTime(&raw);
(drv_offset_convert)(&raw, &correction);
/* Due to modifying the offset, this has to be the cooked time prior
to the change we are about to make */
UTI_AddDoubleToTimeval(&raw, correction, &cooked);
LCL_CookTime(&raw, &cooked, NULL);
old_freq_ppm = current_freq_ppm;
/* Work out new absolute frequency. Note that absolute frequencies
are handled in units of ppm, whereas the 'dfreq' argument is in
terms of the gradient of the (offset) v (local time) function. */
current_freq_ppm = (1.0 - dfreq) * old_freq_ppm +
(1.0e6 * dfreq);
current_freq_ppm = (1.0 + dfreq) * old_freq_ppm + 1.0e6 * dfreq;
#ifdef TRACEON
LOG(LOGS_INFO, LOGF_Local, "old_freq=%.3fppm new_freq=%.3fppm offset=%.6fsec",
@@ -503,12 +512,14 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset)
#endif
/* Call the system-specific driver for setting the frequency */
(*drv_set_freq)(current_freq_ppm);
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);
/* Dispatch to all handlers */
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
(ptr->handler)(&raw, &cooked, dfreq, current_freq_ppm, doffset, 0, ptr->anything);
(ptr->handler)(&raw, &cooked, dfreq, doffset, 0, ptr->anything);
}
@@ -564,7 +575,7 @@ LCL_MakeStep(double threshold)
double correction;
LCL_ReadRawTime(&raw);
correction = LCL_GetOffsetCorrection(&raw);
LCL_GetOffsetCorrection(&raw, &correction, NULL);
if (fabs(correction) <= threshold)
return 0;
@@ -591,3 +602,31 @@ LCL_SetLeap(int leap)
}
/* ================================================== */
double
LCL_SetTempComp(double comp)
{
double uncomp_freq_ppm;
if (temp_comp_ppm == comp)
return comp;
/* Undo previous compensation */
current_freq_ppm = (current_freq_ppm + temp_comp_ppm) /
(1.0 - 1.0e-6 * temp_comp_ppm);
uncomp_freq_ppm = current_freq_ppm;
/* Apply new compensation */
current_freq_ppm = current_freq_ppm * (1.0 - 1.0e-6 * comp) - comp;
/* Call the system-specific driver for setting the frequency */
current_freq_ppm = (*drv_set_freq)(current_freq_ppm);
temp_comp_ppm = (uncomp_freq_ppm - current_freq_ppm) /
(1.0e-6 * uncomp_freq_ppm + 1.0);
return temp_comp_ppm;
}
/* ================================================== */

31
local.h
View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/local.h,v 1.16 2002/02/28 23:27:10 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -50,11 +46,13 @@ extern void LCL_ReadRawTime(struct timeval *);
extern void LCL_ReadCookedTime(struct timeval *t, double *err);
/* Read the current offset between the system clock and true time
(i.e. 'cooked' - 'raw') (in seconds). Only intended for use in
status reporting, really. */
/* Convert raw time to cooked. */
extern void LCL_CookTime(struct timeval *raw, struct timeval *cooked, double *err);
extern double LCL_GetOffsetCorrection(struct timeval *raw);
/* Read the current offset between the system clock and true time
(i.e. 'cooked' - 'raw') (in seconds). */
extern void LCL_GetOffsetCorrection(struct timeval *raw, double *correction, double *err);
/* Type of routines that may be invoked as callbacks when there is a
change to the frequency or offset.
@@ -66,10 +64,6 @@ extern double LCL_GetOffsetCorrection(struct timeval *raw);
dfreq : delta frequency relative to previous value (in terms of
seconds gained by system clock per unit system clock time)
afreq : absolute frequency relative to uncompensated system (in
terms of ppm seconds gained by system clock per unit of the
uncalibrated system clock)
doffset : delta offset applied (positive => make local system fast
by that amount, negative => make it slow by that amount)
@@ -81,7 +75,7 @@ extern double LCL_GetOffsetCorrection(struct timeval *raw);
typedef void (*LCL_ParameterChangeHandler)
(struct timeval *raw, struct timeval *cooked,
double dfreq, double afreq_ppm,
double dfreq,
double doffset, int is_step_change,
void *anything
);
@@ -167,6 +161,10 @@ extern int LCL_GetSysPrecisionAsLog(void);
/* Routine to read the system precision in terms of the actual time step */
extern double LCL_GetSysPrecisionAsQuantum(void);
/* Routine to read the maximum frequency error of the local clock. This
is a frequency stability, not an absolute error. */
extern double LCL_GetMaxClockError(void);
/* Routine to initialise the module (to be called once at program
start-up) */
@@ -186,4 +184,11 @@ extern int LCL_MakeStep(double threshold);
and zero cancels scheduled leap second. */
extern void LCL_SetLeap(int leap);
/* Routine to set a frequency correction (in ppm) that should be applied
to local clock to compensate for temperature changes. A positive
argument means that the clock frequency should be increased. Return the
actual compensation (may be different from the requested compensation
due to clamping or rounding). */
extern double LCL_SetTempComp(double comp);
#endif /* GOT_LOCAL_H */

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/localp.h,v 1.9 2002/02/28 23:27:10 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -40,8 +36,9 @@ typedef double (*lcl_ReadFrequencyDriver)(void);
/* System driver to set the current local frequency, in ppm relative
to nominal. A positive value indicates that the local clock runs
fast when uncompensated. */
typedef void (*lcl_SetFrequencyDriver)(double freq_ppm);
fast when uncompensated. Return actual frequency (may be different
from the requested frequency due to clamping or rounding). */
typedef double (*lcl_SetFrequencyDriver)(double freq_ppm);
/* System driver to accrue an offset. A positive argument means slew
the clock forwards. */
@@ -54,7 +51,7 @@ typedef void (*lcl_ApplyStepOffsetDriver)(double offset);
/* System driver to convert a raw time to an adjusted (cooked) time.
The number of seconds returned in 'corr' have to be added to the
raw time to get the corrected time */
typedef void (*lcl_OffsetCorrectionDriver)(struct timeval *raw, double *corr);
typedef void (*lcl_OffsetCorrectionDriver)(struct timeval *raw, double *corr, double *err);
/* System driver to schedule leap second */
typedef void (*lcl_SetLeapDriver)(int leap);

179
logging.c
View File

@@ -1,12 +1,9 @@
/*
$Header: /cvs/src/chrony/logging.c,v 1.15 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011
*
* 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
@@ -31,14 +28,17 @@
#include "sysincl.h"
#include "main.h"
#include "conf.h"
#include "logging.h"
#include "version.h"
#include "mkdirpp.h"
#include "util.h"
/* ================================================== */
/* Flag indicating we have initialised */
static int initialised = 0;
static int is_detached = 0;
static int system_log = 0;
static time_t last_limited = 0;
@@ -46,6 +46,20 @@ static time_t last_limited = 0;
static FILE *logfile;
#endif
struct LogFile {
const char *name;
const char *banner;
FILE *file;
unsigned long writes;
};
static int n_filelogs = 0;
/* Increase this when adding a new logfile */
#define MAX_FILELOGS 6
static struct LogFile logfiles[MAX_FILELOGS];
/* ================================================== */
/* Init function */
@@ -72,11 +86,13 @@ LOG_Finalise(void)
fclose(logfile);
}
#else
if (is_detached) {
if (system_log) {
closelog();
}
#endif
LOG_CycleLogFiles();
initialised = 0;
return;
}
@@ -96,7 +112,7 @@ LOG_Line_Function(LOG_Severity severity, LOG_Facility facility, const char *form
fprintf(logfile, "%s\n", buf);
}
#else
if (is_detached) {
if (system_log) {
switch (severity) {
case LOGS_INFO:
syslog(LOG_INFO, "%s", buf);
@@ -132,7 +148,7 @@ LOG_Fatal_Function(LOG_Facility facility, const char *format, ...)
fprintf(logfile, "Fatal error : %s\n", buf);
}
#else
if (is_detached) {
if (system_log) {
syslog(LOG_CRIT, "Fatal error : %s", buf);
} else {
fprintf(stderr, "Fatal error : %s\n", buf);
@@ -154,7 +170,7 @@ LOG_Position(const char *filename, int line_number, const char *function_name)
time_t t;
struct tm stm;
char buf[64];
if (!is_detached) {
if (!system_log) {
/* Don't clutter up syslog with internal debugging info */
time(&t);
stm = *gmtime(&t);
@@ -168,50 +184,13 @@ LOG_Position(const char *filename, int line_number, const char *function_name)
/* ================================================== */
void
LOG_GoDaemon(void)
LOG_OpenSystemLog(void)
{
#ifdef WINNT
#else
int pid, fd;
/* Does this preserve existing signal handlers? */
pid = fork();
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' */
} else {
setsid();
/* Do 2nd fork, as-per recommended practice for launching daemons. */
pid = fork();
if (pid < 0) {
LOG(LOGS_ERR, LOGF_Logging, "Could not detach, fork failed : %s", strerror(errno));
} else if (pid > 0) {
exit(0); /* In the 'parent' */
} 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);
}
is_detached = 1;
system_log = 1;
openlog("chronyd", LOG_PID, LOG_DAEMON);
LOG(LOGS_INFO, LOGF_Logging, "chronyd version %s starting", PROGRAM_VERSION_STRING);
}
}
#endif
}
@@ -232,19 +211,101 @@ LOG_RateLimited(void)
}
/* ================================================== */
/* Force a core dump and exit without doing abort() or assert(0).
These do funny things with the call stack in the core file that is
generated, which makes diagnosis difficult. */
int
croak(const char *file, int line, const char *msg)
LOG_FileID
LOG_FileOpen(const char *name, const char *banner)
{
int a;
LOG(LOGS_ERR, LOGF_Util, "Unexpected condition [%s] at %s:%d, core dumped",
msg, file, line);
a = * (int *) 0;
return a; /* Can't happen - this stops the optimiser optimising the
line above */
assert(n_filelogs < MAX_FILELOGS);
logfiles[n_filelogs].name = name;
logfiles[n_filelogs].banner = banner;
logfiles[n_filelogs].file = NULL;
logfiles[n_filelogs].writes = 0;
return n_filelogs++;
}
/* ================================================== */
void
LOG_FileWrite(LOG_FileID id, const char *format, ...)
{
va_list other_args;
int banner;
if (id < 0 || id >= n_filelogs || !logfiles[id].name)
return;
if (!logfiles[id].file) {
char filename[512];
if (snprintf(filename, sizeof(filename), "%s/%s.log",
CNF_GetLogDir(), logfiles[id].name) >= sizeof(filename) ||
!(logfiles[id].file = fopen(filename, "a"))) {
LOG(LOGS_WARN, LOGF_Refclock, "Couldn't open logfile %s for update", filename);
logfiles[id].name = NULL;
return;
}
/* Close on exec */
UTI_FdSetCloexec(fileno(logfiles[id].file));
}
banner = CNF_GetLogBanner();
if (banner && logfiles[id].writes++ % banner == 0) {
char bannerline[256];
int i, bannerlen;
bannerlen = strlen(logfiles[id].banner);
for (i = 0; i < bannerlen; i++)
bannerline[i] = '=';
bannerline[i] = '\0';
fprintf(logfiles[id].file, "%s\n", bannerline);
fprintf(logfiles[id].file, "%s\n", logfiles[id].banner);
fprintf(logfiles[id].file, "%s\n", bannerline);
}
va_start(other_args, format);
vfprintf(logfiles[id].file, format, other_args);
va_end(other_args);
fprintf(logfiles[id].file, "\n");
fflush(logfiles[id].file);
}
/* ================================================== */
void
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;
}
}
/* ================================================== */
void
LOG_CycleLogFiles(void)
{
LOG_FileID i;
for (i = 0; i < n_filelogs; i++) {
if (logfiles[i].file)
fclose(logfiles[i].file);
logfiles[i].file = NULL;
logfiles[i].writes = 0;
}
}
/* ================================================== */

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/logging.h,v 1.15 2002/02/28 23:27:10 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -63,6 +59,7 @@ typedef enum {
LOGF_Regress,
LOGF_Sys,
LOGF_SysLinux,
LOGF_SysNetBSD,
LOGF_SysSolaris,
LOGF_SysSunOS,
LOGF_SysWinnt,
@@ -85,7 +82,8 @@ extern void LOG_Fatal_Function(LOG_Facility facility, const char *format, ...);
/* Position in code reporting function */
extern void LOG_Position(const char *filename, int line_number, const char *function_name);
extern void LOG_GoDaemon(void);
/* Log messages to syslog instead of stderr */
extern void LOG_OpenSystemLog(void);
/* Return zero once per 10 seconds */
extern int LOG_RateLimited(void);
@@ -100,13 +98,14 @@ extern int LOG_RateLimited(void);
#define LOG_FATAL LOG_Position(__FILE__, __LINE__, ""); LOG_Fatal_Function
#endif /* defined (__GNUC__) */
/* Like assert(0) */
/* File logging functions */
#if defined(LINUX) && defined(__alpha__)
#define CROAK(message) assert(0) /* Added JGH Feb 24 2001 FIXME */
#else
extern int croak(const char *file, int line, const char *msg);
#define CROAK(message) croak(__FILE__, __LINE__, message);
#endif
typedef int LOG_FileID;
extern LOG_FileID LOG_FileOpen(const char *name, const char *banner);
extern void LOG_FileWrite(LOG_FileID id, const char *format, ...);
extern void LOG_CreateLogFileDir(void);
extern void LOG_CycleLogFiles(void);
#endif /* GOT_LOGGING_H */

72
main.c
View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/main.c,v 1.31 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -53,6 +49,7 @@
#include "clientlog.h"
#include "broadcast.h"
#include "nameserv.h"
#include "tempcomp.h"
/* ================================================== */
@@ -86,6 +83,7 @@ MAI_CleanupAndExit(void)
SRC_DumpSources();
}
TMC_Finalise();
MNL_Finalise();
ACQ_Finalise();
KEY_Finalise();
@@ -93,10 +91,10 @@ MAI_CleanupAndExit(void)
NSR_Finalise();
NCR_Finalise();
BRD_Finalise();
SRC_Finalise();
SST_Finalise();
REF_Finalise();
RCL_Finalise();
SRC_Finalise();
RTC_Finalise();
CAM_Finalise();
NIO_Finalise();
@@ -208,12 +206,55 @@ write_lockfile(void)
/* ================================================== */
static void
go_daemon(void)
{
#ifdef WINNT
#else
int pid, fd;
/* Does this preserve existing signal handlers? */
pid = fork();
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' */
} else {
setsid();
/* Do 2nd fork, as-per recommended practice for launching daemons. */
pid = fork();
if (pid < 0) {
LOG(LOGS_ERR, LOGF_Logging, "Could not detach, fork failed : %s", strerror(errno));
} else if (pid > 0) {
exit(0); /* In the 'parent' */
} 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);
}
}
}
#endif
}
/* ================================================== */
int main
(int argc, char **argv)
{
char *conf_file = NULL;
char *user = NULL;
int debug = 0;
int debug = 0, nofork = 0;
int do_init_rtc = 0;
int other_pid;
int lock_memory = 0, sched_priority = 0;
@@ -248,8 +289,11 @@ int main
/* This write to the terminal is OK, it comes before we turn into a daemon */
printf("chronyd (chrony) version %s\n", PROGRAM_VERSION_STRING);
exit(0);
} else if (!strcmp("-n", *argv)) {
nofork = 1;
} else if (!strcmp("-d", *argv)) {
debug = 1;
nofork = 1;
} else if (!strcmp("-4", *argv)) {
DNS_SetAddressFamily(IPADDR_INET4);
} else if (!strcmp("-6", *argv)) {
@@ -259,6 +303,8 @@ 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 */
@@ -266,10 +312,13 @@ int main
exit(1);
}
/* Turn into a daemon */
if (!nofork) {
go_daemon();
}
if (!debug) {
LOG_GoDaemon();
LOG_OpenSystemLog();
}
/* Check whether another chronyd may already be running. Do this after
@@ -286,8 +335,6 @@ int main
write_lockfile();
#endif
CNF_ReadFile(conf_file);
if (do_init_rtc) {
RTC_TimePreInit();
}
@@ -298,6 +345,7 @@ int main
NIO_Initialise();
CAM_Initialise();
RTC_Initialise();
SRC_Initialise();
RCL_Initialise();
/* Command-line switch must have priority */
@@ -318,7 +366,6 @@ int main
REF_Initialise();
SST_Initialise();
SRC_Initialise();
BRD_Initialise();
NCR_Initialise();
NSR_Initialise();
@@ -326,6 +373,9 @@ int main
KEY_Initialise();
ACQ_Initialise();
MNL_Initialise();
TMC_Initialise();
LOG_CreateLogFileDir();
/* From now on, it is safe to do finalisation on exit */
initialised = 1;

4
main.h
View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/main.h,v 1.8 2002/02/28 23:27:10 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/manual.c,v 1.21 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -74,7 +70,6 @@ static void
slew_samples(struct timeval *raw,
struct timeval *cooked,
double dfreq,
double afreq,
double doffset,
int is_step_change,
void *not_used);
@@ -188,14 +183,13 @@ int
MNL_AcceptTimestamp(struct timeval *ts, long *offset_cs, double *dfreq_ppm, double *new_afreq_ppm)
{
struct timeval now;
double local_clock_err;
double offset;
int i;
if (enabled) {
/* Check whether timestamp is within margin of old one */
LCL_ReadCookedTime(&now, &local_clock_err);
LCL_ReadCookedTime(&now, NULL);
UTI_DiffTimevalsToDouble(&offset, &now, ts);
@@ -230,17 +224,15 @@ static void
slew_samples(struct timeval *raw,
struct timeval *cooked,
double dfreq,
double afreq,
double doffset,
int is_step_change,
void *not_used)
{
double elapsed, delta_time;
double delta_time;
int i;
for (i=0; i<n_samples; i++) {
UTI_DiffTimevalsToDouble(&elapsed, cooked, &samples[i].when);
delta_time = elapsed * dfreq - doffset;
UTI_AddDoubleToTimeval(&samples[i].when, delta_time, &samples[i].when);
UTI_AdjustTimeval(&samples[i].when, cooked, &samples[i].when, &delta_time,
dfreq, doffset);
samples[i].offset += delta_time;
}
return;
@@ -303,7 +295,6 @@ MNL_DeleteSample(int index)
{
int i;
struct timeval now;
double local_clock_err;
if ((index < 0) || (index >= n_samples)) {
return 0;
@@ -319,7 +310,7 @@ MNL_DeleteSample(int index)
/* Now re-estimate. NULLs because we don't want the parameters back
in this case. */
LCL_ReadCookedTime(&now, &local_clock_err);
LCL_ReadCookedTime(&now, NULL);
estimate_and_set_system(&now, 0, 0.0, NULL, NULL, NULL);
return 1;

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/manual.h,v 1.12 2002/02/28 23:27:11 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/memory.h,v 1.7 2002/02/28 23:27:11 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/mkdirpp.c,v 1.10 2002/11/03 22:49:17 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -86,6 +82,7 @@ mkdir_and_parents(const char *path)
p[i] = 0;
if (do_dir(p) < 0) {
free(p);
return 0;
}

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/mkdirpp.h,v 1.6 2002/02/28 23:27:11 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

View File

@@ -1,13 +1,9 @@
/*
$Header: /cvs/src/chrony/nameserv.c,v 1.15 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009
* Copyright (C) Miroslav Lichvar 2009-2011
*
* 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
@@ -38,9 +34,6 @@
/* ================================================== */
#define MAXRETRIES 10
static unsigned int retries = 0;
static int address_family = IPADDR_UNSPEC;
void
@@ -49,8 +42,8 @@ DNS_SetAddressFamily(int family)
address_family = family;
}
int
DNS_Name2IPAddress(const char *name, IPAddr *addr, int retry)
DNS_Status
DNS_Name2IPAddress(const char *name, IPAddr *addr)
{
#ifdef HAVE_IPV6
struct addrinfo hints, *res, *ai;
@@ -59,21 +52,11 @@ DNS_Name2IPAddress(const char *name, IPAddr *addr, int retry)
memset(&hints, 0, sizeof (hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
#ifdef AI_ADDRCONFIG
hints.ai_flags = AI_ADDRCONFIG;
#endif
try_again:
result = getaddrinfo(name, NULL, &hints, &res);
if (result) {
if (retry && result == EAI_AGAIN && retries < MAXRETRIES) {
sleep(2 << retries);
retries++;
res_init();
goto try_again;
}
return 0;
return result == EAI_AGAIN ? DNS_TryAgain : DNS_Failure;
}
for (ai = res; !result && ai != NULL; ai = ai->ai_next) {
@@ -96,32 +79,22 @@ try_again:
}
freeaddrinfo(res);
return result;
return result ? DNS_Success : DNS_Failure;
#else
struct hostent *host;
char *address0;
try_again:
host = gethostbyname(name);
if (host == NULL) {
if (retry && h_errno == TRY_AGAIN && retries < MAXRETRIES) {
sleep(2 << retries);
retries++;
res_init();
goto try_again;
}
if (h_errno == TRY_AGAIN)
return DNS_TryAgain;
} else {
addr->family = IPADDR_INET4;
address0 = host->h_addr_list[0];
addr->addr.in4 = ((((unsigned long)address0[0])<<24) |
(((unsigned long)address0[1])<<16) |
(((unsigned long)address0[2])<<8) |
(((unsigned long)address0[3])));
return 1;
addr->addr.in4 = ntohl(*(uint32_t *)host->h_addr_list[0]);
return DNS_Success;
}
return 0;
return DNS_Failure;
#endif
}
@@ -190,3 +163,11 @@ DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len)
/* ================================================== */
void
DNS_Reload(void)
{
res_init();
}
/* ================================================== */

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/nameserv.h,v 1.8 2002/02/28 23:27:11 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -34,12 +30,20 @@
#include "addressing.h"
typedef enum {
DNS_Success,
DNS_TryAgain,
DNS_Failure
} DNS_Status;
/* Resolve names only to selected address family */
extern void DNS_SetAddressFamily(int family);
extern int DNS_Name2IPAddress(const char *name, IPAddr *addr, int retry);
extern DNS_Status DNS_Name2IPAddress(const char *name, IPAddr *addr);
extern int DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len);
extern void DNS_Reload(void);
#endif /* GOT_NAMESERV_H */

4
ntp.h
View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/ntp.h,v 1.12 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

View File

@@ -1,13 +1,9 @@
/*
$Header: /cvs/src/chrony/ntp_core.c,v 1.50 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009
* Copyright (C) Miroslav Lichvar 2009-2011
*
* 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
@@ -44,27 +40,17 @@
#include "keys.h"
#include "md5.h"
#include "addrfilt.h"
#include "mkdirpp.h"
#include "clientlog.h"
/* ================================================== */
/* File handle for file to which we write the measurement log */
static FILE *logfile = NULL;
static char *logfilename = NULL;
static unsigned long logwrites=0;
#define MEASUREMENTS_LOG "measurements.log"
static LOG_FileID logfileid;
/* ================================================== */
/* Day number of 1 Jan 1970 */
#define MJD_1970 40587
/* ================================================== */
#define ZONE_WIDTH 4
/* ================================================== */
/* Enumeration used for remembering the operating mode of one of the
sources */
@@ -113,6 +99,13 @@ struct NCR_Instance_Record {
int minpoll; /* Log2 of minimum defined polling interval */
int maxpoll; /* Log2 of maximum defined polling interval */
int min_stratum; /* Increase stratum in received packets to the
minimum */
int poll_target; /* Target number of sourcestats samples */
double poll_score; /* Score of current local poll */
double max_delay; /* Maximum round-trip delay to the
peer that we can tolerate and still
use the sample for generating
@@ -122,6 +115,8 @@ struct NCR_Instance_Record {
min_delay_in_register that we can
tolerate. */
double max_delay_dev_ratio; /* Maximum ratio of increase in delay / stddev */
int do_auth; /* Flag indicating whether we
authenticate packets we send to
this machine (if it's serving us or
@@ -166,8 +161,6 @@ struct NCR_Instance_Record {
SRC_Instance source;
int score;
int burst_good_samples_to_go;
int burst_total_samples_to_go;
@@ -175,16 +168,25 @@ struct NCR_Instance_Record {
/* ================================================== */
/* Initial delay period before first packet is transmitted (in seconds) */
#define INITIAL_DELAY 2.0
#define INITIAL_DELAY 0.2
/* Spacing required between samples for any two servers/peers (to
minimise risk of network collisions) (in seconds) */
#define SAMPLING_SEPARATION 2.0
#define SAMPLING_SEPARATION 0.2
/* Randomness added to spacing between samples for one server/peer */
#define SAMPLING_RANDOMNESS 0.02
/* Spacing between samples in burst mode for one server/peer */
#define BURST_INTERVAL 2.0
/* Time to wait before retransmitting in burst mode, if we did not get
a reply to the previous probe */
#define BURST_TIMEOUT 8.0
/* Time to wait after sending echo to 'warm up' link */
#define WARM_UP_DELAY 4.0
/* The NTP protocol version that we support */
#define NTP_VERSION 3
@@ -217,24 +219,9 @@ static void determine_md5_delay(void);
void
NCR_Initialise(void)
{
char *direc;
if (CNF_GetLogMeasurements()) {
direc = CNF_GetLogDir();
if (!mkdir_and_parents(direc)) {
LOG(LOGS_ERR, LOGF_NtpCore, "Could not create directory %s", direc);
logfile = NULL;
} else {
logfilename = MallocArray(char, 2 + strlen(direc) + strlen(MEASUREMENTS_LOG));
strcpy(logfilename, direc);
strcat(logfilename, "/");
strcat(logfilename, MEASUREMENTS_LOG);
logfile = fopen(logfilename, "a");
if (!logfile) {
LOG(LOGS_WARN, LOGF_NtpCore, "Couldn't open logfile %s for update", logfilename);
}
}
}
logfileid = CNF_GetLogMeasurements() ? LOG_FileOpen("measurements",
" Date (UTC) Time IP Address L St 1234 abc 5678 LP RP Score Offset Peer del. Peer disp. Root del. Root disp.")
: -1;
access_auth_table = ADF_CreateTable();
@@ -247,10 +234,6 @@ NCR_Initialise(void)
void
NCR_Finalise(void)
{
if (logfile) {
fclose(logfile);
}
ADF_DestroyTable(access_auth_table);
}
@@ -263,6 +246,7 @@ start_initial_timeout(NCR_Instance inst)
/* Start timer for first transmission */
inst->timeout_id = SCH_AddTimeoutInClass(INITIAL_DELAY, SAMPLING_SEPARATION,
SAMPLING_RANDOMNESS,
SCH_NtpSamplingClass,
transmit_timeout, (void *)inst);
inst->timer_running = 1;
@@ -272,18 +256,28 @@ start_initial_timeout(NCR_Instance inst)
/* ================================================== */
static NCR_Instance
create_instance(NTP_Remote_Address *remote_addr, NTP_Mode mode, SourceParameters *params)
NCR_Instance
NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params)
{
NCR_Instance result;
result = MallocNew(struct NCR_Instance_Record);
result->remote_addr = *remote_addr;
result->mode = mode;
switch (type) {
case NTP_SERVER:
result->mode = MODE_CLIENT;
break;
case NTP_PEER:
result->mode = MODE_ACTIVE;
break;
default:
assert(0);
}
result->minpoll = params->minpoll;
result->maxpoll = params->maxpoll;
result->min_stratum = params->min_stratum;
result->presend_minpoll = params->presend_minpoll;
result->presend_done = 0;
@@ -298,13 +292,15 @@ create_instance(NTP_Remote_Address *remote_addr, NTP_Mode mode, SourceParameters
result->max_delay = params->max_delay;
result->max_delay_ratio = params->max_delay_ratio;
result->max_delay_dev_ratio = params->max_delay_dev_ratio;
result->tx_count = 0;
result->remote_orig.hi = 0;
result->remote_orig.lo = 0;
result->score = 0;
result->poll_target = params->poll_target;
result->poll_score = 0.0;
if (params->online) {
start_initial_timeout(result);
@@ -315,12 +311,16 @@ create_instance(NTP_Remote_Address *remote_addr, NTP_Mode mode, SourceParameters
result->opmode = MD_OFFLINE;
}
if (params->iburst) {
NCR_InitiateSampleBurst(result, 4, 8);
}
result->auto_offline = params->auto_offline;
result->local_poll = params->minpoll;
/* Create a source instance for this NTP source */
result->source = SRC_CreateNewInstance(UTI_IPToRefid(&remote_addr->ip_addr), SRC_NTP, &result->remote_addr.ip_addr);
result->source = SRC_CreateNewInstance(UTI_IPToRefid(&remote_addr->ip_addr), SRC_NTP, params->sel_option, &result->remote_addr.ip_addr);
result->local_rx.tv_sec = 0;
result->local_rx.tv_usec = 0;
@@ -335,24 +335,6 @@ create_instance(NTP_Remote_Address *remote_addr, NTP_Mode mode, SourceParameters
/* ================================================== */
/* Get a new instance for a server */
NCR_Instance
NCR_GetServerInstance(NTP_Remote_Address *remote_addr, SourceParameters *params)
{
return create_instance(remote_addr, MODE_CLIENT, params);
}
/* ================================================== */
/* Get a new instance for a peer */
NCR_Instance
NCR_GetPeerInstance(NTP_Remote_Address *remote_addr, SourceParameters *params)
{
return create_instance(remote_addr, MODE_ACTIVE, params);
}
/* ================================================== */
/* Destroy an instance */
void
NCR_DestroyInstance(NCR_Instance instance)
@@ -474,29 +456,28 @@ check_packet_auth(NTP_Packet *pkt, unsigned long keyid)
/* ================================================== */
static void
normalise_score(NCR_Instance inst)
adjust_poll(NCR_Instance inst, double adj)
{
inst->poll_score += adj;
while (inst->score >= ZONE_WIDTH) {
++inst->local_poll;
inst->score -= ZONE_WIDTH;
if (inst->poll_score >= 1.0) {
inst->local_poll += (int)inst->poll_score;
inst->poll_score -= (int)inst->poll_score;
}
while (inst->score < 0) {
if (inst->local_poll > 0) {
--inst->local_poll;
}
inst->score += ZONE_WIDTH;
if (inst->poll_score < 0.0) {
inst->local_poll += (int)(inst->poll_score - 1.0);
inst->poll_score -= (int)(inst->poll_score - 1.0);
}
/* Clamp polling interval to defined range */
if (inst->local_poll < inst->minpoll) {
inst->local_poll = inst->minpoll;
inst->score = 0;
inst->poll_score = 0;
} else if (inst->local_poll > inst->maxpoll) {
inst->local_poll = inst->maxpoll;
inst->score = ZONE_WIDTH - 1;
inst->poll_score = 1.0;
}
}
/* ================================================== */
@@ -523,7 +504,6 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
NTP_Packet message;
int version;
int leap;
double local_time_err;
struct timeval local_transmit;
/* Parameters read from reference module */
@@ -535,7 +515,7 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
version = 3;
LCL_ReadCookedTime(&local_transmit, &local_time_err);
LCL_ReadCookedTime(&local_transmit, NULL);
REF_GetReferenceParams(&local_transmit,
&are_we_synchronised, &leap_status,
&our_stratum,
@@ -582,7 +562,7 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
/* Transmit - this our local time right now! Also, we might need to
store this for our own use later, next time we receive a message
from the source we're sending to now. */
LCL_ReadCookedTime(&local_transmit, &local_time_err);
LCL_ReadCookedTime(&local_transmit, NULL);
/* Authenticate */
if (do_auth) {
@@ -608,13 +588,6 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
}
/* ================================================== */
/* ================================================== */
#define WARM_UP_DELAY 4.0
/* ================================================== */
/* Timeout handler for transmitting to a source. */
@@ -622,7 +595,6 @@ static void
transmit_timeout(void *arg)
{
NCR_Instance inst = (NCR_Instance) arg;
NTP_Mode my_mode;
double timeout_delay=0.0;
int do_timer = 0;
int do_auth;
@@ -649,6 +621,7 @@ transmit_timeout(void *arg)
/* Requeue timeout */
inst->timer_running = 1;
inst->timeout_id = SCH_AddTimeoutInClass(WARM_UP_DELAY, SAMPLING_SEPARATION,
SAMPLING_RANDOMNESS,
SCH_NtpSamplingClass,
transmit_timeout, (void *)inst);
@@ -658,38 +631,22 @@ transmit_timeout(void *arg)
inst->presend_done = 0; /* Reset for next time */
++inst->tx_count;
if (inst->tx_count >= 9) {
/* Mark source unreachable */
SRC_UnsetReachable(inst->source);
} else if (inst->tx_count >= 3) {
if (inst->auto_offline) {
NCR_TakeSourceOffline(inst);
}
/* Do reselection */
SRC_SelectSource(0);
} else {
/* Nothing */
}
/* If the source to which we are currently locked starts to lose
connectivity, increase the sampling rate to try and bring it
back. If any other source loses connectivity, back off the
sampling rate to reduce wasted sampling. */
/* If the source loses connectivity, back off the sampling rate to reduce
wasted sampling. If it's the source to which we are currently locked,
back off slower. */
if (SRC_IsSyncPeer(inst->source)) {
if (inst->tx_count >= 2) {
/* Implies we have missed at least one transmission */
inst->score -= 3;
normalise_score(inst);
}
} else {
if (inst->tx_count >= 2) {
inst->score += 1;
normalise_score(inst);
}
}
my_mode = inst->mode;
adjust_poll(inst, SRC_IsSyncPeer(inst->source) ? 0.1 : 0.25);
SRC_UpdateReachability(inst->source, 0);
if (inst->auto_offline && inst->tx_count >= 3) {
NCR_TakeSourceOffline(inst);
}
}
if (inst->do_auth && KEY_KeyKnown(inst->auth_key_id)) {
do_auth = 1;
@@ -697,11 +654,13 @@ transmit_timeout(void *arg)
do_auth = 0;
}
transmit_packet(my_mode, inst->local_poll,
if (inst->opmode != MD_OFFLINE) {
transmit_packet(inst->mode, inst->local_poll,
do_auth, inst->auth_key_id,
&inst->remote_orig,
&inst->local_rx, &inst->local_tx, &inst->local_ntp_tx,
&inst->remote_addr);
}
switch (inst->opmode) {
@@ -730,6 +689,8 @@ transmit_timeout(void *arg)
break;
case MD_OFFLINE:
do_timer = 0;
/* Mark source unreachable */
SRC_ResetReachability(inst->source);
break;
case MD_BURST_WAS_ONLINE:
case MD_BURST_WAS_OFFLINE:
@@ -741,6 +702,7 @@ transmit_timeout(void *arg)
if (do_timer) {
inst->timer_running = 1;
inst->timeout_id = SCH_AddTimeoutInClass(timeout_delay, SAMPLING_SEPARATION,
SAMPLING_RANDOMNESS,
SCH_NtpSamplingClass,
transmit_timeout, (void *)inst);
} else {
@@ -755,7 +717,7 @@ transmit_timeout(void *arg)
/* ================================================== */
static void
receive_packet(NTP_Packet *message, struct timeval *now, NCR_Instance inst, int do_auth)
receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance inst, int do_auth)
{
int pkt_leap;
int source_is_synchronized;
@@ -804,9 +766,9 @@ receive_packet(NTP_Packet *message, struct timeval *now, NCR_Instance inst, int
struct timeval local_average, remote_average;
double local_interval, remote_interval;
int test1, test2, test3, test4, test5, test6, test7, test8;
int test1, test2, test3, test4, test5, test6, test7, test7i, test7ii, test8;
int test4a, test4b;
int test4a, test4b, test4c;
/* In the words of section 3.4.4 of RFC1305, valid_data means
that the NTP protocol association with the peer/server is
@@ -814,8 +776,8 @@ receive_packet(NTP_Packet *message, struct timeval *now, NCR_Instance inst, int
obtained from the packet is suitable for use in synchronising
our local clock. Wierd choice of terminology. */
int valid_data;
int valid_header;
int valid_data, valid_header;
int good_data, good_header;
/* Kiss-of-Death packets */
int kod_rate = 0;
@@ -835,7 +797,7 @@ receive_packet(NTP_Packet *message, struct timeval *now, NCR_Instance inst, int
int poll_to_use;
double delay_time = 0;
int requeue_transmit = 0;
int delta_score;
double poll_adj;
/* ==================== */
@@ -929,7 +891,7 @@ receive_packet(NTP_Packet *message, struct timeval *now, NCR_Instance inst, int
skew = source_freq_hi - source_freq_lo;
/* and then calculate peer dispersion */
epsilon = LCL_GetSysPrecisionAsQuantum() + skew * local_interval;
epsilon = LCL_GetSysPrecisionAsQuantum() + now_err + skew * local_interval;
} else {
/* If test3 failed, we probably can't calculate these quantities
@@ -970,6 +932,18 @@ receive_packet(NTP_Packet *message, struct timeval *now, NCR_Instance inst, int
test4b = 1; /* Success */
}
/* Test 4c (additional to RFC1305) requires that the ratio of the
increase in delay from the minimum one in the stats data register to
the standard deviation of the offsets in the register is less than an
administrator-defined value or the difference between measured offset
and predicted offset is larger than the increase in delay */
if (!SRC_IsGoodSample(inst->source, -theta, delta, inst->max_delay_dev_ratio,
LCL_GetMaxClockError(), &sample_time)) {
test4c = 0; /* Failed */
} else {
test4c = 1; /* Success */
}
/* Test 5 relates to authentication. */
if (inst->do_auth) {
if (do_auth) {
@@ -1010,14 +984,27 @@ receive_packet(NTP_Packet *message, struct timeval *now, NCR_Instance inst, int
message->stratum = NTP_MAX_STRATUM + 1;
}
/* Test 7 checks that the stratum in the packet is appropriate */
if ((message->stratum > REF_GetOurStratum()) ||
(message->stratum > NTP_MAX_STRATUM)) {
test7 = 0; /* Failed */
} else {
test7 = 1;
/* Increase stratum to the configured minimum */
if (message->stratum < inst->min_stratum) {
message->stratum = inst->min_stratum;
}
/* Test 7i checks that the stratum in the packet is valid */
if (message->stratum > NTP_MAX_STRATUM) {
test7i = 0; /* Failed */
} else {
test7i = 1;
}
/* Test 7ii checks that the stratum in the packet is not higher than ours */
if (message->stratum > REF_GetOurStratum()) {
test7ii = 0; /* Failed */
} else {
test7ii = 1;
}
test7 = test7i && test7ii;
/* Test 8 checks that the root delay and dispersion quoted in
the packet are appropriate */
if ((fabs(pkt_root_delay) >= NTP_MAX_DISPERSION) ||
@@ -1036,7 +1023,9 @@ receive_packet(NTP_Packet *message, struct timeval *now, NCR_Instance inst, int
valid_kod = test1 && test2 && test5;
valid_data = test1 && test2 && test3 && test4 && test4a && test4b;
valid_header = test5 && test6 && test7 && test8;
good_data = valid_data && test4c;
valid_header = test5 && test6 && test7i && test8;
good_header = valid_header && test7ii;
root_delay = pkt_root_delay + delta;
root_dispersion = pkt_root_dispersion + epsilon;
@@ -1064,35 +1053,40 @@ receive_packet(NTP_Packet *message, struct timeval *now, NCR_Instance inst, int
LOG(LOGS_INFO, LOGF_NtpCore, "theta=%f delta=%f epsilon=%f root_delay=%f root_dispersion=%f",
theta, delta, epsilon, root_delay, root_dispersion);
LOG(LOGS_INFO, LOGF_NtpCore, "test1=%d test2=%d test3=%d test4=%d valid_data=%d",
test1, test2, test3, test4, valid_data);
LOG(LOGS_INFO, LOGF_NtpCore, "test1=%d test2=%d test3=%d test4=%d valid_data=%d good_data=%d",
test1, test2, test3, test4, valid_data, good_data);
LOG(LOGS_INFO, LOGF_NtpCore, "test5=%d test6=%d test7=%d test8=%d valid_header=%d",
test5, test6, test7, test8, valid_header);
LOG(LOGS_INFO, LOGF_NtpCore, "test5=%d test6=%d test7=%d test8=%d valid_header=%d good_header=%d",
test5, test6, test7, test8, valid_header, good_header);
LOG(LOGS_INFO, LOGF_NtpCore, "kod_rate=%d valid_kod=%d", kod_rate, valid_kod);
#endif
if (valid_header && valid_data) {
inst->tx_count = 0;
SRC_SetReachable(inst->source);
SRC_UpdateReachability(inst->source, 1);
/* Mark the source as suitable for synchronisation when both header and
data are good, unmark when header is not good (i.e. the stratum is
higher than ours) */
if (good_header) {
if (good_data) {
SRC_SetSelectable(inst->source);
}
} else {
SRC_UnsetSelectable(inst->source);
}
}
/* Do this before we accumulate a new sample into the stats registers, obviously */
estimated_offset = SRC_PredictOffset(inst->source, &sample_time);
if (valid_data) {
if (valid_header && good_data) {
SRC_AccumulateSample(inst->source,
&sample_time,
theta, delta, epsilon,
root_delay, root_dispersion,
message->stratum, (NTP_Leap) pkt_leap);
}
/* Only do performance monitoring if we got valid data! */
if (valid_data) {
/* Now examine the registers. First though, if the prediction is
not even within +/- the peer distance of the peer, we are clearly
@@ -1109,31 +1103,44 @@ receive_packet(NTP_Packet *message, struct timeval *now, NCR_Instance inst, int
temp>>=1;
} while (temp);
inst->local_poll -= shift;
inst->score = 0;
poll_adj = -shift - inst->poll_score + 0.5;
} else {
int samples = SRC_Samples(inst->source);
switch (SRC_LastSkewChange(inst->source)) {
case SRC_Skew_Decrease:
delta_score = 1;
break;
case SRC_Skew_Nochange:
delta_score = 0;
break;
case SRC_Skew_Increase:
delta_score = -2;
break;
default: /* Should not happen! */
delta_score = 0;
break;
/* Adjust polling interval so that the number of sourcestats samples
remains close to the target value */
poll_adj = ((double)samples / inst->poll_target - 1.0) / inst->poll_target;
/* Use higher gain when decreasing the interval */
if (samples < inst->poll_target) {
poll_adj *= 2.0;
}
}
inst->score += delta_score;
adjust_poll(inst, poll_adj);
} else if (valid_header && valid_data) {
/* Slowly increase the polling interval if we can't get good_data */
adjust_poll(inst, 0.1);
}
normalise_score(inst);
/* Reduce polling rate if KoD RATE was received */
if (kod_rate && valid_kod) {
if (inst->remote_poll > inst->minpoll) {
inst->minpoll = inst->remote_poll;
if (inst->minpoll > inst->maxpoll)
inst->maxpoll = inst->minpoll;
if (inst->minpoll > inst->local_poll)
inst->local_poll = inst->minpoll;
LOG(LOGS_WARN, LOGF_NtpCore, "Received KoD RATE from %s, minpoll set to %d", UTI_IPToString(&inst->remote_addr.ip_addr), inst->minpoll);
}
/* Stop ongoing burst */
if (inst->opmode == MD_BURST_WAS_OFFLINE || inst->opmode == MD_BURST_WAS_ONLINE) {
inst->burst_good_samples_to_go = 0;
LOG(LOGS_WARN, LOGF_NtpCore, "Received KoD RATE from %s, burst sampling stopped", UTI_IPToString(&inst->remote_addr.ip_addr), inst->minpoll);
}
}
/* If we're in burst mode, check whether the burst is completed and
@@ -1185,6 +1192,8 @@ receive_packet(NTP_Packet *message, struct timeval *now, NCR_Instance inst, int
switch (inst->opmode) {
case MD_OFFLINE:
requeue_transmit = 0;
/* Mark source unreachable */
SRC_ResetReachability(inst->source);
break; /* Even if we've received something, we don't want to
transmit back. This might be a symmetric active peer
that is trying to talk to us. */
@@ -1219,7 +1228,7 @@ receive_packet(NTP_Packet *message, struct timeval *now, NCR_Instance inst, int
break;
default:
CROAK("Impossible");
assert(0);
break;
}
@@ -1229,25 +1238,16 @@ receive_packet(NTP_Packet *message, struct timeval *now, NCR_Instance inst, int
case MD_BURST_WAS_OFFLINE:
requeue_transmit = 1;
delay_time = 0.0;
delay_time = BURST_INTERVAL;
break;
default:
CROAK("Impossible");
assert(0);
break;
}
/* Reduce polling if KoD RATE was received */
if (kod_rate && valid_kod) {
if (inst->remote_poll > inst->minpoll) {
inst->minpoll = inst->remote_poll;
if (inst->minpoll > inst->maxpoll)
inst->maxpoll = inst->minpoll;
if (inst->minpoll > inst->local_poll)
inst->local_poll = inst->minpoll;
LOG(LOGS_INFO, LOGF_NtpCore, "Received KoD RATE from %s, minpoll set to %d", UTI_IPToString(&inst->remote_addr.ip_addr), inst->minpoll);
}
/* Back off for a while */
delay_time += (double) (4 * (1UL << inst->minpoll));
}
@@ -1256,32 +1256,25 @@ receive_packet(NTP_Packet *message, struct timeval *now, NCR_Instance inst, int
/* Get rid of old timeout and start a new one */
SCH_RemoveTimeout(inst->timeout_id);
inst->timeout_id = SCH_AddTimeoutInClass(delay_time, SAMPLING_SEPARATION,
SAMPLING_RANDOMNESS,
SCH_NtpSamplingClass,
transmit_timeout, (void *)inst);
}
/* Do measurement logging */
if (logfile) {
if (((logwrites++) % 32) == 0) {
fprintf(logfile,
"=====================================================================================================================\n"
" Date (UTC) Time IP Address L St 1234 ab 5678 LP RP SC Offset Peer del. Peer disp. Root del. Root disp.\n"
"=====================================================================================================================\n");
}
fprintf(logfile, "%s %-15s %1c %2d %1d%1d%1d%1d %1d%1d %1d%1d%1d%1d %2d %2d %2d %10.3e %10.3e %10.3e %10.3e %10.3e\n",
if (logfileid != -1) {
LOG_FileWrite(logfileid, "%s %-15s %1c %2d %1d%1d%1d%1d %1d%1d%1d %1d%1d%1d%1d %2d %2d %4.2f %10.3e %10.3e %10.3e %10.3e %10.3e",
UTI_TimeToLogForm(sample_time.tv_sec),
UTI_IPToString(&inst->remote_addr.ip_addr),
sync_stats[pkt_leap],
message->stratum,
test1, test2, test3, test4,
test4a, test4b,
test4a, test4b, test4c,
test5, test6, test7, test8,
inst->local_poll, inst->remote_poll,
(inst->score),
inst->poll_score,
theta, delta, epsilon,
pkt_root_delay, pkt_root_dispersion);
fflush(logfile);
}
@@ -1319,6 +1312,7 @@ static void
process_known
(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*/
@@ -1407,7 +1401,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, inst, do_auth);
receive_packet(message, now, now_err, inst, do_auth);
break;
case MODE_PASSIVE:
/* In this software this case should not arise, we don't
@@ -1417,7 +1411,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, inst, do_auth);
receive_packet(message, now, now_err, inst, do_auth);
break;
case MODE_SERVER:
/* Nonsense - we can't have a preconfigured server */
@@ -1438,14 +1432,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, inst, do_auth);
receive_packet(message, now, now_err, inst, do_auth);
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, inst, do_auth);
receive_packet(message, now, now_err, inst, do_auth);
break;
case MODE_SERVER:
/* RFC1305 error condition. */
@@ -1466,7 +1460,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, inst, do_auth);
receive_packet(message, now, now_err, inst, do_auth);
break;
case MODE_PASSIVE:
/* Error condition in RFC1305. Also, we can't have any
@@ -1475,7 +1469,7 @@ process_known
break;
case MODE_CLIENT:
/* This is a wierd combination - how could it arise? */
receive_packet(message, now, inst, do_auth);
receive_packet(message, now, now_err, inst, do_auth);
break;
case MODE_SERVER:
/* Error condition in RFC1305 */
@@ -1508,10 +1502,10 @@ process_known
and it relates to a source we have an ongoing protocol exchange with */
void
NCR_ProcessNoauthKnown(NTP_Packet *message, struct timeval *now, NCR_Instance inst)
NCR_ProcessNoauthKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance inst)
{
process_known(message, now, inst, 0);
process_known(message, now, now_err, inst, 0);
}
@@ -1520,7 +1514,7 @@ NCR_ProcessNoauthKnown(NTP_Packet *message, struct timeval *now, NCR_Instance in
and we do not recognize its source */
void
NCR_ProcessNoauthUnknown(NTP_Packet *message, struct timeval *now, NTP_Remote_Address *remote_addr)
NCR_ProcessNoauthUnknown(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr)
{
NTP_Mode his_mode;
@@ -1577,9 +1571,9 @@ NCR_ProcessNoauthUnknown(NTP_Packet *message, struct timeval *now, NTP_Remote_Ad
exchange with */
void
NCR_ProcessAuthKnown(NTP_Packet *message, struct timeval *now, NCR_Instance data)
NCR_ProcessAuthKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance data)
{
process_known(message, now, data, 1);
process_known(message, now, now_err, data, 1);
}
@@ -1588,7 +1582,7 @@ NCR_ProcessAuthKnown(NTP_Packet *message, struct timeval *now, NCR_Instance data
the network, and we do not recognize its source */
void
NCR_ProcessAuthUnknown(NTP_Packet *message, struct timeval *now, NTP_Remote_Address *remote_addr)
NCR_ProcessAuthUnknown(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr)
{
NTP_Mode his_mode;
@@ -1655,14 +1649,15 @@ void
NCR_SlewTimes(NCR_Instance inst, struct timeval *when, double dfreq, double doffset)
{
struct timeval prev;
double delta;
prev = inst->local_rx;
UTI_AdjustTimeval(&inst->local_rx, when, &inst->local_rx, dfreq, doffset);
UTI_AdjustTimeval(&inst->local_rx, when, &inst->local_rx, &delta, dfreq, doffset);
#ifdef TRACEON
LOG(LOGS_INFO, LOGF_NtpCore, "rx prev=[%s] new=[%s]",
UTI_TimevalToString(&prev), UTI_TimevalToString(&inst->local_rx));
#endif
prev = inst->local_tx;
UTI_AdjustTimeval(&inst->local_tx, when, &inst->local_tx, dfreq, doffset);
UTI_AdjustTimeval(&inst->local_tx, when, &inst->local_tx, &delta, dfreq, doffset);
#ifdef TRACEON
LOG(LOGS_INFO, LOGF_NtpCore, "tx prev=[%s] new=[%s]",
UTI_TimevalToString(&prev), UTI_TimevalToString(&inst->local_tx));
@@ -1682,8 +1677,9 @@ NCR_TakeSourceOnline(NCR_Instance inst)
if (!inst->timer_running) {
/* We are not already actively polling it */
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s online", UTI_IPToString(&inst->remote_addr.ip_addr));
inst->tx_count = 0;
inst->local_poll = inst->minpoll;
inst->score = (ZONE_WIDTH >> 1);
inst->poll_score = 0.5;
inst->opmode = MD_ONLINE;
start_initial_timeout(inst);
}
@@ -1709,6 +1705,8 @@ NCR_TakeSourceOffline(NCR_Instance inst)
SCH_RemoveTimeout(inst->timeout_id);
inst->timer_running = 0;
inst->opmode = MD_OFFLINE;
/* Mark source unreachable */
SRC_ResetReachability(inst->source);
}
break;
case MD_OFFLINE:
@@ -1762,6 +1760,36 @@ NCR_ModifyMaxdelayratio(NCR_Instance inst, double new_max_delay_ratio)
/* ================================================== */
void
NCR_ModifyMaxdelaydevratio(NCR_Instance inst, double new_max_delay_dev_ratio)
{
inst->max_delay_dev_ratio = new_max_delay_dev_ratio;
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new max delay dev ratio %f",
UTI_IPToString(&inst->remote_addr.ip_addr), new_max_delay_dev_ratio);
}
/* ================================================== */
void
NCR_ModifyMinstratum(NCR_Instance inst, int new_min_stratum)
{
inst->min_stratum = new_min_stratum;
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new minstratum %d",
UTI_IPToString(&inst->remote_addr.ip_addr), new_min_stratum);
}
/* ================================================== */
void
NCR_ModifyPolltarget(NCR_Instance inst, int new_poll_target)
{
inst->poll_target = new_poll_target;
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new polltarget %d",
UTI_IPToString(&inst->remote_addr.ip_addr), new_poll_target);
}
/* ================================================== */
void
NCR_InitiateSampleBurst(NCR_Instance inst, int n_good_samples, int n_total_samples)
{
@@ -1789,6 +1817,7 @@ NCR_InitiateSampleBurst(NCR_Instance inst, int n_good_samples, int n_total_sampl
}
inst->timer_running = 1;
inst->timeout_id = SCH_AddTimeoutInClass(0.0, SAMPLING_SEPARATION,
SAMPLING_RANDOMNESS,
SCH_NtpSamplingClass,
transmit_timeout, (void *) inst);
break;
@@ -1802,13 +1831,14 @@ NCR_InitiateSampleBurst(NCR_Instance inst, int n_good_samples, int n_total_sampl
}
inst->timer_running = 1;
inst->timeout_id = SCH_AddTimeoutInClass(0.0, SAMPLING_SEPARATION,
SAMPLING_RANDOMNESS,
SCH_NtpSamplingClass,
transmit_timeout, (void *) inst);
break;
default:
CROAK("Impossible");
assert(0);
break;
}
}
@@ -1830,7 +1860,7 @@ NCR_ReportSource(NCR_Instance inst, RPT_SourceReport *report, struct timeval *no
report->mode = RPT_NTP_PEER;
break;
default:
CROAK("Impossible");
assert(0);
}
return;
@@ -1876,21 +1906,6 @@ NCR_CheckAccessRestriction(IPAddr *ip_addr)
/* ================================================== */
void
NCR_CycleLogFile(void)
{
if (logfile && logfilename) {
fclose(logfile);
logfile = fopen(logfilename, "a");
if (!logfile) {
LOG(LOGS_WARN, LOGF_NtpCore, "Could not reopen logfile %s", logfilename);
}
logwrites = 0;
}
}
/* ================================================== */
void
NCR_IncrementActivityCounters(NCR_Instance inst, int *online, int *offline,
int *burst_online, int *burst_offline)
@@ -1909,7 +1924,7 @@ NCR_IncrementActivityCounters(NCR_Instance inst, int *online, int *offline,
++*offline;
break;
default:
CROAK("Impossible");
assert(0);
break;
}
}
@@ -1923,3 +1938,10 @@ NCR_GetRemoteAddress(NCR_Instance inst)
}
/* ================================================== */
int NCR_IsSyncPeer(NCR_Instance inst)
{
return SRC_IsSyncPeer(inst->source);
}
/* ================================================== */

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/ntp_core.h,v 1.16 2002/02/28 23:27:12 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -38,6 +34,10 @@
#include "ntp.h"
#include "reports.h"
typedef enum {
NTP_SERVER, NTP_PEER
} NTP_Source_Type;
/* This is a private data type used for storing the instance record for
each source that we are chiming with */
typedef struct NCR_Instance_Record *NCR_Instance;
@@ -46,31 +46,28 @@ typedef struct NCR_Instance_Record *NCR_Instance;
extern void NCR_Initialise(void);
extern void NCR_Finalise(void);
/* Get a new instance for a server */
extern NCR_Instance NCR_GetServerInstance(NTP_Remote_Address *remote_addr, SourceParameters *params);
/* Get a new instance for a peer */
extern NCR_Instance NCR_GetPeerInstance(NTP_Remote_Address *remote_addr, SourceParameters *params);
/* Get a new instance for a server or peer */
extern NCR_Instance NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params);
/* Destroy an instance */
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, NCR_Instance data);
extern void NCR_ProcessNoauthKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance data);
/* 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, NTP_Remote_Address *remote_addr);
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, NCR_Instance data);
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, NTP_Remote_Address *remote_addr);
extern void NCR_ProcessAuthUnknown(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr);
/* Slew receive and transmit times in instance records */
extern void NCR_SlewTimes(NCR_Instance inst, struct timeval *when, double dfreq, double doffset);
@@ -90,6 +87,12 @@ extern void NCR_ModifyMaxdelay(NCR_Instance inst, double new_max_delay);
extern void NCR_ModifyMaxdelayratio(NCR_Instance inst, double new_max_delay_ratio);
extern void NCR_ModifyMaxdelaydevratio(NCR_Instance inst, double new_max_delay_dev_ratio);
extern void NCR_ModifyMinstratum(NCR_Instance inst, int new_min_stratum);
extern void NCR_ModifyPolltarget(NCR_Instance inst, int new_poll_target);
extern void NCR_InitiateSampleBurst(NCR_Instance inst, int n_good_samples, int n_total_samples);
extern void NCR_ReportSource(NCR_Instance inst, RPT_SourceReport *report, struct timeval *now);
@@ -97,11 +100,11 @@ extern void NCR_ReportSource(NCR_Instance inst, RPT_SourceReport *report, struct
extern int NCR_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all);
extern int NCR_CheckAccessRestriction(IPAddr *ip_addr);
extern void NCR_CycleLogFile(void);
extern void NCR_IncrementActivityCounters(NCR_Instance inst, int *online, int *offline,
int *burst_online, int *burst_offline);
extern NTP_Remote_Address *NCR_GetRemoteAddress(NCR_Instance instance);
extern int NCR_IsSyncPeer(NCR_Instance instance);
#endif /* GOT_NTP_CORE_H */

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/ntp_io.c,v 1.24 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -121,6 +117,9 @@ prepare_socket(int family)
return -1;
}
/* Close on exec */
UTI_FdSetCloexec(sock_fd);
/* Make the socket capable of re-using an old address */
if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on_off, sizeof(on_off)) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set reuseaddr socket options");
@@ -281,6 +280,7 @@ read_from_socket(void *anything)
union sockaddr_in46 where_from;
unsigned int flags = 0;
struct timeval now;
double now_err;
NTP_Remote_Address remote_addr;
char cmsgbuf[256];
struct msghdr msg;
@@ -289,7 +289,7 @@ read_from_socket(void *anything)
assert(initialised);
SCH_GetFileReadyTime(&now);
SCH_GetFileReadyTime(&now, &now_err);
iov.iov_base = message.arbitrary;
iov.iov_len = sizeof(message);
@@ -346,27 +346,20 @@ read_from_socket(void *anything)
#ifdef SO_TIMESTAMP
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMP) {
struct timeval tv;
double correction;
memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
correction = LCL_GetOffsetCorrection(&tv);
UTI_AddDoubleToTimeval(&tv, correction, &tv);
#if 0
UTI_DiffTimevalsToDouble(&correction, &now, &tv);
LOG(LOGS_INFO, LOGF_NtpIO, "timestamp diff: %f", correction);
#endif
now = tv;
LCL_CookTime(&tv, &now, &now_err);
}
#endif
}
if (status == NTP_NORMAL_PACKET_SIZE) {
NSR_ProcessReceive((NTP_Packet *) &message.ntp_pkt, &now, &remote_addr);
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, &remote_addr);
NSR_ProcessAuthenticatedReceive((NTP_Packet *) &message.ntp_pkt, &now, now_err, &remote_addr);
} else {
@@ -460,7 +453,14 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr)
if (!cmsglen)
msg.msg_control = NULL;
if (sendmsg(sock_fd, &msg, 0) < 0 && !LOG_RateLimited()) {
if (sendmsg(sock_fd, &msg, 0) < 0 &&
#ifdef ENETUNREACH
errno != ENETUNREACH &&
#endif
#ifdef ENETDOWN
errno != ENETDOWN &&
#endif
!LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_NtpIO, "Could not send to %s:%d : %s",
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port, strerror(errno));
}

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/ntp_io.h,v 1.9 2002/02/28 23:27:12 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

View File

@@ -1,12 +1,9 @@
/*
$Header: /cvs/src/chrony/ntp_sources.c,v 1.18 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -37,6 +34,9 @@
#include "util.h"
#include "logging.h"
#include "local.h"
#include "memory.h"
#include "nameserv.h"
#include "sched.h"
/* ================================================== */
@@ -60,13 +60,25 @@ static int n_sources;
/* The largest number of sources we want to have stored in the hash table */
#define MAX_SOURCES 64
/* Source with unknown address (which may be resolved later) */
struct UnresolvedSource {
char *name;
int port;
NTP_Source_Type type;
SourceParameters params;
struct UnresolvedSource *next;
};
static struct UnresolvedSource *unresolved_sources = NULL;
static int resolving_interval = 0;
static SCH_TimeoutID resolving_id;
/* ================================================== */
/* Forward prototypes */
static void
slew_sources(struct timeval *raw,
struct timeval *cooked,
double dfreq,
double afreq,
double doffset,
int is_step_change,
void *anything);
@@ -171,10 +183,9 @@ find_slot(NTP_Remote_Address *remote_addr, int *slot, int *found)
/* ================================================== */
/* Procedure to add a new server source (to which this machine will be
a client) */
/* Procedure to add a new source */
NSR_Status
NSR_AddServer(NTP_Remote_Address *remote_addr, SourceParameters *params)
NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params)
{
int slot, found;
@@ -196,7 +207,7 @@ NSR_AddServer(NTP_Remote_Address *remote_addr, SourceParameters *params)
return NSR_InvalidAF;
} else {
n_sources++;
records[slot].data = NCR_GetServerInstance(remote_addr, params); /* Will need params passing through */
records[slot].data = NCR_GetInstance(remote_addr, type, params); /* Will need params passing through */
records[slot].remote_addr = NCR_GetRemoteAddress(records[slot].data);
return NSR_Success;
}
@@ -205,34 +216,70 @@ NSR_AddServer(NTP_Remote_Address *remote_addr, SourceParameters *params)
/* ================================================== */
/* Procedure to add a new peer. */
NSR_Status
NSR_AddPeer(NTP_Remote_Address *remote_addr, SourceParameters *params)
static void
resolve_sources(void *arg)
{
int slot, found;
NTP_Remote_Address address;
struct UnresolvedSource *us, **i;
DNS_Status s;
assert(initialised);
memset(&address.local_ip_addr, 0, sizeof (address.local_ip_addr));
#if 0
LOG(LOGS_INFO, LOGF_NtpSources, "IP=%s port=%d", UTI_IPToString(&remote_addr->ip_addr), remote_addr->port);
#endif
DNS_Reload();
/* Find empty bin & check that we don't have the address already */
find_slot(remote_addr, &slot, &found);
if (found) {
return NSR_AlreadyInUse;
for (i = &unresolved_sources; *i; ) {
us = *i;
s = DNS_Name2IPAddress(us->name, &address.ip_addr);
if (s == DNS_TryAgain) {
i = &(*i)->next;
continue;
} else if (s == DNS_Success) {
address.port = us->port;
NSR_AddSource(&address, us->type, &us->params);
} else {
if (n_sources == MAX_SOURCES) {
return NSR_TooManySources;
} else if (remote_addr->ip_addr.family != IPADDR_INET4 &&
remote_addr->ip_addr.family != IPADDR_INET6) {
return NSR_InvalidAF;
} else {
n_sources++;
records[slot].data = NCR_GetPeerInstance(remote_addr, params); /* Will need params passing through */
records[slot].remote_addr = NCR_GetRemoteAddress(records[slot].data);
return NSR_Success;
LOG(LOGS_WARN, LOGF_NtpSources, "Invalid host %s", us->name);
}
*i = us->next;
Free(us->name);
Free(us);
}
if (unresolved_sources) {
/* Try again later */
if (resolving_interval < 9)
resolving_interval++;
resolving_id = SCH_AddTimeoutByDelay(7 * (1 << resolving_interval), resolve_sources, NULL);
} else {
resolving_interval = 0;
}
}
/* ================================================== */
/* Procedure to add a new server or peer source, but instead of an IP address
only a name is provided */
void
NSR_AddUnresolvedSource(char *name, int port, NTP_Source_Type type, SourceParameters *params)
{
struct UnresolvedSource *us, **i;
us = MallocNew(struct UnresolvedSource);
us->name = name;
us->port = port;
us->type = type;
us->params = *params;
us->next = NULL;
for (i = &unresolved_sources; *i; i = &(*i)->next)
;
*i = us;
if (!resolving_interval) {
resolving_interval = 2;
resolving_id = SCH_AddTimeoutByDelay(7 * (1 << resolving_interval), resolve_sources, NULL);
}
}
@@ -245,26 +292,48 @@ NSR_AddPeer(NTP_Remote_Address *remote_addr, SourceParameters *params)
NSR_Status
NSR_RemoveSource(NTP_Remote_Address *remote_addr)
{
int slot, found;
int i, slot, found;
SourceRecord temp_records[N_RECORDS];
assert(initialised);
find_slot(remote_addr, &slot, &found);
if (!found) {
return NSR_NoSuchSource;
} else {
}
n_sources--;
records[slot].remote_addr = NULL;
NCR_DestroyInstance(records[slot].data);
return NSR_Success;
/* Rehash the table to make sure there are no broken probe sequences.
This is costly, but it's not expected to happen frequently. */
memcpy(temp_records, records, sizeof (records));
for (i = 0; i < N_RECORDS; i++) {
records[i].remote_addr = NULL;
}
for (i = 0; i < N_RECORDS; i++) {
if (!temp_records[i].remote_addr)
continue;
find_slot(temp_records[i].remote_addr, &slot, &found);
assert(!found);
records[slot].remote_addr = temp_records[i].remote_addr;
records[slot].data = temp_records[i].data;
}
return NSR_Success;
}
/* ================================================== */
/* This routine is called by ntp_io when a new packet arrives off the network.*/
void
NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, NTP_Remote_Address *remote_addr)
NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr)
{
int slot, found;
@@ -278,9 +347,9 @@ NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, NTP_Remote_Address
find_slot(remote_addr, &slot, &found);
if (found == 2) { /* Must match IP address AND port number */
NCR_ProcessNoauthKnown(message, now, records[slot].data);
NCR_ProcessNoauthKnown(message, now, now_err, records[slot].data);
} else {
NCR_ProcessNoauthUnknown(message, now, remote_addr);
NCR_ProcessNoauthUnknown(message, now, now_err, remote_addr);
}
}
@@ -288,7 +357,7 @@ NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, NTP_Remote_Address
/* 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, NTP_Remote_Address *remote_addr)
NSR_ProcessAuthenticatedReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr)
{
int slot, found;
@@ -296,9 +365,9 @@ NSR_ProcessAuthenticatedReceive(NTP_Packet *message, struct timeval *now, NTP_Re
find_slot(remote_addr, &slot, &found);
if (found == 2) {
NCR_ProcessAuthKnown(message, now, records[slot].data);
NCR_ProcessAuthKnown(message, now, now_err, records[slot].data);
} else {
NCR_ProcessAuthUnknown(message, now, remote_addr);
NCR_ProcessAuthUnknown(message, now, now_err, remote_addr);
}
}
@@ -308,7 +377,6 @@ static void
slew_sources(struct timeval *raw,
struct timeval *cooked,
double dfreq,
double afreq,
double doffset,
int is_step_change,
void *anything)
@@ -336,6 +404,13 @@ 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);
}
any = 0;
for (i=0; i<N_RECORDS; i++) {
if (records[i].remote_addr) {
@@ -347,6 +422,15 @@ NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address)
}
}
if (address->family == IPADDR_UNSPEC) {
struct UnresolvedSource *us;
for (us = unresolved_sources; us; us = us->next) {
any = 1;
us->params.online = 1;
}
}
return any;
}
@@ -355,20 +439,38 @@ NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address)
int
NSR_TakeSourcesOffline(IPAddr *mask, IPAddr *address)
{
int i;
int any;
int i, any, syncpeer;
any = 0;
syncpeer = -1;
for (i=0; i<N_RECORDS; i++) {
if (records[i].remote_addr) {
if (address->family == IPADDR_UNSPEC ||
!UTI_CompareIPs(&records[i].remote_addr->ip_addr, address, mask)) {
any = 1;
if (NCR_IsSyncPeer(records[i].data)) {
syncpeer = i;
continue;
}
NCR_TakeSourceOffline(records[i].data);
}
}
}
/* Take sync peer offline as last to avoid reference switching */
if (syncpeer >= 0) {
NCR_TakeSourceOffline(records[syncpeer].data);
}
if (address->family == IPADDR_UNSPEC) {
struct UnresolvedSource *us;
for (us = unresolved_sources; us; us = us->next) {
any = 1;
us->params.online = 0;
}
}
return any;
}
@@ -450,6 +552,63 @@ NSR_ModifyMaxdelayratio(IPAddr *address, double new_max_delay_ratio)
/* ================================================== */
int
NSR_ModifyMaxdelaydevratio(IPAddr *address, double new_max_delay_dev_ratio)
{
int slot, found;
NTP_Remote_Address addr;
addr.ip_addr = *address;
addr.port = 0;
find_slot(&addr, &slot, &found);
if (found == 0) {
return 0;
} else {
NCR_ModifyMaxdelaydevratio(records[slot].data, new_max_delay_dev_ratio);
return 1;
}
}
/* ================================================== */
int
NSR_ModifyMinstratum(IPAddr *address, int new_min_stratum)
{
int slot, found;
NTP_Remote_Address addr;
addr.ip_addr = *address;
addr.port = 0;
find_slot(&addr, &slot, &found);
if (found == 0) {
return 0;
} else {
NCR_ModifyMinstratum(records[slot].data, new_min_stratum);
return 1;
}
}
/* ================================================== */
int
NSR_ModifyPolltarget(IPAddr *address, int new_poll_target)
{
int slot, found;
NTP_Remote_Address addr;
addr.ip_addr = *address;
addr.port = 0;
find_slot(&addr, &slot, &found);
if (found == 0) {
return 0;
} else {
NCR_ModifyPolltarget(records[slot].data, new_poll_target);
return 1;
}
}
/* ================================================== */
int
NSR_InitiateSampleBurst(int n_good_samples, int n_total_samples,
IPAddr *mask, IPAddr *address)
@@ -499,6 +658,7 @@ void
NSR_GetActivityReport(RPT_ActivityReport *report)
{
int i;
struct UnresolvedSource *us;
report->online = 0;
report->offline = 0;
@@ -511,6 +671,12 @@ NSR_GetActivityReport(RPT_ActivityReport *report)
&report->burst_online, &report->burst_offline);
}
}
/* Add unresolved sources to offline count */
for (us = unresolved_sources; us; us = us->next) {
report->offline++;
}
return;
}

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/ntp_sources.h,v 1.12 2002/02/28 23:27:12 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -45,27 +41,27 @@
typedef enum {
NSR_Success, /* Operation successful */
NSR_NoSuchSource, /* Remove - attempt to remove a source that is not known */
NSR_AlreadyInUse, /* AddServer, AddPeer - attempt to add a source that is already known */
NSR_TooManySources, /* AddServer, AddPeer - too many sources already present */
NSR_InvalidAF /* AddServer, AddPeer - attempt to add a source with invalid address family */
NSR_AlreadyInUse, /* AddSource - attempt to add a source that is already known */
NSR_TooManySources, /* AddSource - too many sources already present */
NSR_InvalidAF /* AddSource - attempt to add a source with invalid address family */
} NSR_Status;
/* Procedure to add a new server source (to which this machine will be
a client) */
extern NSR_Status NSR_AddServer(NTP_Remote_Address *remote_addr, SourceParameters *params);
/* Procedure to add a new server or peer source. */
extern NSR_Status NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params);
/* Procedure to add a new peer source. We will use symmetric active
mode packets when communicating with this source */
extern NSR_Status NSR_AddPeer(NTP_Remote_Address *remote_addr, SourceParameters *params);
/* Procedure to add a new server or peer source with currently unknown address.
The name will be periodically resolved in exponentially increasing intervals
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 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, NTP_Remote_Address *remote_addr);
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, NTP_Remote_Address *remote_addr);
extern void NSR_ProcessAuthenticatedReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr);
/* Initialisation function */
extern void NSR_Initialise(void);
@@ -91,6 +87,12 @@ extern int NSR_ModifyMaxdelay(IPAddr *address, double new_max_delay);
extern int NSR_ModifyMaxdelayratio(IPAddr *address, double new_max_delay_ratio);
extern int NSR_ModifyMaxdelaydevratio(IPAddr *address, double new_max_delay_ratio);
extern int NSR_ModifyMinstratum(IPAddr *address, int new_min_stratum);
extern int NSR_ModifyPolltarget(IPAddr *address, int new_poll_target);
extern int NSR_InitiateSampleBurst(int n_good_samples, int n_total_samples, IPAddr *mask, IPAddr *address);
extern void NSR_ReportSource(RPT_SourceReport *report, struct timeval *now);

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/pktlength.c,v 1.12 2002/02/28 23:27:12 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -65,6 +61,8 @@ PKL_CommandLength(CMD_Request *r)
return offsetof(CMD_Request, data.modify_maxdelay.EOR);
case REQ_MODIFY_MAXDELAYRATIO:
return offsetof(CMD_Request, data.modify_maxdelayratio.EOR);
case REQ_MODIFY_MAXDELAYDEVRATIO:
return offsetof(CMD_Request, data.modify_maxdelaydevratio.EOR);
case REQ_MODIFY_MAXUPDATESKEW:
return offsetof(CMD_Request, data.modify_maxupdateskew.EOR);
case REQ_LOGON :
@@ -147,6 +145,12 @@ PKL_CommandLength(CMD_Request *r)
return offsetof(CMD_Request, data.make_step.EOR);
case REQ_ACTIVITY:
return offsetof(CMD_Request, data.activity.EOR);
case REQ_RESELECT:
return offsetof(CMD_Request, data.reselect.EOR);
case REQ_MODIFY_MINSTRATUM:
return offsetof(CMD_Request, data.modify_minstratum.EOR);
case REQ_MODIFY_POLLTARGET:
return offsetof(CMD_Request, data.modify_polltarget.EOR);
default:
/* If we fall through the switch, it most likely means we've forgotten to implement a new case */
assert(0);

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/pktlength.h,v 1.4 2002/02/28 23:27:12 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2009
* Copyright (C) Miroslav Lichvar 2009-2011
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -33,8 +33,8 @@
#include "util.h"
#include "sources.h"
#include "logging.h"
#include "regress.h"
#include "sched.h"
#include "mkdirpp.h"
/* list of refclock drivers */
extern RefclockDriver RCL_SHM_driver;
@@ -43,6 +43,7 @@ extern RefclockDriver RCL_PPS_driver;
struct FilterSample {
double offset;
double dispersion;
struct timeval sample_time;
};
@@ -51,7 +52,13 @@ struct MedianFilter {
int index;
int used;
int last;
int avg_var_n;
double avg_var;
struct FilterSample *samples;
int *selected;
double *x_data;
double *y_data;
double *w_data;
};
struct RCL_Instance_Record {
@@ -62,7 +69,6 @@ struct RCL_Instance_Record {
int driver_poll;
int driver_polled;
int poll;
int missed_samples;
int leap_status;
int pps_rate;
struct MedianFilter filter;
@@ -70,6 +76,7 @@ struct RCL_Instance_Record {
unsigned long lock_ref;
double offset;
double delay;
double precision;
SCH_TimeoutID timeout_id;
SRC_Instance source;
};
@@ -79,42 +86,35 @@ struct RCL_Instance_Record {
static struct RCL_Instance_Record refclocks[MAX_RCL_SOURCES];
static int n_sources = 0;
#define REFCLOCKS_LOG "refclocks.log"
static FILE *logfile = NULL;
static char *logfilename = NULL;
static unsigned long logwrites = 0;
static LOG_FileID logfileid;
static int valid_sample_time(RCL_Instance instance, struct timeval *tv);
static int pps_stratum(RCL_Instance instance, struct timeval *tv);
static void poll_timeout(void *arg);
static void slew_samples(struct timeval *raw, struct timeval *cooked, double dfreq, double afreq,
static void slew_samples(struct timeval *raw, struct timeval *cooked, double dfreq,
double doffset, int is_step_change, void *anything);
static void log_sample(RCL_Instance instance, struct timeval *sample_time, int pulse, double raw_offset, double cooked_offset);
static void add_dispersion(double dispersion, void *anything);
static void log_sample(RCL_Instance instance, struct timeval *sample_time, int filtered, int pulse, double raw_offset, double cooked_offset, double dispersion);
static void filter_init(struct MedianFilter *filter, int length);
static void filter_fini(struct MedianFilter *filter);
static void filter_reset(struct MedianFilter *filter);
static void filter_add_sample(struct MedianFilter *filter, struct timeval *sample_time, double offset);
static int filter_get_last_sample(struct MedianFilter *filter, struct timeval *sample_time, double *offset);
static double filter_get_avg_sample_dispersion(struct MedianFilter *filter);
static void filter_add_sample(struct MedianFilter *filter, struct timeval *sample_time, double offset, double dispersion);
static int filter_get_last_sample(struct MedianFilter *filter, struct timeval *sample_time, double *offset, double *dispersion);
static int filter_select_samples(struct MedianFilter *filter);
static int filter_get_sample(struct MedianFilter *filter, struct timeval *sample_time, double *offset, double *dispersion);
static void filter_slew_samples(struct MedianFilter *filter, struct timeval *when, double dfreq, double doffset);
static void filter_add_dispersion(struct MedianFilter *filter, double dispersion);
void
RCL_Initialise(void)
{
CNF_AddRefclocks();
if (CNF_GetLogRefclocks()) {
char *logdir = CNF_GetLogDir();
if (!mkdir_and_parents(logdir)) {
LOG(LOGS_ERR, LOGF_Refclock, "Could not create directory %s", logdir);
} else {
logfilename = MallocArray(char, 2 + strlen(logdir) + strlen(REFCLOCKS_LOG));
strcpy(logfilename, logdir);
strcat(logfilename, "/");
strcat(logfilename, REFCLOCKS_LOG);
}
}
logfileid = CNF_GetLogRefclocks() ? LOG_FileOpen("refclocks",
" Date (UTC) Time Refid DP L P Raw offset Cooked offset Disp.")
: -1;
}
void
@@ -132,12 +132,10 @@ RCL_Finalise(void)
Free(inst->driver_parameter);
}
if (n_sources > 0)
if (n_sources > 0) {
LCL_RemoveParameterChangeHandler(slew_samples, NULL);
if (logfile)
fclose(logfile);
Free(logfilename);
LCL_RemoveDispersionNotifyHandler(add_dispersion, NULL);
}
}
int
@@ -152,11 +150,14 @@ RCL_AddRefclock(RefclockParameters *params)
if (strncmp(params->driver_name, "SHM", 4) == 0) {
inst->driver = &RCL_SHM_driver;
inst->precision = 1e-6;
} else if (strncmp(params->driver_name, "SOCK", 4) == 0) {
inst->driver = &RCL_SOCK_driver;
inst->precision = 1e-9;
pps_source = 1;
} else if (strncmp(params->driver_name, "PPS", 4) == 0) {
inst->driver = &RCL_PPS_driver;
inst->precision = 1e-9;
pps_source = 1;
} else {
LOG_FATAL(LOGF_Refclock, "unknown refclock driver %s", params->driver_name);
@@ -173,13 +174,14 @@ RCL_AddRefclock(RefclockParameters *params)
inst->driver_parameter_length = 0;
inst->driver_poll = params->driver_poll;
inst->poll = params->poll;
inst->missed_samples = 0;
inst->driver_polled = 0;
inst->leap_status = 0;
inst->pps_rate = params->pps_rate;
inst->lock_ref = params->lock_ref_id;
inst->offset = params->offset;
inst->delay = params->delay;
if (params->precision > 0.0)
inst->precision = params->precision;
inst->timeout_id = -1;
inst->source = NULL;
@@ -199,18 +201,31 @@ RCL_AddRefclock(RefclockParameters *params)
inst->pps_rate = 0;
}
if (inst->driver_poll > inst->poll)
inst->driver_poll = inst->poll;
if (params->ref_id)
inst->ref_id = params->ref_id;
else {
unsigned char ref[5] = { 0, 0, 0, 0, 0 };
snprintf((char *)ref, 5, "%3s%d", params->driver_name, n_sources % 10);
snprintf((char *)ref, 5, "%3.3s%d", params->driver_name, n_sources % 10);
inst->ref_id = ref[0] << 24 | ref[1] << 16 | ref[2] << 8 | ref[3];
}
if (inst->driver->poll) {
int max_samples;
if (inst->driver_poll > inst->poll)
inst->driver_poll = inst->poll;
max_samples = 1 << (inst->poll - inst->driver_poll);
if (max_samples < params->filter_length) {
if (max_samples < 4) {
LOG(LOGS_WARN, LOGF_Refclock, "Setting filter length for %s to %d",
UTI_RefidToString(inst->ref_id), max_samples);
}
params->filter_length = max_samples;
}
}
if (inst->driver->init)
if (!inst->driver->init(inst)) {
LOG_FATAL(LOGF_Refclock, "refclock %s initialisation failed", params->driver_name);
@@ -219,6 +234,8 @@ RCL_AddRefclock(RefclockParameters *params)
filter_init(&inst->filter, params->filter_length);
inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, params->sel_option, NULL);
#if 0
LOG(LOGS_INFO, LOGF_Refclock, "refclock added poll=%d dpoll=%d filter=%d",
inst->poll, inst->driver_poll, params->filter_length);
@@ -236,7 +253,7 @@ RCL_StartRefclocks(void)
for (i = 0; i < n_sources; i++) {
RCL_Instance inst = &refclocks[i];
inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, NULL);
SRC_SetSelectable(inst->source);
inst->timeout_id = SCH_AddTimeoutByDelay(0.0, poll_timeout, (void *)inst);
if (inst->lock_ref) {
@@ -248,8 +265,10 @@ RCL_StartRefclocks(void)
inst->lock_ref = -1;
}
if (n_sources > 0)
if (n_sources > 0) {
LCL_AddParameterChangeHandler(slew_samples, NULL);
LCL_AddDispersionNotifyHandler(add_dispersion, NULL);
}
}
void
@@ -317,24 +336,24 @@ RCL_GetDriverOption(RCL_Instance instance, char *name)
int
RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset, NTP_Leap leap_status)
{
double correction;
double correction, dispersion;
struct timeval cooked_time;
correction = LCL_GetOffsetCorrection(sample_time);
LCL_GetOffsetCorrection(sample_time, &correction, &dispersion);
UTI_AddDoubleToTimeval(sample_time, correction, &cooked_time);
dispersion += instance->precision + filter_get_avg_sample_dispersion(&instance->filter);
if (!valid_sample_time(instance, sample_time))
return 0;
#if 0
LOG(LOGS_INFO, LOGF_Refclock, "refclock sample offset=%.9f cooked=%.9f",
offset, offset - correction + instance->offset);
#endif
filter_add_sample(&instance->filter, &cooked_time, offset - correction + instance->offset);
filter_add_sample(&instance->filter, &cooked_time, offset - correction + instance->offset, dispersion);
instance->leap_status = leap_status;
log_sample(instance, &cooked_time, 0, offset, offset - correction + instance->offset);
log_sample(instance, &cooked_time, 0, 0, offset, offset - correction + instance->offset, dispersion);
/* for logging purposes */
if (!instance->driver->poll)
instance->driver_polled++;
return 1;
}
@@ -342,18 +361,13 @@ RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset,
int
RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
{
double correction, offset;
double correction, dispersion, offset;
struct timeval cooked_time;
int rate;
struct timeval ref_time;
int is_synchronised, stratum;
double root_delay, root_dispersion, distance;
NTP_Leap leap;
unsigned long ref_id;
correction = LCL_GetOffsetCorrection(pulse_time);
LCL_GetOffsetCorrection(pulse_time, &correction, &dispersion);
UTI_AddDoubleToTimeval(pulse_time, correction, &cooked_time);
dispersion += instance->precision + filter_get_avg_sample_dispersion(&instance->filter);
if (!valid_sample_time(instance, pulse_time))
return 0;
@@ -372,10 +386,10 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
if (instance->lock_ref != -1) {
struct timeval ref_sample_time;
double sample_diff, ref_offset, shift;
double sample_diff, ref_offset, ref_dispersion, shift;
if (!filter_get_last_sample(&refclocks[instance->lock_ref].filter,
&ref_sample_time, &ref_offset))
&ref_sample_time, &ref_offset, &ref_dispersion))
return 0;
UTI_DiffTimevalsToDouble(&sample_diff, &cooked_time, &ref_sample_time);
@@ -390,7 +404,7 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
offset += shift;
if (fabs(ref_offset - offset) >= 0.2 / rate)
if (fabs(ref_offset - offset) + ref_dispersion + dispersion >= 0.2 / rate)
return 0;
#if 0
@@ -398,6 +412,12 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
second, offset, ref_offset - offset, sample_diff);
#endif
} else {
struct timeval ref_time;
int is_synchronised, stratum;
double root_delay, root_dispersion, distance;
NTP_Leap leap;
unsigned long ref_id;
/* Ignore the pulse if we are not well synchronized */
REF_GetReferenceParams(&cooked_time, &is_synchronised, &leap, &stratum,
@@ -415,29 +435,18 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
}
}
#if 0
LOG(LOGS_INFO, LOGF_Refclock, "refclock pulse second=%.9f offset=%.9f",
second, offset);
#endif
filter_add_sample(&instance->filter, &cooked_time, offset);
filter_add_sample(&instance->filter, &cooked_time, offset, dispersion);
instance->leap_status = LEAP_Normal;
log_sample(instance, &cooked_time, 1, second, offset);
log_sample(instance, &cooked_time, 0, 1, second, offset, dispersion);
/* for logging purposes */
if (!instance->driver->poll)
instance->driver_polled++;
return 1;
}
void
RCL_CycleLogFile(void)
{
if (logfile) {
fclose(logfile);
logfile = NULL;
logwrites = 0;
}
}
static int
valid_sample_time(RCL_Instance instance, struct timeval *tv)
{
@@ -470,7 +479,8 @@ pps_stratum(RCL_Instance instance, struct timeval *tv)
/* Or the current source is another PPS refclock */
for (i = 0; i < n_sources; i++) {
if (refclocks[i].ref_id == ref_id && refclocks[i].pps_rate)
if (refclocks[i].ref_id == ref_id &&
refclocks[i].pps_rate && refclocks[i].lock_ref == -1)
return stratum - 1;
}
@@ -499,29 +509,22 @@ poll_timeout(void *arg)
int sample_ok, stratum;
sample_ok = filter_get_sample(&inst->filter, &sample_time, &offset, &dispersion);
filter_reset(&inst->filter);
inst->driver_polled = 0;
if (sample_ok) {
#if 0
LOG(LOGS_INFO, LOGF_Refclock, "refclock filtered sample: offset=%.9f dispersion=%.9f [%s]",
offset, dispersion, UTI_TimevalToString(&sample_time));
#endif
if (inst->pps_rate)
if (inst->pps_rate && inst->lock_ref == -1)
/* Handle special case when PPS is used with local stratum */
stratum = pps_stratum(inst, &sample_time);
else
stratum = 0;
SRC_SetReachable(inst->source);
SRC_UpdateReachability(inst->source, 1);
SRC_AccumulateSample(inst->source, &sample_time, offset,
inst->delay, dispersion, inst->delay, dispersion, stratum, inst->leap_status);
inst->missed_samples = 0;
log_sample(inst, &sample_time, 1, 0, 0.0, offset, dispersion);
} else {
inst->missed_samples++;
if (inst->missed_samples > 9)
SRC_UnsetReachable(inst->source);
SRC_UpdateReachability(inst->source, 0);
}
}
@@ -534,7 +537,7 @@ poll_timeout(void *arg)
}
static void
slew_samples(struct timeval *raw, struct timeval *cooked, double dfreq, double afreq,
slew_samples(struct timeval *raw, struct timeval *cooked, double dfreq,
double doffset, int is_step_change, void *anything)
{
int i;
@@ -544,30 +547,24 @@ slew_samples(struct timeval *raw, struct timeval *cooked, double dfreq, double a
}
static void
log_sample(RCL_Instance instance, struct timeval *sample_time, int pulse, double raw_offset, double cooked_offset)
add_dispersion(double dispersion, void *anything)
{
int i;
for (i = 0; i < n_sources; i++)
filter_add_dispersion(&refclocks[i].filter, dispersion);
}
static void
log_sample(RCL_Instance instance, struct timeval *sample_time, int filtered, int pulse, double raw_offset, double cooked_offset, double dispersion)
{
char sync_stats[4] = {'N', '+', '-', '?'};
if (!logfilename)
if (logfileid == -1)
return;
if (!logfile) {
logfile = fopen(logfilename, "a");
if (!logfile) {
LOG(LOGS_WARN, LOGF_Refclock, "Couldn't open logfile %s for update", logfilename);
Free(logfilename);
logfilename = NULL;
return;
}
}
if (((logwrites++) % 32) == 0) {
fprintf(logfile,
"====================================================================\n"
" Date (UTC) Time Refid DP L P Raw offset Cooked offset\n"
"====================================================================\n");
}
fprintf(logfile, "%s.%06d %-5s %3d %1c %1d %13.6e %13.6e\n",
if (!filtered) {
LOG_FileWrite(logfileid, "%s.%06d %-5s %3d %1c %1d %13.6e %13.6e %10.3e",
UTI_TimeToLogForm(sample_time->tv_sec),
(int)sample_time->tv_usec,
UTI_RefidToString(instance->ref_id),
@@ -575,8 +572,17 @@ log_sample(RCL_Instance instance, struct timeval *sample_time, int pulse, double
sync_stats[instance->leap_status],
pulse,
raw_offset,
cooked_offset);
fflush(logfile);
cooked_offset,
dispersion);
} else {
LOG_FileWrite(logfileid, "%s.%06d %-5s - %1c - - %13.6e %10.3e",
UTI_TimeToLogForm(sample_time->tv_sec),
(int)sample_time->tv_usec,
UTI_RefidToString(instance->ref_id),
sync_stats[instance->leap_status],
cooked_offset,
dispersion);
}
}
static void
@@ -589,13 +595,24 @@ filter_init(struct MedianFilter *filter, int length)
filter->index = -1;
filter->used = 0;
filter->last = -1;
/* set first estimate to system precision */
filter->avg_var_n = 0;
filter->avg_var = LCL_GetSysPrecisionAsQuantum() * LCL_GetSysPrecisionAsQuantum();
filter->samples = MallocArray(struct FilterSample, filter->length);
filter->selected = MallocArray(int, filter->length);
filter->x_data = MallocArray(double, filter->length);
filter->y_data = MallocArray(double, filter->length);
filter->w_data = MallocArray(double, filter->length);
}
static void
filter_fini(struct MedianFilter *filter)
{
Free(filter->samples);
Free(filter->selected);
Free(filter->x_data);
Free(filter->y_data);
Free(filter->w_data);
}
static void
@@ -605,8 +622,14 @@ filter_reset(struct MedianFilter *filter)
filter->used = 0;
}
static double
filter_get_avg_sample_dispersion(struct MedianFilter *filter)
{
return sqrt(filter->avg_var);
}
static void
filter_add_sample(struct MedianFilter *filter, struct timeval *sample_time, double offset)
filter_add_sample(struct MedianFilter *filter, struct timeval *sample_time, double offset, double dispersion)
{
filter->index++;
filter->index %= filter->length;
@@ -616,23 +639,30 @@ filter_add_sample(struct MedianFilter *filter, struct timeval *sample_time, doub
filter->samples[filter->index].sample_time = *sample_time;
filter->samples[filter->index].offset = offset;
filter->samples[filter->index].dispersion = dispersion;
}
static int
filter_get_last_sample(struct MedianFilter *filter, struct timeval *sample_time, double *offset)
filter_get_last_sample(struct MedianFilter *filter, struct timeval *sample_time, double *offset, double *dispersion)
{
if (filter->last < 0)
return 0;
*sample_time = filter->samples[filter->last].sample_time;
*offset = filter->samples[filter->last].offset;
*dispersion = filter->samples[filter->last].dispersion;
return 1;
}
static const struct FilterSample *tmp_sorted_array;
static int
sample_compare(const void *a, const void *b)
{
const struct FilterSample *s1 = a, *s2 = b;
const struct FilterSample *s1, *s2;
s1 = &tmp_sorted_array[*(int *)a];
s2 = &tmp_sorted_array[*(int *)b];
if (s1->offset < s2->offset)
return -1;
@@ -641,54 +671,183 @@ sample_compare(const void *a, const void *b)
return 0;
}
int
filter_select_samples(struct MedianFilter *filter)
{
int i, j, k, o, from, to, *selected;
double min_dispersion;
if (filter->used < 1)
return 0;
/* for lengths below 4 require full filter,
for 4 and above require at least 4 samples */
if ((filter->length < 4 && filter->used != filter->length) ||
(filter->length >= 4 && filter->used < 4))
return 0;
selected = filter->selected;
if (filter->used > 4) {
/* select samples with dispersion better than 1.5 * minimum */
for (i = 1, min_dispersion = filter->samples[0].dispersion; i < filter->used; i++) {
if (min_dispersion > filter->samples[i].dispersion)
min_dispersion = filter->samples[i].dispersion;
}
for (i = j = 0; i < filter->used; i++) {
if (filter->samples[i].dispersion <= 1.5 * min_dispersion)
selected[j++] = i;
}
} else {
j = 0;
}
if (j < 4) {
/* select all samples */
for (j = 0; j < filter->used; j++)
selected[j] = j;
}
/* and sort their indices by offset */
tmp_sorted_array = filter->samples;
qsort(selected, j, sizeof (int), sample_compare);
/* select 60 percent of the samples closest to the median */
if (j > 2) {
from = j / 5;
if (from < 1)
from = 1;
to = j - from;
} else {
from = 0;
to = j;
}
/* mark unused samples and sort the rest from oldest to newest */
o = filter->used - filter->index - 1;
for (i = 0; i < from; i++)
selected[i] = -1;
for (; i < to; i++)
selected[i] = (selected[i] + o) % filter->used;
for (; i < filter->used; i++)
selected[i] = -1;
for (i = from; i < to; i++) {
j = selected[i];
selected[i] = -1;
while (j != -1 && selected[j] != j) {
k = selected[j];
selected[j] = j;
j = k;
}
}
for (i = j = 0, k = -1; i < filter->used; i++) {
if (selected[i] != -1)
selected[j++] = (selected[i] + filter->used - o) % filter->used;
}
return j;
}
static int
filter_get_sample(struct MedianFilter *filter, struct timeval *sample_time, double *offset, double *dispersion)
{
if (filter->used == 0)
struct FilterSample *s, *ls;
int i, n, dof;
double x, y, d, e, var, prev_avg_var;
n = filter_select_samples(filter);
if (n < 1)
return 0;
if (filter->used == 1) {
*sample_time = filter->samples[filter->index].sample_time;
*offset = filter->samples[filter->index].offset;
*dispersion = 0.0;
} else {
int i, from, to;
double x, x1, y, d;
ls = &filter->samples[filter->selected[n - 1]];
/* sort samples by offset */
qsort(filter->samples, filter->used, sizeof (struct FilterSample), sample_compare);
/* prepare data */
for (i = 0; i < n; i++) {
s = &filter->samples[filter->selected[i]];
/* average the half of the samples closest to the median */
if (filter->used > 2) {
from = (filter->used + 2) / 4;
to = filter->used - from;
} else {
from = 0;
to = filter->used;
UTI_DiffTimevalsToDouble(&filter->x_data[i], &s->sample_time, &ls->sample_time);
filter->y_data[i] = s->offset;
filter->w_data[i] = s->dispersion;
}
for (i = from, x = y = 0.0; i < to; i++) {
#if 0
LOG(LOGS_INFO, LOGF_Refclock, "refclock averaging offset %.9f [%s]",
filter->samples[i].offset, UTI_TimevalToString(&filter->samples[i].sample_time));
#endif
UTI_DiffTimevalsToDouble(&x1, &filter->samples[i].sample_time, &filter->samples[0].sample_time);
x += x1;
y += filter->samples[i].offset;
/* mean offset, sample time and sample dispersion */
for (i = 0, x = y = e = 0.0; i < n; i++) {
x += filter->x_data[i];
y += filter->y_data[i];
e += filter->w_data[i];
}
x /= n;
y /= n;
e /= n;
e -= sqrt(filter->avg_var);
if (n >= 4) {
double b0, b1, s2, sb0, sb1;
/* set y axis to the mean sample time */
for (i = 0; i < n; i++)
filter->x_data[i] -= x;
/* make a linear fit and use the estimated standard deviation of intercept
as dispersion */
RGR_WeightedRegression(filter->x_data, filter->y_data, filter->w_data, n,
&b0, &b1, &s2, &sb0, &sb1);
var = s2;
d = sb0;
dof = n - 2;
} else if (n >= 2) {
for (i = 0, d = 0.0; i < n; i++)
d += (filter->y_data[i] - y) * (filter->y_data[i] - y);
var = d / (n - 1);
d = sqrt(var);
dof = n - 1;
} else {
var = filter->avg_var;
d = sqrt(var);
dof = 1;
}
x /= to - from;
y /= to - from;
/* avoid having zero dispersion */
if (var < 1e-20) {
var = 1e-20;
d = sqrt(var);
}
for (i = from, d = 0.0; i < to; i++)
d += (filter->samples[i].offset - y) * (filter->samples[i].offset - y);
prev_avg_var = filter->avg_var;
d = sqrt(d / (to - from));
/* update exponential moving average of the variance */
if (filter->avg_var_n > 100) {
filter->avg_var += dof / (dof + 100.0) * (var - filter->avg_var);
} else {
filter->avg_var = (filter->avg_var * filter->avg_var_n + var * dof) /
(dof + filter->avg_var_n);
if (filter->avg_var_n == 0)
prev_avg_var = filter->avg_var;
filter->avg_var_n += dof;
}
UTI_AddDoubleToTimeval(&filter->samples[0].sample_time, x, sample_time);
/* reduce noise in sourcestats weights by using the long-term average
instead of the estimated variance if it's not significantly lower */
if (var * dof / RGR_GetChi2Coef(dof) < prev_avg_var)
d = sqrt(filter->avg_var) * d / sqrt(var);
if (d < e)
d = e;
UTI_AddDoubleToTimeval(&ls->sample_time, x, sample_time);
*offset = y;
*dispersion = d;
}
filter_reset(filter);
return 1;
}
@@ -697,16 +856,12 @@ static void
filter_slew_samples(struct MedianFilter *filter, struct timeval *when, double dfreq, double doffset)
{
int i;
double elapsed, delta_time, prev_offset;
double delta_time, prev_offset;
struct timeval *sample;
for (i = 0; i < filter->used; i++) {
sample = &filter->samples[i].sample_time;
UTI_DiffTimevalsToDouble(&elapsed, when, sample);
delta_time = elapsed * dfreq - doffset;
UTI_AddDoubleToTimeval(sample, delta_time, sample);
UTI_AdjustTimeval(sample, when, sample, &delta_time, dfreq, doffset);
prev_offset = filter->samples[i].offset;
filter->samples[i].offset -= delta_time;
#if 0
@@ -715,3 +870,13 @@ filter_slew_samples(struct MedianFilter *filter, struct timeval *when, double df
#endif
}
}
static void
filter_add_dispersion(struct MedianFilter *filter, double dispersion)
{
int i;
for (i = 0; i < filter->used; i++) {
filter->samples[i].dispersion += dispersion;
}
}

View File

@@ -42,6 +42,8 @@ typedef struct {
unsigned long lock_ref_id;
double offset;
double delay;
double precision;
SRC_SelectOption sel_option;
} RefclockParameters;
typedef struct RCL_Instance_Record *RCL_Instance;
@@ -58,7 +60,6 @@ extern int RCL_AddRefclock(RefclockParameters *params);
extern void RCL_StartRefclocks(void);
extern void RCL_StartRefclocks(void);
extern void RCL_ReportSource(RPT_SourceReport *report, struct timeval *now);
extern void RCL_CycleLogFile(void);
/* functions used by drivers */
extern void RCL_SetDriverData(RCL_Instance instance, void *data);

View File

@@ -57,6 +57,8 @@ static int pps_initialise(RCL_Instance instance) {
return 0;
}
UTI_FdSetCloexec(fd);
if (time_pps_create(fd, &handle) < 0) {
LOG_FATAL(LOGF_Refclock, "time_pps_create() failed on %s", path);
return 0;
@@ -93,6 +95,7 @@ static int pps_initialise(RCL_Instance instance) {
return 0;
}
pps = MallocNew(struct pps_instance);
pps->handle = handle;
pps->last_seq = 0;

View File

@@ -105,6 +105,8 @@ static int sock_initialise(RCL_Instance instance)
return 0;
}
UTI_FdSetCloexec(sockfd);
unlink(path);
if (bind(sockfd, (struct sockaddr *)&s, sizeof (s)) < 0) {
LOG_FATAL(LOGF_Refclock, "bind() failed");

View File

@@ -1,13 +1,9 @@
/*
$Header: /cvs/src/chrony/reference.c,v 1.42 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009
* Copyright (C) Miroslav Lichvar 2009-2011
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -37,7 +33,7 @@
#include "conf.h"
#include "logging.h"
#include "local.h"
#include "mkdirpp.h"
#include "sched.h"
/* ================================================== */
@@ -76,18 +72,15 @@ static char *mail_change_user;
/* Filename of the drift file. */
static char *drift_file=NULL;
static double drift_file_age;
static void update_drift_file(double, double);
#define MAIL_PROGRAM "/usr/lib/sendmail"
/* ================================================== */
/* File to which statistics are logged, NULL if none */
static FILE *logfile = NULL;
static char *logfilename = NULL;
static unsigned long logwrites = 0;
#define TRACKING_LOG "tracking.log"
static LOG_FileID logfileid;
/* ================================================== */
@@ -96,10 +89,30 @@ static unsigned long logwrites = 0;
/* ================================================== */
/* Exponential moving averages of absolute clock frequencies
used as a fallback when synchronisation is lost. */
struct fb_drift {
double freq;
double secs;
};
static int fb_drift_min;
static int fb_drift_max;
static struct fb_drift *fb_drifts = NULL;
static int next_fb_drift;
static SCH_TimeoutID fb_drift_timeout_id;
/* Timestamp of last reference update */
static struct timeval last_ref_update;
static double last_ref_update_interval;
/* ================================================== */
void
REF_Initialise(void)
{
char *direc;
FILE *in;
char line[1024];
double file_freq_ppm, file_skew_ppm;
@@ -139,27 +152,14 @@ REF_Initialise(void)
drift_file);
}
update_drift_file(our_frequency_ppm,our_skew);
drift_file_age = 0.0;
}
LCL_SetAbsoluteFrequency(our_frequency_ppm);
if (CNF_GetLogTracking()) {
direc = CNF_GetLogDir();
if (!mkdir_and_parents(direc)) {
LOG(LOGS_ERR, LOGF_Reference, "Could not create directory %s", direc);
logfile = NULL;
} else {
logfilename = MallocArray(char, 2 + strlen(direc) + strlen(TRACKING_LOG));
strcpy(logfilename, direc);
strcat(logfilename, "/");
strcat(logfilename, TRACKING_LOG);
logfile = fopen(logfilename, "a");
if (!logfile) {
LOG(LOGS_WARN, LOGF_Reference, "Couldn't open logfile %s for update", logfilename);
}
}
}
logfileid = CNF_GetLogTracking() ? LOG_FileOpen("tracking",
" Date (UTC) Time IP Address St Freq ppm Skew ppm Offset")
: -1;
max_update_skew = fabs(CNF_GetMaxUpdateSkew()) * 1.0e-6;
@@ -169,11 +169,26 @@ REF_Initialise(void)
CNF_GetLogChange(&do_log_change, &log_change_threshold);
CNF_GetMailOnChange(&do_mail_change, &mail_change_threshold, &mail_change_user);
CNF_GetFallbackDrifts(&fb_drift_min, &fb_drift_max);
if (fb_drift_max >= fb_drift_min && fb_drift_min > 0) {
fb_drifts = MallocArray(struct fb_drift, fb_drift_max - fb_drift_min + 1);
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;
}
/* And just to prevent anything wierd ... */
if (do_log_change) {
log_change_threshold = fabs(log_change_threshold);
}
/* Make first entry in tracking log */
REF_SetUnsynchronised();
return;
}
@@ -186,10 +201,12 @@ REF_Finalise(void)
LCL_SetLeap(0);
}
if (logfile) {
fclose(logfile);
if (drift_file && drift_file_age > 0.0) {
update_drift_file(LCL_ReadAbsoluteFrequency(), our_skew);
}
Free(fb_drifts);
initialised = 0;
return;
}
@@ -269,6 +286,117 @@ update_drift_file(double freq_ppm, double skew)
/* ================================================== */
static void
update_fb_drifts(double freq_ppm, double update_interval)
{
int i, secs;
assert(are_we_synchronised);
if (next_fb_drift > 0) {
#if 0
/* Reset drifts that were used when we were unsynchronised */
for (i = 0; i < next_fb_drift - fb_drift_min; i++)
fb_drifts[i].secs = 0.0;
#endif
next_fb_drift = 0;
}
if (fb_drift_timeout_id != -1) {
SCH_RemoveTimeout(fb_drift_timeout_id);
fb_drift_timeout_id = -1;
}
if (update_interval < 0.0 || update_interval > last_ref_update_interval * 4.0)
return;
for (i = 0; i < fb_drift_max - fb_drift_min + 1; i++) {
/* Don't allow differences larger than 10 ppm */
if (fabs(freq_ppm - fb_drifts[i].freq) > 10.0)
fb_drifts[i].secs = 0.0;
secs = 1 << (i + fb_drift_min);
if (fb_drifts[i].secs < secs) {
/* Calculate average over 2 * secs interval before switching to
exponential updating */
fb_drifts[i].freq = (fb_drifts[i].freq * fb_drifts[i].secs +
update_interval * 0.5 * freq_ppm) / (update_interval * 0.5 + fb_drifts[i].secs);
fb_drifts[i].secs += update_interval * 0.5;
} else {
/* Update exponential moving average. The smoothing factor for update
interval equal to secs is about 0.63, for half interval about 0.39,
for double interval about 0.86. */
fb_drifts[i].freq += (1 - 1.0 / exp(update_interval / secs)) *
(freq_ppm - fb_drifts[i].freq);
}
#if 0
LOG(LOGS_INFO, LOGF_Reference, "Fallback drift %d updated: %f ppm %f seconds",
i + fb_drift_min, fb_drifts[i].freq, fb_drifts[i].secs);
#endif
}
}
/* ================================================== */
static void
fb_drift_timeout(void *arg)
{
assert(are_we_synchronised == 0);
assert(next_fb_drift >= fb_drift_min && next_fb_drift <= fb_drift_max);
fb_drift_timeout_id = -1;
LCL_SetAbsoluteFrequency(fb_drifts[next_fb_drift - fb_drift_min].freq);
REF_SetUnsynchronised();
}
/* ================================================== */
static void
schedule_fb_drift(struct timeval *now)
{
int i, c, secs;
double unsynchronised;
struct timeval when;
if (fb_drift_timeout_id != -1)
return; /* already scheduled */
UTI_DiffTimevalsToDouble(&unsynchronised, now, &last_ref_update);
for (c = 0, i = fb_drift_min; i <= fb_drift_max; i++) {
secs = 1 << i;
if (fb_drifts[i - fb_drift_min].secs < secs)
continue;
if (unsynchronised < secs && i > next_fb_drift)
break;
c = i;
}
if (c > next_fb_drift) {
LCL_SetAbsoluteFrequency(fb_drifts[c - fb_drift_min].freq);
next_fb_drift = c;
#if 0
LOG(LOGS_INFO, LOGF_Reference, "Fallback drift %d set", c);
#endif
}
if (i <= fb_drift_max) {
next_fb_drift = i;
UTI_AddDoubleToTimeval(now, secs - unsynchronised, &when);
fb_drift_timeout_id = SCH_AddTimeout(&when, fb_drift_timeout, NULL);
#if 0
LOG(LOGS_INFO, LOGF_Reference, "Fallback drift %d scheduled", i);
#endif
}
}
/* ================================================== */
#define BUFLEN 255
#define S_MAX_USER_LEN "128"
@@ -377,19 +505,9 @@ update_leap_status(NTP_Leap leap)
static void
write_log(struct timeval *ref_time, char *ref, int stratum, double freq, double skew, double offset)
{
if (logfile) {
if (((logwrites++) % 32) == 0) {
fprintf(logfile,
"=======================================================================\n"
" Date (UTC) Time IP Address St Freq ppm Skew ppm Offset\n"
"=======================================================================\n");
}
fprintf(logfile, "%s %-15s %2d %10.3f %10.3f %10.3e\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);
fflush(logfile);
}
}
@@ -417,13 +535,15 @@ REF_SetReference(int stratum,
double abs_freq_ppm;
double update_interval;
assert(initialised);
/* Avoid getting NaNs */
if (skew == 0.0)
skew = 1e-10;
if (our_skew == 0.0)
our_skew = 1e-10;
if (skew < 1e-12)
skew = 1e-12;
if (our_skew < 1e-12)
our_skew = 1e-12;
/* If we get a serious rounding error in the source stats regression
processing, there is a remote chance that the skew argument is a
@@ -516,9 +636,24 @@ REF_SetReference(int stratum,
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;
if (drift_file_age < 0.0 || drift_file_age > 3600.0) {
update_drift_file(abs_freq_ppm, our_skew);
drift_file_age = 0.0;
}
}
/* Update fallback drifts */
if (fb_drifts) {
update_fb_drifts(abs_freq_ppm, update_interval);
}
last_ref_update = *ref_time;
last_ref_update_interval = update_interval;
/* And now set the freq and offset to zero */
our_frequency = 0.0;
@@ -573,11 +708,14 @@ REF_SetUnsynchronised(void)
{
/* Variables required for logging to statistics log */
struct timeval now;
double local_clock_err;
assert(initialised);
LCL_ReadCookedTime(&now, &local_clock_err);
LCL_ReadCookedTime(&now, NULL);
if (fb_drifts) {
schedule_fb_drift(&now);
}
write_log(&now,
"0.0.0.0",
@@ -618,7 +756,7 @@ REF_GetReferenceParams
*stratum = our_stratum;
UTI_DiffTimevalsToDouble(&elapsed, local_time, &our_ref_time);
extra_dispersion = (our_skew + fabs(our_residual_freq)) * elapsed;
extra_dispersion = (our_skew + fabs(our_residual_freq) + LCL_GetMaxClockError()) * elapsed;
*leap_status = our_leap_status;
*ref_id = our_ref_id;
@@ -725,13 +863,13 @@ REF_GetTrackingReport(RPT_TrackingReport *rep)
double correction;
LCL_ReadRawTime(&now_raw);
correction = LCL_GetOffsetCorrection(&now_raw);
LCL_GetOffsetCorrection(&now_raw, &correction, NULL);
UTI_AddDoubleToTimeval(&now_raw, correction, &now_cooked);
if (are_we_synchronised) {
UTI_DiffTimevalsToDouble(&elapsed, &now_cooked, &our_ref_time);
extra_dispersion = (our_skew + fabs(our_residual_freq)) * elapsed;
extra_dispersion = (our_skew + fabs(our_residual_freq) + LCL_GetMaxClockError()) * elapsed;
rep->ref_id = our_ref_id;
rep->ip_addr = our_ref_ip;
@@ -775,18 +913,3 @@ REF_GetTrackingReport(RPT_TrackingReport *rep)
}
/* ================================================== */
void
REF_CycleLogFile(void)
{
if (logfile && logfilename) {
fclose(logfile);
logfile = fopen(logfilename, "a");
if (!logfile) {
LOG(LOGS_WARN, LOGF_Reference, "Could not reopen logfile %s", logfilename);
}
logwrites = 0;
}
}
/* ================================================== */

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/reference.h,v 1.13 2002/02/28 23:27:12 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -144,6 +140,4 @@ extern int REF_IsLocalActive(void);
extern void REF_GetTrackingReport(RPT_TrackingReport *rep);
extern void REF_CycleLogFile(void);
#endif /* GOT_REFERENCE_H */

106
regress.c
View File

@@ -1,12 +1,9 @@
/*
$Header: /cvs/src/chrony/regress.c,v 1.32 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011
*
* 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
@@ -69,9 +66,7 @@ RGR_WeightedRegression
double u, ui, aa;
int i;
if (n<3) {
CROAK("Insufficient points");
}
assert(n >= 3);
W = U = 0;
for (i=0; i<n; i++) {
@@ -135,6 +130,30 @@ RGR_GetTCoef(int dof)
}
}
/* ================================================== */
/* Get 90% quantile of chi-square distribution */
double
RGR_GetChi2Coef(int dof)
{
static double coefs[] = {
2.706, 4.605, 6.251, 7.779, 9.236, 10.645, 12.017, 13.362,
14.684, 15.987, 17.275, 18.549, 19.812, 21.064, 22.307, 23.542,
24.769, 25.989, 27.204, 28.412, 29.615, 30.813, 32.007, 33.196,
34.382, 35.563, 36.741, 37.916, 39.087, 40.256, 41.422, 42.585,
43.745, 44.903, 46.059, 47.212, 48.363, 49.513, 50.660, 51.805,
52.949, 54.090, 55.230, 56.369, 57.505, 58.641, 59.774, 60.907,
62.038, 63.167, 64.295, 65.422, 66.548, 67.673, 68.796, 69.919,
71.040, 72.160, 73.279, 74.397, 75.514, 76.630, 77.745, 78.860
};
if (dof <= 64) {
return coefs[dof-1];
} else {
return 1.2 * dof; /* Until I can be bothered to do something better */
}
}
/* ================================================== */
/* Structure used for holding results of each regression */
@@ -150,23 +169,23 @@ typedef struct {
} RegressionResult;
/* ================================================== */
/* Critical value for number of runs of residuals with same sign. 10%
critical region for now */
/* Critical value for number of runs of residuals with same sign.
5% critical region for now. */
static int critical_runs10[] =
{ 0, 0, 0, 0, 0, 0, 0, 0, 3, 3,
4, 4, 4, 4, 5, 5, 6, 6, 7, 7,
7, 8, 8, 9, 9, 10, 10, 10, 11, 11,
12, 12, 13, 13, 14, 14, 14, 15, 15, 16,
16, 17, 17, 18, 18, 18, 19, 19, 20, 20,
/* Note that 66 onwards are bogus - I haven't worked out the
critical values */
21, 21, 22, 22, 23, 23, 23, 24, 24, 25,
25, 26, 26, 27, 27, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28
static char critical_runs[] = {
0, 0, 0, 0, 0, 0, 0, 0, 2, 3,
3, 3, 4, 4, 5, 5, 5, 6, 6, 7,
7, 7, 8, 8, 9, 9, 9, 10, 10, 11,
11, 11, 12, 12, 13, 13, 14, 14, 14, 15,
15, 16, 16, 17, 17, 18, 18, 18, 19, 19,
20, 20, 21, 21, 21, 22, 22, 23, 23, 24,
24, 25, 25, 26, 26, 26, 27, 27, 28, 28,
29, 29, 30, 30, 30, 31, 31, 32, 32, 33,
33, 34, 34, 35, 35, 35, 36, 36, 37, 37,
38, 38, 39, 39, 40, 40, 40, 41, 41, 42,
42, 43, 43, 44, 44, 45, 45, 46, 46, 46,
47, 47, 48, 48, 49, 49, 50, 50, 51, 51,
52, 52, 52, 53, 53, 54, 54, 55, 55, 56
};
/* ================================================== */
@@ -194,7 +213,6 @@ n_runs_from_residuals(double *resid, int n)
/* Return a boolean indicating whether we had enough points for
regression */
#define RESID_SIZE 1024
#define MIN_SAMPLES_FOR_REGRESS 3
int
@@ -205,6 +223,9 @@ RGR_FindBestRegression
less reliable) */
int n, /* number of data points */
int m, /* number of extra samples in x and y arrays
(negative index) which can be used to
extend runs test */
/* And now the results */
@@ -228,13 +249,16 @@ RGR_FindBestRegression
)
{
double P, Q, U, V, W; /* total */
double resid[RESID_SIZE];
double resid[MAX_POINTS * REGRESS_RUNS_RATIO];
double ss;
double a, b, u, ui, aa;
int start, nruns, npoints, npoints_left;
int start, resid_start, nruns, npoints;
int i;
assert(n <= MAX_POINTS);
assert(n * REGRESS_RUNS_RATIO < sizeof (critical_runs) / sizeof (critical_runs[0]));
if (n < MIN_SAMPLES_FOR_REGRESS) {
return 0;
}
@@ -258,20 +282,22 @@ RGR_FindBestRegression
V += ui * ui / w[i];
}
npoints = n - start;
b = Q / V;
a = (P / W) - (b * u);
for (i=start; i<n; i++) {
resid[i] = y[i] - a - b*x[i];
/* Get residuals also for the extra samples before start */
resid_start = n - (n - start) * REGRESS_RUNS_RATIO;
if (resid_start < -m)
resid_start = -m;
for (i=resid_start; i<n; i++) {
resid[i - resid_start] = y[i] - a - b*x[i];
}
/* Count number of runs */
nruns = n_runs_from_residuals(resid + start, npoints);
nruns = n_runs_from_residuals(resid, n - resid_start);
npoints_left = n - start - 1;
if ((nruns > critical_runs10[npoints]) || (npoints_left < MIN_SAMPLES_FOR_REGRESS)) {
if (nruns > critical_runs[n - resid_start] || n - start <= MIN_SAMPLES_FOR_REGRESS) {
break;
} else {
/* Try dropping one sample at a time until the runs test passes. */
@@ -286,7 +312,7 @@ RGR_FindBestRegression
ss = 0.0;
for (i=start; i<n; i++) {
ss += resid[i]*resid[i] / w[i];
ss += resid[i - resid_start]*resid[i - resid_start] / w[i];
}
npoints = n - start;
@@ -332,9 +358,7 @@ find_ordered_entry_with_flags(double *x, int n, int index, int *flags)
double piv;
int pivind;
if (index < 0) {
CROAK("Negative index");
}
assert(index >= 0);
/* If this bit of the array is already sorted, simple! */
if (flags[index]) {
@@ -378,8 +402,6 @@ find_ordered_entry_with_flags(double *x, int n, int index, int *flags)
v = r - 1;
} else if (index > r) {
u = l;
} else {
CROAK("Impossible");
}
}
} while (1);
@@ -498,6 +520,8 @@ RGR_FindBestRobustRegression
double mx, dx, my, dy;
int nruns = 0;
assert(n < MAX_POINTS);
if (n < 2) {
return 0;
} else if (n == 2) {
@@ -591,7 +615,7 @@ RGR_FindBestRobustRegression
bhi = bmid;
rhi = rmid;
} else {
CROAK("Impossible");
assert(0);
}
} while ((bhi - blo) > tol);
@@ -610,7 +634,7 @@ RGR_FindBestRobustRegression
nruns = n_runs_from_residuals(resids + start, n_points);
if (nruns > critical_runs10[n_points]) {
if (nruns > critical_runs[n_points]) {
break;
} else {
start++;

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/regress.h,v 1.13 2002/02/28 23:27:13 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -61,6 +57,15 @@ RGR_WeightedRegression
extern double RGR_GetTCoef(int dof);
/* Return the value to apply to the variance to make an upper one-sided
test assuming a chi-square distribution. */
extern double RGR_GetChi2Coef(int dof);
/* Maximum ratio of number of points used for runs test to number of regression
points */
#define REGRESS_RUNS_RATIO 2
/* Return a status indicating whether there were enough points to
carry out the regression */
@@ -72,6 +77,9 @@ RGR_FindBestRegression
less reliable) */
int n, /* number of data points */
int m, /* number of extra samples in x and y arrays
(negative index) which can be used to
extend runs test */
/* And now the results */

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/reports.h,v 1.17 2002/02/28 23:27:13 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -41,7 +37,7 @@ typedef struct {
int stratum;
int poll;
enum {RPT_NTP_CLIENT, RPT_NTP_PEER, RPT_LOCAL_REFERENCE} mode;
enum {RPT_SYNC, RPT_UNREACH, RPT_FALSETICKER, RPT_JITTERY, RPT_OTHER} state;
enum {RPT_SYNC, RPT_UNREACH, RPT_FALSETICKER, RPT_JITTERY, RPT_CANDIDATE} state;
unsigned long latest_meas_ago; /* seconds */
double orig_latest_meas; /* seconds */

23
rtc.c
View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/rtc.c,v 1.14 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -50,7 +46,6 @@ static struct {
int (*write_parameters)(void);
int (*get_report)(RPT_RTC_Report *report);
int (*trim)(void);
void (*cycle_logfile)(void);
} driver =
{
#if defined LINUX && defined FEAT_RTC
@@ -61,8 +56,7 @@ static struct {
RTC_Linux_StartMeasurements,
RTC_Linux_WriteParameters,
RTC_Linux_GetReport,
RTC_Linux_Trim,
RTC_Linux_CycleLogFile
RTC_Linux_Trim
#else
NULL,
NULL,
@@ -71,7 +65,6 @@ static struct {
NULL,
NULL,
NULL,
NULL,
NULL
#endif
};
@@ -89,6 +82,10 @@ RTC_Initialise(void)
file_name = CNF_GetRtcFile();
if (file_name) {
if (CNF_GetRTCSync()) {
LOG_FATAL(LOGF_Rtc, "rtcfile directive cannot be used with rtcsync");
}
if (driver.init) {
if ((driver.init)()) {
ok = 1;
@@ -210,13 +207,3 @@ RTC_Trim(void)
/* ================================================== */
void
RTC_CycleLogFile(void)
{
if (driver_initialised) {
(driver.cycle_logfile)();
}
}
/* ================================================== */

6
rtc.h
View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/rtc.h,v 1.9 2002/02/28 23:27:13 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -47,6 +43,4 @@ extern int RTC_WriteParameters(void);
extern int RTC_Trim(void);
extern void RTC_CycleLogFile(void);
#endif /* GOT_RTC_H */

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/rtc_linux.c,v 1.32 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -61,7 +57,6 @@
#include "io_linux.h"
#include "conf.h"
#include "memory.h"
#include "mkdirpp.h"
struct rtc_time {
int tm_sec;
@@ -180,11 +175,7 @@ static int rtc_on_utc = 1;
/* ================================================== */
static FILE *logfile=NULL;
static char *logfilename = NULL;
static unsigned long logwrites=0;
#define RTC_LOG "rtc.log"
static LOG_FileID logfileid;
/* ================================================== */
@@ -198,12 +189,7 @@ discard_samples(int new_first)
{
int n_to_save;
if (!(new_first < n_samples)) {
CROAK("new_first should be < n_samples");
}
if (!(new_first >= 0)) {
CROAK("new_first should be non-negative");
}
assert(new_first >= 0 && new_first < n_samples);
n_to_save = n_samples - new_first;
@@ -307,27 +293,17 @@ run_regression(int new_sample,
static void
slew_samples
(struct timeval *raw, struct timeval *cooked,
double dfreq, double afreq_ppm,
double dfreq,
double doffset, int is_step_change,
void *anything)
{
int i;
double elapsed;
double new_freq;
double old_freq;
double delta_time;
double old_seconds_fast, old_gain_rate;
new_freq = 1.0e-6 * afreq_ppm;
old_freq = (new_freq - dfreq) / (1.0 - dfreq);
for (i=0; i<n_samples; i++) {
UTI_DiffTimevalsToDouble(&elapsed, cooked, system_times + i);
delta_time = -(elapsed * dfreq) - doffset;
UTI_AddDoubleToTimeval(system_times + i, delta_time, system_times + i);
UTI_AdjustTimeval(system_times + i, cooked, system_times + i, &delta_time,
dfreq, doffset);
}
old_seconds_fast = coef_seconds_fast;
@@ -335,12 +311,12 @@ slew_samples
if (coefs_valid) {
coef_seconds_fast += doffset;
coef_gain_rate = 1.0 - ((1.0 + new_freq) / (1.0 + old_freq)) * (1.0 - coef_gain_rate);
coef_gain_rate = (1.0 + dfreq) * (1.0 + coef_gain_rate) - 1.0;
}
#if 0
LOG(LOGS_INFO, LOGF_RtcLinux, "dfreq=%.8f doffset=%.6f new_freq=%.3f old_freq=%.3f old_fast=%.6f old_rate=%.3f new_fast=%.6f new_rate=%.3f",
dfreq, doffset, 1.0e6*new_freq, 1.0e6*old_freq,
LOG(LOGS_INFO, LOGF_RtcLinux, "dfreq=%.8f doffset=%.6f old_fast=%.6f old_rate=%.3f new_fast=%.6f new_rate=%.3f",
dfreq, doffset,
old_seconds_fast, 1.0e6 * old_gain_rate,
coef_seconds_fast, 1.0e6 * coef_gain_rate);
#endif
@@ -542,7 +518,6 @@ int
RTC_Linux_Initialise(void)
{
int major, minor, patch;
char *direc;
/* Check whether we can support the real time clock.
@@ -612,6 +587,9 @@ RTC_Linux_Initialise(void)
return 0;
}
/* Close on exec */
UTI_FdSetCloexec(fd);
n_samples = 0;
n_samples_since_regression = 0;
n_runs = 0;
@@ -627,18 +605,9 @@ RTC_Linux_Initialise(void)
/* Register slew handler */
LCL_AddParameterChangeHandler(slew_samples, NULL);
if (CNF_GetLogRtc()) {
direc = CNF_GetLogDir();
if (!mkdir_and_parents(direc)) {
LOG(LOGS_ERR, LOGF_RtcLinux, "Could not create directory %s", direc);
} else {
logfilename = MallocArray(char, 2 + strlen(direc) + strlen(RTC_LOG));
strcpy(logfilename, direc);
strcat(logfilename, "/");
strcat(logfilename, RTC_LOG);
}
}
logfileid = CNF_GetLogRtc() ? LOG_FileOpen("rtc",
" Date (UTC) Time RTC fast (s) Val Est fast (s) Slope (ppm) Ns Nr Meas")
: -1;
return 1;
}
@@ -661,11 +630,6 @@ RTC_Linux_Finalise(void)
(void) RTC_Linux_WriteParameters();
}
if (logfile) {
fclose(logfile);
}
Free(logfilename);
}
/* ================================================== */
@@ -832,38 +796,19 @@ process_reading(time_t rtc_time, struct timeval *system_time)
}
break;
default:
CROAK("Impossible");
assert(0);
break;
}
if (logfilename) {
if (!logfile) {
logfile = fopen(logfilename, "a");
if (!logfile) {
LOG(LOGS_WARN, LOGF_RtcLinux, "Couldn't open logfile %s for update", logfilename);
Free(logfilename);
logfilename = NULL;
return;
}
}
if (logfileid != -1) {
rtc_fast = (double)(rtc_time - system_time->tv_sec) - 1.0e-6 * (double) system_time->tv_usec;
if (((logwrites++) % 32) == 0) {
fprintf(logfile,
"===============================================================================\n"
" Date (UTC) Time RTC fast (s) Val Est fast (s) Slope (ppm) Ns Nr Meas\n"
"===============================================================================\n");
}
fprintf(logfile, "%s %14.6f %1d %14.6f %12.3f %2d %2d %4d\n",
LOG_FileWrite(logfileid, "%s %14.6f %1d %14.6f %12.3f %2d %2d %4d",
UTI_TimeToLogForm(system_time->tv_sec),
rtc_fast,
coefs_valid,
coef_seconds_fast, coef_gain_rate * 1.0e6, n_samples, n_runs, measurement_period);
fflush(logfile);
}
}
@@ -892,10 +837,6 @@ read_from_device(void *any)
switch_interrupts(0); /* Likely to raise error too, but just to be sure... */
close(fd);
fd = -1;
if (logfile) {
fclose(logfile);
logfile = NULL;
}
return;
}
@@ -911,7 +852,7 @@ read_from_device(void *any)
/* Read RTC time, sandwiched between two polls of the system clock
so we can bound any error. */
SCH_GetFileReadyTime(&sys_time);
SCH_GetFileReadyTime(&sys_time, NULL);
status = ioctl(fd, RTC_RD_TIME, &rtc_raw);
if (status < 0) {
@@ -990,7 +931,7 @@ turn_off_interrupt:
break;
default:
CROAK("Impossible");
assert(0);
break;
}
@@ -1139,7 +1080,6 @@ int
RTC_Linux_Trim(void)
{
struct timeval now;
double local_clock_err;
/* Remember the slope coefficient - we won't be able to determine a
@@ -1158,7 +1098,7 @@ RTC_Linux_Trim(void)
want |E| <= 0.5, which implies R <= S <= R+1, i.e. R is just
the rounded down part of S, i.e. the seconds part. */
LCL_ReadCookedTime(&now, &local_clock_err);
LCL_ReadCookedTime(&now, NULL);
set_rtc(now.tv_sec);
@@ -1181,16 +1121,4 @@ RTC_Linux_Trim(void)
/* ================================================== */
void
RTC_Linux_CycleLogFile(void)
{
if (logfile) {
fclose(logfile);
logfile = NULL;
logwrites = 0;
}
}
/* ================================================== */
#endif /* defined LINUX */

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/rtc_linux.h,v 1.13 2002/02/28 23:27:13 richard Exp $
======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

128
sched.c
View File

@@ -1,12 +1,9 @@
/*
$Header: /cvs/src/chrony/sched.c,v 1.17 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011
*
* 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
@@ -73,6 +70,7 @@ 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;
/* ================================================== */
@@ -109,6 +107,9 @@ static SCH_TimeoutID next_tqe_id;
/* Pointer to head of free list */
static TimerQueueEntry *tqe_free_list = NULL;
/* Timestamp when was last timeout dispatched for each class */
static struct timeval last_class_dispatch[SCH_NumberOfClasses];
/* ================================================== */
static int need_to_exit;
@@ -119,7 +120,6 @@ static void
handle_slew(struct timeval *raw,
struct timeval *cooked,
double dfreq,
double afreq,
double doffset,
int is_step_change,
void *anything);
@@ -129,6 +129,7 @@ handle_slew(struct timeval *raw,
void
SCH_Initialise(void)
{
struct timeval tv;
FD_ZERO(&read_fds);
n_read_fds = 0;
@@ -143,6 +144,9 @@ SCH_Initialise(void)
LCL_AddParameterChangeHandler(handle_slew, NULL);
LCL_ReadRawTime(&tv);
srandom(tv.tv_sec * tv.tv_usec);
initialised = 1;
return;
@@ -164,16 +168,12 @@ SCH_AddInputFileHandler
(int fd, SCH_FileHandler handler, SCH_ArbitraryArgument arg)
{
if (!initialised) {
CROAK("Should be initialised");
}
assert(initialised);
/* Don't want to allow the same fd to register a handler more than
once without deleting a previous association - this suggests
a bug somewhere else in the program. */
if (FD_ISSET(fd, &read_fds)) {
CROAK("File handler already registered");
}
assert(!FD_ISSET(fd, &read_fds));
++n_read_fds;
@@ -197,14 +197,10 @@ SCH_RemoveInputFileHandler(int fd)
{
int fds_left, fd_to_check;
if (!initialised) {
CROAK("Should be initialised");
}
assert(initialised);
/* Check that a handler was registered for the fd in question */
if (!FD_ISSET(fd, &read_fds)) {
CROAK("File handler not registered");
}
assert(FD_ISSET(fd, &read_fds));
--n_read_fds;
@@ -229,9 +225,11 @@ SCH_RemoveInputFileHandler(int fd)
/* ================================================== */
void
SCH_GetFileReadyTime(struct timeval *tv)
SCH_GetFileReadyTime(struct timeval *tv, double *err)
{
*tv = last_fdready;
if (err)
*err = last_fdready_err;
}
/* ================================================== */
@@ -276,9 +274,7 @@ SCH_AddTimeout(struct timeval *tv, SCH_TimeoutHandler handler, SCH_ArbitraryArgu
TimerQueueEntry *new_tqe;
TimerQueueEntry *ptr;
if (!initialised) {
CROAK("Should be initialised");
}
assert(initialised);
new_tqe = allocate_tqe();
@@ -319,9 +315,7 @@ SCH_AddTimeoutByDelay(double delay, SCH_TimeoutHandler handler, SCH_ArbitraryArg
{
struct timeval now, then;
if (!initialised) {
CROAK("Should be initialised");
}
assert(initialised);
LCL_ReadRawTime(&now);
UTI_AddDoubleToTimeval(&now, delay, &then);
@@ -332,23 +326,34 @@ SCH_AddTimeoutByDelay(double delay, SCH_TimeoutHandler handler, SCH_ArbitraryArg
/* ================================================== */
SCH_TimeoutID
SCH_AddTimeoutInClass(double min_delay, double separation,
SCH_AddTimeoutInClass(double min_delay, double separation, double randomness,
SCH_TimeoutClass class,
SCH_TimeoutHandler handler, SCH_ArbitraryArgument arg)
{
TimerQueueEntry *new_tqe;
TimerQueueEntry *ptr;
struct timeval now;
double diff;
double diff, r;
double new_min_delay;
if (!initialised) {
CROAK("Should be initialised");
assert(initialised);
assert(class < SCH_NumberOfClasses);
if (randomness > 0.0) {
r = random() % 0xffff / (0xffff - 1.0) * randomness + 1.0;
min_delay *= r;
separation *= r;
}
LCL_ReadRawTime(&now);
new_min_delay = min_delay;
/* Check the separation from the last dispatched timeout */
UTI_DiffTimevalsToDouble(&diff, &now, &last_class_dispatch[class]);
if (diff < separation && diff >= 0.0 && diff + new_min_delay < separation) {
new_min_delay = separation - diff;
}
/* Scan through list for entries in the same class and increase min_delay
if necessary to keep at least the separation away */
for (ptr = timer_queue.next; ptr != &timer_queue; ptr = ptr->next) {
@@ -358,8 +363,7 @@ SCH_AddTimeoutInClass(double min_delay, double separation,
if (new_min_delay - diff < separation) {
new_min_delay = diff + separation;
}
}
if (new_min_delay < diff) {
} else {
if (diff - new_min_delay < separation) {
new_min_delay = diff + separation;
}
@@ -398,13 +402,8 @@ void
SCH_RemoveTimeout(SCH_TimeoutID id)
{
TimerQueueEntry *ptr;
int ok;
if (!initialised) {
CROAK("Should be initialised");
}
ok = 0;
assert(initialised);
for (ptr = timer_queue.next; ptr != &timer_queue; ptr = ptr->next) {
@@ -421,14 +420,9 @@ SCH_RemoveTimeout(SCH_TimeoutID id)
/* Release memory back to the operating system */
release_tqe(ptr);
ok = 1;
break;
}
}
assert(ok);
}
/* ================================================== */
@@ -438,27 +432,26 @@ SCH_RemoveTimeout(SCH_TimeoutID id)
static int
dispatch_timeouts(struct timeval *now) {
TimerQueueEntry *ptr;
SCH_TimeoutHandler handler;
SCH_ArbitraryArgument arg;
int n_done = 0;
if ((n_timer_queue_entries > 0) &&
(UTI_CompareTimevals(now, &(timer_queue.next->tv)) >= 0)) {
ptr = timer_queue.next;
last_class_dispatch[ptr->class] = *now;
handler = ptr->handler;
arg = ptr->arg;
SCH_RemoveTimeout(ptr->id);
/* Dispatch the handler */
(ptr->handler)(ptr->arg);
(handler)(arg);
/* Increment count of timeouts handled */
++n_done;
/* Unlink entry from the queue */
ptr->prev->next = ptr->next;
ptr->next->prev = ptr->prev;
/* Decrement count of entries in queue */
--n_timer_queue_entries;
/* Delete entry */
release_tqe(ptr);
}
return n_done;
@@ -495,13 +488,12 @@ static void
handle_slew(struct timeval *raw,
struct timeval *cooked,
double dfreq,
double afreq,
double doffset,
int is_step_change,
void *anything)
{
TimerQueueEntry *ptr;
struct timeval T1;
int i;
if (is_step_change) {
/* We're not interested in anything else - it won't affect the
@@ -509,10 +501,12 @@ handle_slew(struct timeval *raw,
occurs, just shift all the timeouts by the offset */
for (ptr = timer_queue.next; ptr != &timer_queue; ptr = ptr->next) {
UTI_AddDoubleToTimeval(&ptr->tv, -doffset, &T1);
ptr->tv = T1;
UTI_AddDoubleToTimeval(&ptr->tv, -doffset, &ptr->tv);
}
for (i = 0; i < SCH_NumberOfClasses; i++) {
UTI_AddDoubleToTimeval(&last_class_dispatch[i], -doffset, &last_class_dispatch[i]);
}
}
}
@@ -525,11 +519,8 @@ SCH_MainLoop(void)
int status;
struct timeval tv, *ptv;
struct timeval now;
double err;
if (!initialised) {
CROAK("Should be initialised");
}
assert(initialised);
while (!need_to_exit) {
@@ -565,24 +556,19 @@ SCH_MainLoop(void)
status = select(one_highest_fd, &rd, NULL, NULL, ptv);
if (status < 0) {
if (!need_to_exit)
CROAK("Status < 0 after select");
assert(need_to_exit);
} else if (status > 0) {
/* A file descriptor is ready to read */
LCL_ReadCookedTime(&last_fdready, &err);
LCL_ReadCookedTime(&last_fdready, &last_fdready_err);
dispatch_filehandlers(status, &rd);
} else {
if (status != 0) {
CROAK("Unexpected value from select");
}
assert(status == 0);
/* No descriptors readable, timeout must have elapsed.
Therefore, tv must be non-null */
if (!ptv) {
CROAK("No descriptors or timeout?");
}
assert(ptv);
/* There's nothing to do here, since the timeouts
will be dispatched at the top of the next loop
@@ -600,9 +586,7 @@ SCH_MainLoop(void)
void
SCH_QuitProgram(void)
{
if (!initialised) {
CROAK("Should be initialised");
}
assert(initialised);
need_to_exit = 1;
}

21
sched.h
View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/sched.h,v 1.10 2002/02/28 23:27:14 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -35,10 +31,12 @@
typedef unsigned long SCH_TimeoutID;
typedef unsigned long SCH_TimeoutClass;
static const SCH_TimeoutClass SCH_ReservedTimeoutValue = 0;
static const SCH_TimeoutClass SCH_NtpSamplingClass = 1;
static const SCH_TimeoutClass SCH_NtpBroadcastClass = 2;
typedef enum {
SCH_ReservedTimeoutValue = 0,
SCH_NtpSamplingClass,
SCH_NtpBroadcastClass,
SCH_NumberOfClasses /* needs to be last */
} SCH_TimeoutClass;
typedef void* SCH_ArbitraryArgument;
typedef void (*SCH_FileHandler)(SCH_ArbitraryArgument);
@@ -62,7 +60,7 @@ extern void SCH_RemoveInputFileHandler(int fd);
/* Get the time (cooked) when file descriptor became ready, intended for use
in file handlers */
extern void SCH_GetFileReadyTime(struct timeval *tv);
extern void SCH_GetFileReadyTime(struct timeval *tv, double *err);
/* This queues a timeout to elapse at a given (raw) local time */
extern SCH_TimeoutID SCH_AddTimeout(struct timeval *tv, SCH_TimeoutHandler, SCH_ArbitraryArgument);
@@ -72,8 +70,9 @@ extern SCH_TimeoutID SCH_AddTimeoutByDelay(double delay, SCH_TimeoutHandler, SCH
/* This queues a timeout in a particular class, ensuring that the
expiry time is at least a given separation away from any other
timeout in the same class */
extern SCH_TimeoutID SCH_AddTimeoutInClass(double min_delay, double separation,
timeout in the same class, given randomness is added to the delay
and separation */
extern SCH_TimeoutID SCH_AddTimeoutInClass(double min_delay, double separation, double randomness,
SCH_TimeoutClass class,
SCH_TimeoutHandler handler, SCH_ArbitraryArgument);

432
sources.c
View File

@@ -1,12 +1,9 @@
/*
$Header: /cvs/src/chrony/sources.c,v 1.33 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011
*
* 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
@@ -90,9 +87,11 @@ struct SRC_Instance_Record {
reference _it_ is sync'd to) */
IPAddr *ip_addr; /* Its IP address if NTP source */
/* Flag indicating that we are receiving packets with valid headers
from this source and can use it as a reference */
int reachable;
/* Flag indicating that we can use this source as a reference */
int selectable;
/* Reachability register */
int reachability;
/* Flag indicating the status of the source */
SRC_Status status;
@@ -100,6 +99,12 @@ struct SRC_Instance_Record {
/* Type of the source */
SRC_Type type;
/* Options used when selecting sources */
SRC_SelectOption sel_option;
/* Score against currently selected source */
double sel_score;
struct SelectInfo sel_info;
};
@@ -124,12 +129,23 @@ static int selected_source_index; /* Which source index is currently
selected (set to INVALID_SOURCE
if no current valid reference) */
/* Keep reachability status for last 8 samples */
#define REACH_BITS 8
/* Score needed to replace the currently selected source */
#define SCORE_LIMIT 10.0
static double reselect_distance;
static double stratum_weight;
/* ================================================== */
/* Forward prototype */
static void
slew_sources(struct timeval *raw, struct timeval *cooked, double dfreq, double afreq,
slew_sources(struct timeval *raw, struct timeval *cooked, double dfreq,
double doffset, int is_step_change, void *anything);
static void
add_dispersion(double dispersion, void *anything);
static char *
source_to_string(SRC_Instance inst);
@@ -141,9 +157,12 @@ void SRC_Initialise(void) {
n_sources = 0;
max_n_sources = 0;
selected_source_index = INVALID_SOURCE;
reselect_distance = CNF_GetReselectDistance();
stratum_weight = CNF_GetStratumWeight();
initialised = 1;
LCL_AddParameterChangeHandler(slew_sources, NULL);
LCL_AddDispersionNotifyHandler(add_dispersion, NULL);
return;
}
@@ -153,6 +172,7 @@ void SRC_Initialise(void) {
void SRC_Finalise(void)
{
LCL_RemoveParameterChangeHandler(slew_sources, NULL);
LCL_RemoveDispersionNotifyHandler(add_dispersion, NULL);
initialised = 0;
return;
}
@@ -161,13 +181,11 @@ 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, IPAddr *addr)
SRC_Instance SRC_CreateNewInstance(unsigned long ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr)
{
SRC_Instance result;
if (!initialised) {
CROAK("Should be initialised");
}
assert(initialised);
result = MallocNew(struct SRC_Instance_Record);
result->stats = SST_CreateInstance(ref_id, addr);
@@ -191,9 +209,12 @@ SRC_Instance SRC_CreateNewInstance(unsigned long ref_id, SRC_Type type, IPAddr *
result->leap_status = LEAP_Normal;
result->ref_id = ref_id;
result->ip_addr = addr;
result->reachable = 0;
result->selectable = 0;
result->reachability = 0;
result->status = SRC_BAD_STATS;
result->type = type;
result->sel_score = 1.0;
result->sel_option = sel_option;
n_sources++;
@@ -210,14 +231,9 @@ void SRC_DestroyInstance(SRC_Instance instance)
{
int dead_index, i;
if (!initialised) {
CROAK("Should be initialised");
}
assert(initialised);
if (instance->index == selected_source_index) {
instance->reachable = 0;
SRC_SelectSource(0);
}
SRC_UnsetSelectable(instance);
SST_DeleteInstance(instance->stats);
dead_index = instance->index;
@@ -247,9 +263,7 @@ void SRC_DestroyInstance(SRC_Instance instance)
void SRC_GetFrequencyRange(SRC_Instance instance, double *lo, double *hi)
{
if (!initialised) {
CROAK("Should be initialised");
}
assert(initialised);
SST_GetFrequencyRange(instance->stats, lo, hi);
return;
@@ -280,9 +294,7 @@ void SRC_AccumulateSample
NTP_Leap leap_status)
{
if (!initialised) {
CROAK("Should be initialised");
}
assert(initialised);
inst->leap_status = leap_status;
@@ -304,9 +316,9 @@ void SRC_AccumulateSample
/* ================================================== */
void
SRC_SetReachable(SRC_Instance inst)
SRC_SetSelectable(SRC_Instance inst)
{
inst->reachable = 1;
inst->selectable = 1;
#ifdef TRACEON
LOG(LOGS_INFO, LOGF_Sources, "%s", source_to_string(inst));
@@ -319,9 +331,9 @@ SRC_SetReachable(SRC_Instance inst)
/* ================================================== */
void
SRC_UnsetReachable(SRC_Instance inst)
SRC_UnsetSelectable(SRC_Instance inst)
{
inst->reachable = 0;
inst->selectable = 0;
#ifdef TRACEON
LOG(LOGS_INFO, LOGF_Sources, "%s%s", source_to_string(inst),
@@ -338,6 +350,30 @@ SRC_UnsetReachable(SRC_Instance inst)
/* ================================================== */
void
SRC_UpdateReachability(SRC_Instance inst, int reachable)
{
inst->reachability <<= 1;
inst->reachability |= !!reachable;
inst->reachability &= ~(-1 << REACH_BITS);
if (!reachable && inst->index == selected_source_index) {
/* Try to select a better source */
SRC_SelectSource(0);
}
}
/* ================================================== */
void
SRC_ResetReachability(SRC_Instance inst)
{
inst->reachability = 0;
SRC_UpdateReachability(inst, 0);
}
/* ================================================== */
static int
compare_sort_elements(const void *a, const void *b)
{
@@ -368,7 +404,7 @@ source_to_string(SRC_Instance inst)
case SRC_REFCLOCK:
return UTI_RefidToString(inst->ref_id);
default:
CROAK("Unknown source type");
assert(0);
}
return NULL;
}
@@ -377,51 +413,53 @@ source_to_string(SRC_Instance inst)
/* This function selects the current reference from amongst the pool
of sources we are holding.
Updates are only made to the local reference if match_addr is zero or is
equal to the selected reference source address */
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 */
void
SRC_SelectSource(unsigned long match_addr)
{
int i, j, index;
int i, j, index, old_selected_index;
struct timeval now;
double local_clock_err;
int src_select_ok;
double src_offset, src_offset_sd, src_frequency, src_skew;
double src_accrued_dispersion;
int n_endpoints, j1, j2;
double best_lo, best_hi;
int depth, best_depth;
int n_sel_sources;
double distance, min_distance;
double distance, sel_src_distance;
int stratum, min_stratum;
int min_distance_index;
struct SelectInfo *si;
double total_root_dispersion;
int n_reachable_sources;
int n_badstats_sources;
int max_sel_reach, max_badstat_reach;
int max_score_index;
double max_score;
NTP_Leap leap_status = LEAP_Normal;
old_selected_index = selected_source_index;
if (n_sources == 0) {
/* In this case, we clearly cannot synchronise to anything */
if (selected_source_index != INVALID_SOURCE) {
LOG(LOGS_INFO, LOGF_Sources, "Can't synchronise: no sources");
}
selected_source_index = INVALID_SOURCE;
REF_SetUnsynchronised();
}
return;
}
LCL_ReadCookedTime(&now, &local_clock_err);
LCL_ReadCookedTime(&now, NULL);
/* Step 1 - build intervals about each source */
n_endpoints = 0;
n_reachable_sources = 0;
n_sel_sources = 0;
n_badstats_sources = 0;
max_sel_reach = max_badstat_reach = 0;
for (i=0; i<n_sources; i++) {
if (sources[i]->reachable) {
++n_reachable_sources;
if (sources[i]->selectable && sources[i]->reachability &&
sources[i]->sel_option != SRC_SelectNoselect) {
si = &(sources[i]->sel_info);
SST_GetSelectionData(sources[i]->stats, &now,
@@ -432,10 +470,6 @@ SRC_SelectSource(unsigned long match_addr)
&(si->variance),
&(si->select_ok));
/* Eventually this might be a flag indicating whether the get
selection data call was successful. For now it always is. */
src_select_ok = 1;
si->root_distance = si->root_dispersion + 0.5 * fabs(si->root_delay);
si->lo_limit = si->best_offset - si->root_distance;
si->hi_limit = si->best_offset + si->root_distance;
@@ -447,7 +481,8 @@ SRC_SelectSource(unsigned long match_addr)
si->lo_limit, si->hi_limit);
#endif
if (src_select_ok) {
if (si->select_ok) {
++n_sel_sources;
sources[i]->status = SRC_OK; /* For now */
@@ -466,8 +501,16 @@ SRC_SelectSource(unsigned long match_addr)
n_endpoints += 2;
if (max_sel_reach < sources[i]->reachability) {
max_sel_reach = sources[i]->reachability;
}
} else {
++n_badstats_sources;
sources[i]->status = SRC_BAD_STATS;
if (max_badstat_reach < sources[i]->reachability) {
max_badstat_reach = sources[i]->reachability;
}
}
} else {
/* If the source is not reachable, there is no way we will pick
@@ -476,6 +519,23 @@ SRC_SelectSource(unsigned long match_addr)
}
}
#if 0
LOG(LOGS_INFO, LOGF_Sources, "badstat_sources=%d sel_sources=%d badstat_reach=%x sel_reach=%x",
n_badstats_sources, n_sel_sources, max_badstat_reach, max_sel_reach);
#endif
/* Wait for the next call if we have no source selected and there is
a source with bad stats (has less than 3 samples) with reachability
equal to shifted maximum reachability of sources with valid stats.
This delays selecting source on start with servers using the same
polling interval until they all have valid stats. */
if (n_badstats_sources && n_sel_sources &&
selected_source_index == INVALID_SOURCE &&
max_sel_reach >> 1 == max_badstat_reach) {
return;
}
#if 0
LOG(LOGS_INFO, LOGF_Sources, "n_endpoints=%d", n_endpoints);
#endif
@@ -527,7 +587,7 @@ SRC_SelectSource(unsigned long match_addr)
break;
case CENTRE:
CROAK("CENTRE cannot occur");
assert(0);
break;
case HIGH:
@@ -545,7 +605,7 @@ SRC_SelectSource(unsigned long match_addr)
best_depth, best_lo, best_hi);
#endif
if (best_depth <= n_reachable_sources/2) {
if (best_depth <= n_sel_sources/2) {
/* Could not even get half the reachable sources to agree -
clearly we can't synchronise.
@@ -561,7 +621,6 @@ SRC_SelectSource(unsigned long match_addr)
LOG(LOGS_INFO, LOGF_Sources, "Can't synchronise: no majority");
}
selected_source_index = INVALID_SOURCE;
REF_SetUnsynchronised();
/* .. and mark all sources as falsetickers (so they appear thus
on the outputs from the command client) */
@@ -600,6 +659,7 @@ SRC_SelectSource(unsigned long match_addr)
}
}
#if 0
/* We now have a list of indices for the sources which pass the
false-ticker test. Now go on to reject those whose variance is
greater than the minimum distance of any other */
@@ -619,11 +679,12 @@ SRC_SelectSource(unsigned long match_addr)
LOG(LOGS_INFO, LOGF_Sources, "min_distance=%f", min_distance);
#endif
/* Now go through and prune any sources that have excessive
/* Now go through and prune any NTP sources that have excessive
variance */
for (i=0; i<n_sel_sources; i++) {
index = sel_sources[i];
if (sources[index]->sel_info.variance > min_distance) {
if (sources[index]->type == SRC_NTP &&
sqrt(sources[index]->sel_info.variance) > min_distance) {
sel_sources[i] = INVALID_SOURCE;
sources[index]->status = SRC_JITTERY;
#if 0
@@ -631,6 +692,7 @@ SRC_SelectSource(unsigned long match_addr)
#endif
}
}
#endif
/* Now crunch the list and mark all sources as selectable */
for (i=j=0; i<n_sel_sources; i++) {
@@ -643,77 +705,7 @@ SRC_SelectSource(unsigned long match_addr)
}
n_sel_sources = j;
/* Now find minimum stratum. If none are left now,
tough. RFC1305 is not so harsh on pruning sources due to
excess variance, which prevents this from happening */
if (n_sel_sources > 0) {
index = sel_sources[0];
min_stratum = sources[index]->sel_info.stratum;
for (i=1; i<n_sel_sources; i++) {
index = sel_sources[i];
stratum = sources[index]->sel_info.stratum;
if (stratum < min_stratum) min_stratum = stratum;
}
/* Find the best source with minimum stratum */
min_distance_index = INVALID_SOURCE;
for (i=0; i<n_sel_sources; i++) {
index = sel_sources[i];
if (sources[index]->sel_info.stratum == min_stratum) {
if ((min_distance_index == INVALID_SOURCE) ||
(sources[index]->sel_info.root_distance < min_distance)) {
min_distance = sources[index]->sel_info.root_distance;
min_distance_index = index;
}
}
}
#if 0
LOG(LOGS_INFO, LOGF_Sources, "min_stratum=%d", min_stratum);
#endif
/* Does the current source have this stratum, doesn't have distance
much worse than the best source and is it still a survivor? */
if ((selected_source_index == INVALID_SOURCE) ||
(sources[selected_source_index]->status != SRC_SELECTABLE) ||
(sources[selected_source_index]->sel_info.stratum > min_stratum) ||
(sources[selected_source_index]->sel_info.root_distance > 10 * min_distance)) {
/* We have to elect a new synchronisation source */
selected_source_index = min_distance_index;
LOG(LOGS_INFO, LOGF_Sources, "Selected source %s",
source_to_string(sources[selected_source_index]));
#if 0
LOG(LOGS_INFO, LOGF_Sources, "new_sel_index=%d", min_distance_index);
#endif
} else {
/* We retain the existing sync source, see p40 of RFC1305b.ps */
#if 0
LOG(LOGS_INFO, LOGF_Sources, "existing reference retained", min_distance_index);
#endif
}
sources[selected_source_index]->status = SRC_SYNC;
/* Now just use the statistics of the selected source for
trimming the local clock */
LCL_ReadCookedTime(&now, &local_clock_err);
SST_GetTrackingData(sources[selected_source_index]->stats, &now,
&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);
/* Accept leap second status if more than half of selectable sources agree */
for (i=j1=j2=0; i<n_sel_sources; i++) {
@@ -731,8 +723,134 @@ SRC_SelectSource(unsigned long match_addr)
leap_status = LEAP_DeleteSecond;
}
if ((match_addr == 0) ||
(match_addr == sources[selected_source_index]->ref_id)) {
/* If there are any sources with prefer option, reduce the list again
only to the prefer sources */
for (i=j=0; i<n_sel_sources; i++) {
if (sources[sel_sources[i]]->sel_option == SRC_SelectPrefer) {
sel_sources[j++] = sel_sources[i];
}
}
if (j > 0) {
n_sel_sources = j;
}
/* Now find minimum stratum. If none are left now,
tough. RFC1305 is not so harsh on pruning sources due to
excess variance, which prevents this from happening */
index = sel_sources[0];
min_stratum = sources[index]->sel_info.stratum;
for (i=1; i<n_sel_sources; i++) {
index = sel_sources[i];
stratum = sources[index]->sel_info.stratum;
if (stratum < min_stratum) min_stratum = stratum;
}
#if 0
LOG(LOGS_INFO, LOGF_Sources, "min_stratum=%d", min_stratum);
#endif
/* Update scores and find source with maximum score */
max_score_index = INVALID_SOURCE;
max_score = 0.0;
sel_src_distance = 0.0;
if (selected_source_index != INVALID_SOURCE) {
sel_src_distance = sources[selected_source_index]->sel_info.root_distance +
(sources[selected_source_index]->sel_info.stratum - min_stratum) * stratum_weight;
}
for (i = 0; i < n_sources; i++) {
/* Reset score for non-selectable sources */
if (sources[i]->status != SRC_SELECTABLE) {
sources[i]->sel_score = 1.0;
continue;
}
distance = sources[i]->sel_info.root_distance +
(sources[i]->sel_info.stratum - min_stratum) * stratum_weight;
if (sources[i]->type == SRC_NTP)
distance += reselect_distance;
if (selected_source_index != INVALID_SOURCE) {
/* 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) {
sources[i]->sel_score *= sel_src_distance / distance;
if (sources[i]->sel_score < 1.0)
sources[i]->sel_score = 1.0;
}
} else {
/* When there is no selected source yet, assign scores so the
source with minimum distance will have maximum score. The scores
will be immediately reset. */
sources[i]->sel_score = 1.0 / distance;
}
#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);
#endif
if (max_score < sources[i]->sel_score) {
max_score = sources[i]->sel_score;
max_score_index = i;
}
}
assert(max_score_index != INVALID_SOURCE);
/* Is the current source still a survivor
and no other source has reached the score limit? */
if ((selected_source_index == INVALID_SOURCE) ||
(sources[selected_source_index]->status != SRC_SELECTABLE) ||
(max_score_index != selected_source_index && max_score > SCORE_LIMIT)) {
/* We have to elect a new synchronisation source */
selected_source_index = max_score_index;
LOG(LOGS_INFO, LOGF_Sources, "Selected source %s",
source_to_string(sources[selected_source_index]));
#if 0
LOG(LOGS_INFO, LOGF_Sources, "new_sel_index=%d", selected_source_index);
#endif
/* New source has been selected, reset all scores */
for (i=0; i < n_sources; i++) {
sources[i]->sel_score = 1.0;
}
}
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) */
if (selected_source_index != old_selected_index ||
match_addr == 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,
&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);
REF_SetReference(min_stratum, leap_status,
sources[selected_source_index]->ref_id,
@@ -750,11 +868,7 @@ SRC_SelectSource(unsigned long match_addr)
LOG(LOGS_INFO, LOGF_Sources, "Can't synchronise: no selectable sources");
}
selected_source_index = INVALID_SOURCE;
REF_SetUnsynchronised();
}
}
} else {
@@ -763,9 +877,22 @@ SRC_SelectSource(unsigned long match_addr)
LOG(LOGS_INFO, LOGF_Sources, "Can't synchronise: no reachable sources");
}
selected_source_index = INVALID_SOURCE;
REF_SetUnsynchronised();
}
if (selected_source_index == INVALID_SOURCE &&
selected_source_index != old_selected_index) {
REF_SetUnsynchronised();
}
}
/* ================================================== */
/* Force reselecting the best source */
void
SRC_ReselectSource(void)
{
selected_source_index = INVALID_SOURCE;
SRC_SelectSource(0);
}
/* ================================================== */
@@ -784,6 +911,16 @@ SRC_MinRoundTripDelay(SRC_Instance inst)
return SST_MinRoundTripDelay(inst->stats);
}
/* ================================================== */
int
SRC_IsGoodSample(SRC_Instance inst, double offset, double delay,
double max_delay_dev_ratio, double clock_error, struct timeval *when)
{
return SST_IsGoodSample(inst->stats, offset, delay, max_delay_dev_ratio,
clock_error, when);
}
/* ================================================== */
/* This routine is registered as a callback with the local clock
module, to be called whenever the local clock changes frequency or
@@ -795,7 +932,6 @@ static void
slew_sources(struct timeval *raw,
struct timeval *cooked,
double dfreq,
double afreq,
double doffset,
int is_step_change,
void *anything)
@@ -808,6 +944,20 @@ slew_sources(struct timeval *raw,
}
/* ================================================== */
/* This routine is called when an indeterminate offset is introduced
into the local time. */
static void
add_dispersion(double dispersion, void *anything)
{
int i;
for (i = 0; i < n_sources; i++) {
SST_AddDispersion(sources[i]->stats, dispersion);
}
}
/* ================================================== */
/* This is called to dump out the source measurement registers */
@@ -875,8 +1025,6 @@ SRC_ReloadSources(void)
LOG(LOGS_WARN, LOGF_Sources, "Could not open dump file %s", filename);
} else {
if (SST_LoadFromFile(sources[i]->stats, in)) {
/* We might want to use SST_DoUpdateRegression here, but we
need to check it has the same functionality */
SST_DoNewRegression(sources[i]->stats);
} else {
LOG(LOGS_WARN, LOGF_Sources, "Problem loading from file %s", filename);
@@ -935,14 +1083,18 @@ SRC_ReportSource(int index, RPT_SourceReport *report, struct timeval *now)
case SRC_JITTERY:
report->state = RPT_JITTERY;
break;
case SRC_BAD_STATS:
case SRC_UNREACHABLE:
report->state = RPT_UNREACH;
break;
case SRC_FALSETICKER:
report->state = RPT_FALSETICKER;
break;
case SRC_SELECTABLE:
report->state = RPT_CANDIDATE;
break;
default:
report->state = RPT_OTHER;
assert(0);
break;
}
/* Call stats module to fill out estimates */
@@ -1006,3 +1158,11 @@ SRC_Skew_Direction SRC_LastSkewChange(SRC_Instance inst)
}
/* ================================================== */
int
SRC_Samples(SRC_Instance inst)
{
return SST_Samples(inst->stats);
}
/* ================================================== */

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/sources.h,v 1.15 2002/02/28 23:27:14 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -55,10 +51,17 @@ typedef enum {
SRC_REFCLOCK /* Rerefence clock */
} SRC_Type;
/* Options used when selecting sources */
typedef enum {
SRC_SelectNormal,
SRC_SelectNoselect,
SRC_SelectPrefer
} SRC_SelectOption;
/* 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, IPAddr *addr);
extern SRC_Instance SRC_CreateNewInstance(unsigned long 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
@@ -113,22 +116,30 @@ extern void SRC_AccumulateSample(SRC_Instance instance, struct timeval *sample_t
/* This routine indicates that packets with valid headers are being
received from the designated source */
extern void SRC_SetReachable(SRC_Instance instance);
extern void SRC_SetSelectable(SRC_Instance instance);
/* This routine indicates that we are no longer receiving packets with
valid headers from the designated source */
extern void SRC_UnsetReachable(SRC_Instance instance);
extern void SRC_UnsetSelectable(SRC_Instance instance);
/* This routine updates the reachability register */
extern void SRC_UpdateReachability(SRC_Instance inst, int reachable);
/* This routine marks the source unreachable */
extern void SRC_ResetReachability(SRC_Instance inst);
/* This routine is used to select the best source from amongst those
we currently have valid data on, and use it as the tracking base
for the local time. If match_addr is zero it means we must start
tracking the (newly) selected reference unconditionally, otherwise
it is equal to the address we should track if it turns out to be
the best reference. (This avoids updating the frequency tracking
for every sample from other sources - only the ones from the
selected reference make a difference) */
for the local time. 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. (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);
/* Force reselecting the best source */
extern void SRC_ReselectSource(void);
/* 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. */
@@ -138,6 +149,10 @@ extern double SRC_PredictOffset(SRC_Instance inst, struct timeval *when);
currently held in the register */
extern double SRC_MinRoundTripDelay(SRC_Instance inst);
/* This routine determines if a new sample is good enough that it should be
accumulated */
extern int SRC_IsGoodSample(SRC_Instance inst, double offset, double delay, double max_delay_dev_ratio, double clock_error, struct timeval *when);
extern void SRC_DumpSources(void);
extern void SRC_ReloadSources(void);
@@ -158,5 +173,7 @@ typedef enum {
extern SRC_Skew_Direction SRC_LastSkewChange(SRC_Instance inst);
extern int SRC_Samples(SRC_Instance inst);
#endif /* GOT_SOURCES_H */

View File

@@ -1,12 +1,9 @@
/*
$Header: /cvs/src/chrony/sourcestats.c,v 1.40 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011
*
* 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
@@ -38,7 +35,6 @@
#include "conf.h"
#include "logging.h"
#include "local.h"
#include "mkdirpp.h"
/* ================================================== */
/* Define the maxumum number of samples that we want
@@ -49,16 +45,9 @@
2000ppm, which would be pretty bad */
#define WORST_CASE_FREQ_BOUND (2000.0/1.0e6)
/* Day number of 1 Jan 1970 */
#define MJD_1970 40587
/* ================================================== */
/* File to which statistics are logged, NULL if none */
static FILE *logfile = NULL;
static char *logfilename = NULL;
static unsigned long logwrites = 0;
#define STATISTICS_LOG "statistics.log"
static LOG_FileID logfileid;
/* ================================================== */
/* This data structure is used to hold the history of data from the
@@ -70,16 +59,27 @@ struct SST_Stats_Record {
unsigned long refid;
IPAddr *ip_addr;
/* Number of samples currently stored. sample[n_samples-1] is the
newest. The samples are expected to be sorted in order, but that
probably doesn't matter. */
/* Number of samples currently stored. The samples are stored in circular
buffer. */
int n_samples;
/* The index in the registers of the best individual sample that we
are holding, in terms of the minimum root distance at the present
time */
/* Number of extra samples stored in sample_times and offsets arrays that are
used to extend runs test */
int runs_samples;
/* The index of the newest sample */
int last_sample;
/* Flag indicating whether last regression was successful */
int regression_ok;
/* The best individual sample that we are holding, in terms of the minimum
root distance at the present time */
int best_single_sample;
/* The index of the sample with minimum delay in peer_delays */
int min_delay_sample;
/* This is the estimated offset (+ve => local fast) at a particular time */
double estimated_offset;
double estimated_offset_sd;
@@ -107,7 +107,7 @@ struct SST_Stats_Record {
/* This array contains the sample epochs, in terms of the local
clock. */
struct timeval sample_times[MAX_SAMPLES];
struct timeval sample_times[MAX_SAMPLES * REGRESS_RUNS_RATIO];
/* This is an array of offsets, in seconds, corresponding to the
sample times. In this module, we use the convention that
@@ -115,7 +115,7 @@ struct SST_Stats_Record {
means it is SLOW. This is contrary to the convention in the NTP
stuff; that part of the code is written to correspond with
RFC1305 conventions. */
double offsets[MAX_SAMPLES];
double offsets[MAX_SAMPLES * REGRESS_RUNS_RATIO];
/* This is an array of the offsets as originally measured. Local
clock fast of real time is indicated by positive values. This
@@ -139,10 +139,6 @@ struct SST_Stats_Record {
time of the measurements */
double root_dispersions[MAX_SAMPLES];
/* This array contains the weights to be used in the regression
analysis for each of the samples. */
double weights[MAX_SAMPLES];
/* This array contains the strata that were associated with the sources
at the times the samples were generated */
int strata[MAX_SAMPLES];
@@ -151,27 +147,17 @@ struct SST_Stats_Record {
/* ================================================== */
static void find_min_delay_sample(SST_Stats inst);
static int get_buf_index(SST_Stats inst, int i);
/* ================================================== */
void
SST_Initialise(void)
{
char *direc;
if (CNF_GetLogStatistics()) {
direc = CNF_GetLogDir();
if (!mkdir_and_parents(direc)) {
LOG(LOGS_ERR, LOGF_SourceStats, "Could not create directory %s", direc);
logfile = NULL;
} else {
logfilename = MallocArray(char, 2 + strlen(direc) + strlen(STATISTICS_LOG));
strcpy(logfilename, direc);
strcat(logfilename, "/");
strcat(logfilename, STATISTICS_LOG);
logfile = fopen(logfilename, "a");
if (!logfile) {
LOG(LOGS_WARN, LOGF_SourceStats, "Couldn't open logfile %s for update", logfilename);
}
}
}
logfileid = CNF_GetLogStatistics() ? LOG_FileOpen("statistics",
" Date (UTC) Time IP Address Std dev'n Est offset Offset sd Diff freq Est skew Stress Ns Bs Nr")
: -1;
}
/* ================================================== */
@@ -179,9 +165,6 @@ SST_Initialise(void)
void
SST_Finalise(void)
{
if (logfile) {
fclose(logfile);
}
}
/* ================================================== */
@@ -195,6 +178,11 @@ SST_CreateInstance(unsigned long refid, IPAddr *addr)
inst->refid = refid;
inst->ip_addr = addr;
inst->n_samples = 0;
inst->runs_samples = 0;
inst->last_sample = 0;
inst->regression_ok = 0;
inst->best_single_sample = 0;
inst->min_delay_sample = 0;
inst->estimated_frequency = 0;
inst->skew = 2000.0e-6;
inst->skew_dirn = SST_Skew_Nochange;
@@ -217,45 +205,25 @@ SST_DeleteInstance(SST_Stats inst)
return;
}
/* ================================================== */
static void
move_stats_entry(SST_Stats inst, int src, int dest)
{
inst->sample_times[dest] = inst->sample_times[src];
inst->offsets[dest] = inst->offsets[src];
inst->orig_offsets[dest] = inst->orig_offsets[src];
inst->peer_delays[dest] = inst->peer_delays[src];
inst->peer_dispersions[dest] = inst->peer_dispersions[src];
inst->root_delays[dest] = inst->root_delays[src];
inst->root_dispersions[dest] = inst->root_dispersions[src];
inst->weights[dest] = inst->weights[src];
inst->strata[dest] = inst->strata[src];
}
/* ================================================== */
/* This function is called to prune the register down when it is full.
For now, just discard the oldest sample. */
static void
prune_register(SST_Stats inst, int new_oldest, int *bad_points)
prune_register(SST_Stats inst, int new_oldest)
{
int i, j;
if (!new_oldest)
return;
if (!(new_oldest < inst->n_samples)) {
CROAK("new_oldest should be < n_samples");
}
assert(inst->n_samples >= new_oldest);
inst->n_samples -= new_oldest;
inst->runs_samples += new_oldest;
if (inst->runs_samples > inst->n_samples * (REGRESS_RUNS_RATIO - 1))
inst->runs_samples = inst->n_samples * (REGRESS_RUNS_RATIO - 1);
for (i=0, j=new_oldest; j<inst->n_samples; j++) {
if (!bad_points || !bad_points[j]) {
if (j != i) {
move_stats_entry(inst, j, i);
}
i++;
}
}
inst->n_samples = i;
assert(inst->n_samples + inst->runs_samples <= MAX_SAMPLES * REGRESS_RUNS_RATIO);
find_min_delay_sample(inst);
}
/* ================================================== */
@@ -267,37 +235,50 @@ SST_AccumulateSample(SST_Stats inst, struct timeval *sample_time,
double root_delay, double root_dispersion,
int stratum)
{
int n;
#if 0
double root_distance;
#endif
int n, m;
if (inst->n_samples == MAX_SAMPLES) {
prune_register(inst, 1, NULL);
prune_register(inst, 1);
}
n = inst->n_samples;
n = inst->last_sample = (inst->last_sample + 1) %
(MAX_SAMPLES * REGRESS_RUNS_RATIO);
m = n % MAX_SAMPLES;
inst->sample_times[n] = *sample_time;
inst->offsets[n] = offset;
inst->orig_offsets[n] = offset;
inst->peer_delays[n] = peer_delay;
inst->peer_dispersions[n] = peer_dispersion;
inst->root_delays[n] = root_delay;
inst->root_dispersions[n] = root_dispersion;
inst->orig_offsets[m] = offset;
inst->peer_delays[m] = fabs(peer_delay);
inst->peer_dispersions[m] = peer_dispersion;
inst->root_delays[m] = root_delay;
inst->root_dispersions[m] = root_dispersion;
inst->strata[m] = stratum;
#if 0
/* The weight is worked out when we run the regression algorithm */
root_distance = root_dispersion + 0.5 * fabs(root_delay);
/* For now, this is the formula for the weight functions */
inst->weights[n] = root_distance * root_distance;
#endif
inst->strata[n] = stratum;
if (!inst->n_samples || inst->peer_delays[m] < inst->peer_delays[inst->min_delay_sample])
inst->min_delay_sample = m;
++inst->n_samples;
}
/* ================================================== */
/* Return index of the i-th sample in the sample_times and offset buffers,
i can be negative down to -runs_samples */
static int
get_runsbuf_index(SST_Stats inst, int i)
{
return (unsigned int)(inst->last_sample + 2 * MAX_SAMPLES * REGRESS_RUNS_RATIO -
inst->n_samples + i + 1) % (MAX_SAMPLES * REGRESS_RUNS_RATIO);
}
/* ================================================== */
/* Return index of the i-th sample in the other buffers */
static int
get_buf_index(SST_Stats inst, int i)
{
return (unsigned int)(inst->last_sample + MAX_SAMPLES * REGRESS_RUNS_RATIO -
inst->n_samples + i + 1) % MAX_SAMPLES;
}
/* ================================================== */
@@ -311,10 +292,11 @@ convert_to_intervals(SST_Stats inst, double *times_back)
struct timeval *newest_tv;
int i;
newest_tv = &(inst->sample_times[inst->n_samples - 1]);
for (i=0; i<inst->n_samples; i++) {
newest_tv = &(inst->sample_times[inst->last_sample]);
for (i = -inst->runs_samples; i < inst->n_samples; i++) {
/* The entries in times_back[] should end up negative */
UTI_DiffTimevalsToDouble(&(times_back[i]), &(inst->sample_times[i]), newest_tv);
UTI_DiffTimevalsToDouble(&times_back[i],
&inst->sample_times[get_runsbuf_index(inst, i)], newest_tv);
}
}
@@ -328,41 +310,28 @@ find_best_sample_index(SST_Stats inst, double *times_back)
double root_distance, best_root_distance;
double elapsed;
int i, n, best_index;
int i, j, best_index;
if (!inst->n_samples)
return;
best_index = -1;
best_root_distance = DBL_MAX;
for (i = 0; i < inst->n_samples; i++) {
j = get_buf_index(inst, i);
n = inst->n_samples - 1;
best_root_distance = inst->root_dispersions[n] + 0.5 * fabs(inst->root_delays[n]);
best_index = n;
#if 0
LOG(LOGS_INFO, LOGF_SourceStats, "n=%d brd=%f", n, best_root_distance);
#endif
for (i=0; i<n; i++) {
elapsed = -times_back[i];
#if 0
LOG(LOGS_INFO, LOGF_SourceStats, "n=%d i=%d latest=[%s] doing=[%s] elapsed=%f", n, i,
UTI_TimevalToString(&(inst->sample_times[n])),
UTI_TimevalToString(&(inst->sample_times[i])),
elapsed);
#endif
assert(elapsed >= 0.0);
/* Because the loop does not consider the most recent sample, this assertion must hold */
if (elapsed <= 0.0) {
LOG(LOGS_ERR, LOGF_SourceStats, "Elapsed<0! n=%d i=%d latest=[%s] doing=[%s] elapsed=%f",
n, i,
UTI_TimevalToString(&(inst->sample_times[n])),
UTI_TimevalToString(&(inst->sample_times[i])),
elapsed);
elapsed = fabs(elapsed);
}
root_distance = inst->root_dispersions[i] + elapsed * inst->skew + 0.5 * fabs(inst->root_delays[i]);
root_distance = inst->root_dispersions[j] + elapsed * inst->skew + 0.5 * fabs(inst->root_delays[j]);
if (root_distance < best_root_distance) {
best_root_distance = root_distance;
best_index = i;
}
}
assert(best_index >= 0);
inst->best_single_sample = best_index;
#if 0
@@ -374,6 +343,22 @@ find_best_sample_index(SST_Stats inst, double *times_back)
/* ================================================== */
static void
find_min_delay_sample(SST_Stats inst)
{
int i, index;
inst->min_delay_sample = get_buf_index(inst, 0);
for (i = 1; i < inst->n_samples; i++) {
index = get_buf_index(inst, i);
if (inst->peer_delays[index] < inst->peer_delays[inst->min_delay_sample])
inst->min_delay_sample = index;
}
}
/* ================================================== */
/* This defines the assumed ratio between the standard deviation of
the samples and the peer distance as measured from the round trip
time. E.g. a value of 4 means that we think the standard deviation
@@ -390,29 +375,29 @@ find_best_sample_index(SST_Stats inst, double *times_back)
void
SST_DoNewRegression(SST_Stats inst)
{
double times_back[MAX_SAMPLES];
double times_back[MAX_SAMPLES * REGRESS_RUNS_RATIO];
double offsets[MAX_SAMPLES * REGRESS_RUNS_RATIO];
double peer_distances[MAX_SAMPLES];
double weights[MAX_SAMPLES];
int bad_points[MAX_SAMPLES];
int degrees_of_freedom;
int best_start;
int best_start, times_back_start;
double est_intercept, est_slope, est_var, est_intercept_sd, est_slope_sd;
int i, nruns;
int i, j, nruns;
double min_distance;
double sd_weight;
double sd_weight, sd;
double old_skew, old_freq, stress;
int regression_ok;
convert_to_intervals(inst, times_back);
convert_to_intervals(inst, times_back + inst->runs_samples);
if (inst->n_samples > 0) {
for (i=0; i<inst->n_samples; i++) {
peer_distances[i] = 0.5 * fabs(inst->peer_delays[i]) + inst->peer_dispersions[i];
for (i = -inst->runs_samples; i < inst->n_samples; i++) {
offsets[i + inst->runs_samples] = inst->offsets[get_runsbuf_index(inst, i)];
}
min_distance = peer_distances[0];
for (i=1; i<inst->n_samples; i++) {
for (i = 0, min_distance = DBL_MAX; i < inst->n_samples; i++) {
j = get_buf_index(inst, i);
peer_distances[i] = 0.5 * inst->peer_delays[j] + inst->peer_dispersions[j];
if (peer_distances[i] < min_distance) {
min_distance = peer_distances[i];
}
@@ -420,23 +405,24 @@ SST_DoNewRegression(SST_Stats inst)
/* And now, work out the weight vector */
sd = sqrt(inst->variance);
if (sd > min_distance || sd <= 0.0)
sd = min_distance;
for (i=0; i<inst->n_samples; i++) {
sd_weight = 1.0 + SD_TO_DIST_RATIO * (peer_distances[i] - min_distance) / min_distance;
inst->weights[i] = sd_weight * sd_weight;
sd_weight = 1.0 + SD_TO_DIST_RATIO * (peer_distances[i] - min_distance) / sd;
weights[i] = sd_weight * sd_weight;
}
}
regression_ok = RGR_FindBestRegression(times_back, inst->offsets, inst->weights,
inst->n_samples,
inst->regression_ok = RGR_FindBestRegression(times_back + inst->runs_samples,
offsets + inst->runs_samples, weights,
inst->n_samples, inst->runs_samples,
&est_intercept, &est_slope, &est_var,
&est_intercept_sd, &est_slope_sd,
&best_start, &nruns, &degrees_of_freedom);
/* This is a legacy of when the regression routine found outliers
for us. We don't use it anymore. */
memset((void *) bad_points, 0, MAX_SAMPLES * sizeof(int));
if (regression_ok) {
if (inst->regression_ok) {
old_skew = inst->skew;
old_freq = inst->estimated_frequency;
@@ -444,7 +430,7 @@ SST_DoNewRegression(SST_Stats inst)
inst->estimated_frequency = est_slope;
inst->skew = est_slope_sd * RGR_GetTCoef(degrees_of_freedom);
inst->estimated_offset = est_intercept;
inst->offset_time = inst->sample_times[inst->n_samples - 1];
inst->offset_time = inst->sample_times[inst->last_sample];
inst->estimated_offset_sd = est_intercept_sd;
inst->variance = est_var;
inst->nruns = nruns;
@@ -463,17 +449,8 @@ SST_DoNewRegression(SST_Stats inst)
}
}
if (logfile) {
if (((logwrites++) % 32) == 0) {
fprintf(logfile,
"==============================================================================================================\n"
" Date (UTC) Time IP Address Std dev'n Est offset Offset sd Diff freq Est skew Stress Ns Bs Nr\n"
"==============================================================================================================\n");
}
fprintf(logfile, "%s %-15s %10.3e %10.3e %10.3e %10.3e %10.3e %7.1e %3d %3d %3d\n",
if (logfileid != -1) {
LOG_FileWrite(logfileid, "%s %-15s %10.3e %10.3e %10.3e %10.3e %10.3e %7.1e %3d %3d %3d",
UTI_TimeToLogForm(inst->offset_time.tv_sec),
inst->ip_addr ? UTI_IPToString(inst->ip_addr) : UTI_RefidToString(inst->refid),
sqrt(inst->variance),
@@ -484,58 +461,20 @@ SST_DoNewRegression(SST_Stats inst)
stress,
inst->n_samples,
best_start, nruns);
fflush(logfile);
}
prune_register(inst, best_start, bad_points);
times_back_start = inst->runs_samples + best_start;
prune_register(inst, best_start);
} else {
#if 0
LOG(LOGS_INFO, LOGF_SourceStats, "too few points (%d) for regression", inst->n_samples);
#endif
inst->estimated_frequency = 0.0;
inst->skew = WORST_CASE_FREQ_BOUND;
times_back_start = 0;
}
find_best_sample_index(inst, times_back);
}
/* ================================================== */
/* This function does a simple regression on what is in the register,
without trying to optimise the error bounds on the frequency by
deleting old samples */
void
SST_DoUpdateRegression(SST_Stats inst)
{
double times_back[MAX_SAMPLES];
double freq_error_bound;
double est_intercept, est_slope, est_var_base, est_intercept_sd, est_slope_sd;
convert_to_intervals(inst, times_back);
if (inst->n_samples >= 3) { /* Otherwise, we're wasting our time - we
can't do a useful linear regression
with less than 3 points */
RGR_WeightedRegression(times_back, inst->offsets, inst->weights,
inst->n_samples,
&est_intercept, &est_slope, &est_var_base,
&est_intercept_sd, &est_slope_sd);
freq_error_bound = est_slope_sd * RGR_GetTCoef(inst->n_samples - 2);
inst->estimated_frequency = est_slope;
inst->skew = freq_error_bound;
} else {
inst->estimated_frequency = 0.0;
inst->skew = WORST_CASE_FREQ_BOUND;
}
find_best_sample_index(inst, times_back);
find_best_sample_index(inst, times_back + times_back_start);
}
@@ -549,22 +488,23 @@ SST_GetReferenceData(SST_Stats inst, struct timeval *now,
{
double elapsed;
int n;
int i, j;
*frequency = inst->estimated_frequency;
*skew = inst->skew;
n = inst->best_single_sample;
i = get_runsbuf_index(inst, inst->best_single_sample);
j = get_buf_index(inst, inst->best_single_sample);
UTI_DiffTimevalsToDouble(&elapsed, now, &(inst->sample_times[n]));
*root_delay = inst->root_delays[n];
*root_dispersion = inst->root_dispersions[n] + elapsed * inst->skew;
*offset = inst->offsets[n] + elapsed * inst->estimated_frequency;
*stratum = inst->strata[n];
UTI_DiffTimevalsToDouble(&elapsed, now, &inst->sample_times[i]);
*root_delay = inst->root_delays[j];
*root_dispersion = inst->root_dispersions[j] + elapsed * inst->skew;
*offset = inst->offsets[i] + elapsed * inst->estimated_frequency;
*stratum = inst->strata[j];
#ifdef TRACEON
LOG(LOGS_INFO, LOGF_SourceStats, "n=%d freq=%f skew=%f del=%f disp=%f ofs=%f str=%d",
n, *frequency, *skew, *root_delay, *root_dispersion, *offset, *stratum);
inst->n_samples, *frequency, *skew, *root_delay, *root_dispersion, *offset, *stratum);
#endif
return;
@@ -595,37 +535,43 @@ SST_GetSelectionData(SST_Stats inst, struct timeval *now,
int *stratum,
double *best_offset, double *best_root_delay,
double *best_root_dispersion,
double *variance, int *average_ok)
double *variance, int *select_ok)
{
double average_offset;
double sample_elapsed;
double elapsed;
int n;
int i, j;
int average_ok;
double peer_distance;
n = inst->best_single_sample;
*stratum = inst->strata[n];
i = get_runsbuf_index(inst, inst->best_single_sample);
j = get_buf_index(inst, inst->best_single_sample);
*stratum = inst->strata[j];
*variance = inst->variance;
peer_distance = inst->peer_dispersions[n] + 0.5 * fabs(inst->peer_delays[n]);
peer_distance = inst->peer_dispersions[j] + 0.5 * inst->peer_delays[j];
UTI_DiffTimevalsToDouble(&elapsed, now, &(inst->offset_time));
UTI_DiffTimevalsToDouble(&sample_elapsed, now, &(inst->sample_times[n]));
*best_offset = inst->offsets[n] + sample_elapsed * inst->estimated_frequency;
*best_root_delay = inst->root_delays[n];
*best_root_dispersion = inst->root_dispersions[n] + sample_elapsed * inst->skew;
UTI_DiffTimevalsToDouble(&sample_elapsed, now, &inst->sample_times[i]);
*best_offset = inst->offsets[i] + sample_elapsed * inst->estimated_frequency;
*best_root_delay = inst->root_delays[j];
*best_root_dispersion = inst->root_dispersions[j] + sample_elapsed * inst->skew;
/* average_ok ignored for now */
average_offset = inst->estimated_offset + inst->estimated_frequency * elapsed;
if (fabs(average_offset - *best_offset) <= peer_distance) {
*average_ok = 1;
average_ok = 1;
} else {
*average_ok = 0;
average_ok = 0;
}
*select_ok = inst->regression_ok;
#ifdef TRACEON
LOG(LOGS_INFO, LOGF_SourceStats, "n=%d off=%f del=%f dis=%f var=%f pdist=%f avoff=%f avok=%d",
n, *best_offset, *best_root_delay, *best_root_dispersion, *variance,
peer_distance, average_offset, *average_ok);
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);
#endif
return;
@@ -639,26 +585,27 @@ SST_GetTrackingData(SST_Stats inst, struct timeval *now,
double *accrued_dispersion,
double *frequency, double *skew)
{
int n;
int i, j;
double peer_distance;
double elapsed_offset, elapsed_sample;
n = inst->best_single_sample;
i = get_runsbuf_index(inst, inst->best_single_sample);
j = get_buf_index(inst, inst->best_single_sample);
*frequency = inst->estimated_frequency;
*skew = inst->skew;
peer_distance = inst->peer_dispersions[n] + 0.5 * fabs(inst->peer_delays[n]);
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[n]));
UTI_DiffTimevalsToDouble(&elapsed_sample, now, &inst->sample_times[i]);
*accrued_dispersion = 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",
n, *frequency, 1.0e6* *frequency, *skew, 1.0e6* *skew, peer_distance, *average_offset, *offset_sd, *accrued_dispersion);
inst->n_samples, *frequency, 1.0e6* *frequency, *skew, 1.0e6* *skew, peer_distance, *average_offset, *offset_sd, *accrued_dispersion);
#endif
}
@@ -668,24 +615,16 @@ SST_GetTrackingData(SST_Stats inst, struct timeval *now,
void
SST_SlewSamples(SST_Stats inst, struct timeval *when, double dfreq, double doffset)
{
int n, i;
double elapsed;
int m, i;
double delta_time;
struct timeval *sample, prev;
double prev_offset, prev_freq;
n = inst->n_samples;
for (i=0; i<n; i++) {
for (m = -inst->runs_samples; m < inst->n_samples; m++) {
i = get_runsbuf_index(inst, m);
sample = &(inst->sample_times[i]);
prev = *sample;
#if 0
UTI_AdjustTimeval(sample, when, sample, dfreq, doffset);
/* Can't easily use this because we need to slew offset */
#endif
UTI_DiffTimevalsToDouble(&elapsed, when, sample);
delta_time = elapsed * dfreq - doffset;
UTI_AddDoubleToTimeval(sample, delta_time, sample);
UTI_AdjustTimeval(sample, when, sample, &delta_time, dfreq, doffset);
prev_offset = inst->offsets[i];
inst->offsets[i] += delta_time;
#ifdef TRACEON
@@ -696,12 +635,11 @@ SST_SlewSamples(SST_Stats inst, struct timeval *when, double dfreq, double doffs
}
/* Do a half-baked update to the regression estimates */
UTI_DiffTimevalsToDouble(&elapsed, when, &(inst->offset_time));
prev = inst->offset_time;
delta_time = elapsed * dfreq - doffset;
UTI_AddDoubleToTimeval(&(inst->offset_time), delta_time, &(inst->offset_time));
prev_offset = inst->estimated_offset;
prev_freq = inst->estimated_frequency;
UTI_AdjustTimeval(&(inst->offset_time), when, &(inst->offset_time),
&delta_time, dfreq, doffset);
inst->estimated_offset += delta_time;
inst->estimated_frequency -= dfreq;
@@ -717,6 +655,20 @@ SST_SlewSamples(SST_Stats inst, struct timeval *when, double dfreq, double doffs
/* ================================================== */
void
SST_AddDispersion(SST_Stats inst, double dispersion)
{
int m, i;
for (m = 0; m < inst->n_samples; m++) {
i = get_buf_index(inst, m);
inst->root_dispersions[i] += dispersion;
inst->peer_dispersions[i] += dispersion;
}
}
/* ================================================== */
double
SST_PredictOffset(SST_Stats inst, struct timeval *when)
{
@@ -727,7 +679,7 @@ SST_PredictOffset(SST_Stats inst, struct timeval *when)
interval is minimal. We can't do any useful prediction other
than use the latest sample or zero if we don't have any samples */
if (inst->n_samples > 0) {
return inst->offsets[inst->n_samples - 1];
return inst->offsets[inst->last_sample];
} else {
return 0.0;
}
@@ -743,21 +695,48 @@ SST_PredictOffset(SST_Stats inst, struct timeval *when)
double
SST_MinRoundTripDelay(SST_Stats inst)
{
double min_delay, delay;
int i;
if (inst->n_samples == 0) {
if (!inst->n_samples)
return DBL_MAX;
} else {
min_delay = fabs(inst->peer_delays[0]);
for (i=1; i<inst->n_samples; i++) {
delay = fabs(inst->peer_delays[i]);
if (delay < min_delay) {
min_delay = delay;
}
}
return min_delay;
return inst->peer_delays[inst->min_delay_sample];
}
/* ================================================== */
int
SST_IsGoodSample(SST_Stats inst, double offset, double delay,
double max_delay_dev_ratio, double clock_error, struct timeval *when)
{
double elapsed, allowed_increase, delay_increase;
if (inst->n_samples < 3)
return 1;
UTI_DiffTimevalsToDouble(&elapsed, when, &inst->offset_time);
/* Require that the ratio of the increase in delay from the minimum to the
standard deviation is less than max_delay_dev_ratio. In the allowed
increase in delay include also skew and clock_error. */
allowed_increase = sqrt(inst->variance) * max_delay_dev_ratio +
elapsed * (inst->skew + clock_error);
delay_increase = (delay - SST_MinRoundTripDelay(inst)) / 2.0;
if (delay_increase < allowed_increase)
return 1;
offset -= inst->estimated_offset + elapsed * inst->estimated_frequency;
/* Before we decide to drop the sample, make sure the difference between
measured offset and predicted offset is not significantly larger than
the increase in delay */
if (fabs(offset) - delay_increase > allowed_increase)
return 1;
#if 0
LOG(LOGS_INFO, LOGF_SourceStats, "bad sample: offset=%f delay=%f incr_delay=%f allowed=%f", offset, delay, allowed_increase, delay_increase);
#endif
return 0;
}
/* ================================================== */
@@ -767,23 +746,25 @@ SST_MinRoundTripDelay(SST_Stats inst)
void
SST_SaveToFile(SST_Stats inst, FILE *out)
{
int i;
int m, i, j;
fprintf(out, "%d\n", inst->n_samples);
for(i=0; i<inst->n_samples; i++) {
for(m = 0; m < inst->n_samples; m++) {
i = get_runsbuf_index(inst, m);
j = get_buf_index(inst, m);
fprintf(out, "%08lx %08lx %.6e %.6e %.6e %.6e %.6e %.6e %.6e %d\n",
(unsigned long) inst->sample_times[i].tv_sec,
(unsigned long) inst->sample_times[i].tv_usec,
inst->offsets[i],
inst->orig_offsets[i],
inst->peer_delays[i],
inst->peer_dispersions[i],
inst->root_delays[i],
inst->root_dispersions[i],
inst->weights[i],
inst->strata[i]);
inst->orig_offsets[j],
inst->peer_delays[j],
inst->peer_dispersions[j],
inst->root_delays[j],
inst->root_dispersions[j],
1.0, /* used to be inst->weights[i] */
inst->strata[j]);
}
}
@@ -797,9 +778,10 @@ SST_LoadFromFile(SST_Stats inst, FILE *in)
int i, line_number;
char line[1024];
unsigned long sec, usec;
double weight;
if (fgets(line, sizeof(line), in) &&
(sscanf(line, "%d", &inst->n_samples) == 1)) {
(sscanf(line, "%u", &inst->n_samples) == 1) && inst->n_samples <= MAX_SAMPLES) {
line_number = 2;
@@ -813,7 +795,7 @@ SST_LoadFromFile(SST_Stats inst, FILE *in)
&(inst->peer_dispersions[i]),
&(inst->root_delays[i]),
&(inst->root_dispersions[i]),
&(inst->weights[i]),
&weight, /* not used anymore */
&(inst->strata[i])) != 10)) {
/* This is the branch taken if the read FAILED */
@@ -836,6 +818,11 @@ SST_LoadFromFile(SST_Stats inst, FILE *in)
return 0;
}
inst->last_sample = inst->n_samples - 1;
inst->runs_samples = 0;
find_min_delay_sample(inst);
return 1;
}
@@ -845,17 +832,18 @@ SST_LoadFromFile(SST_Stats inst, FILE *in)
void
SST_DoSourceReport(SST_Stats inst, RPT_SourceReport *report, struct timeval *now)
{
int n;
int i, j;
struct timeval ago;
if (inst->n_samples > 0) {
n = inst->n_samples - 1;
report->orig_latest_meas = inst->orig_offsets[n];
report->latest_meas = inst->offsets[n];
report->latest_meas_err = 0.5*inst->root_delays[n] + inst->root_dispersions[n];
report->stratum = inst->strata[n];
i = get_runsbuf_index(inst, inst->n_samples - 1);
j = get_buf_index(inst, inst->n_samples - 1);
report->orig_latest_meas = inst->orig_offsets[j];
report->latest_meas = inst->offsets[i];
report->latest_meas_err = 0.5*inst->root_delays[j] + inst->root_dispersions[j];
report->stratum = inst->strata[j];
UTI_DiffTimevals(&ago, now, &inst->sample_times[n]);
UTI_DiffTimevals(&ago, now, &inst->sample_times[i]);
report->latest_meas_ago = ago.tv_sec;
} else {
report->latest_meas_ago = 86400 * 365 * 10;
@@ -876,32 +864,43 @@ SST_Skew_Direction SST_LastSkewChange(SST_Stats inst)
/* ================================================== */
int
SST_Samples(SST_Stats inst)
{
return inst->n_samples;
}
/* ================================================== */
void
SST_DoSourcestatsReport(SST_Stats inst, RPT_SourcestatsReport *report, struct timeval *now)
{
double dspan;
double elapsed, sample_elapsed;
int n, nb;
int li, lj, bi, bj;
report->n_samples = inst->n_samples;
report->n_runs = inst->nruns;
if (inst->n_samples > 1) {
n = inst->n_samples - 1;
UTI_DiffTimevalsToDouble(&dspan, &inst->sample_times[n], &inst->sample_times[0]);
li = get_runsbuf_index(inst, inst->n_samples - 1);
lj = get_buf_index(inst, inst->n_samples - 1);
UTI_DiffTimevalsToDouble(&dspan, &inst->sample_times[li],
&inst->sample_times[get_runsbuf_index(inst, 0)]);
report->span_seconds = (unsigned long) (dspan + 0.5);
if (inst->n_samples > 3) {
UTI_DiffTimevalsToDouble(&elapsed, now, &inst->offset_time);
nb = inst->best_single_sample;
UTI_DiffTimevalsToDouble(&sample_elapsed, now, &(inst->sample_times[nb]));
bi = get_runsbuf_index(inst, inst->best_single_sample);
bj = get_buf_index(inst, inst->best_single_sample);
UTI_DiffTimevalsToDouble(&sample_elapsed, now, &inst->sample_times[bi]);
report->est_offset = inst->estimated_offset + elapsed * inst->estimated_frequency;
report->est_offset_err = (inst->estimated_offset_sd +
sample_elapsed * inst->skew +
(0.5*inst->root_delays[nb] + inst->root_dispersions[nb]));
(0.5*inst->root_delays[bj] + inst->root_dispersions[bj]));
} else {
report->est_offset = inst->offsets[n];
report->est_offset_err = 0.5*inst->root_delays[n] + inst->root_dispersions[n];
report->est_offset = inst->offsets[li];
report->est_offset_err = 0.5*inst->root_delays[lj] + inst->root_dispersions[lj];
}
} else {
report->span_seconds = 0;
@@ -915,18 +914,3 @@ SST_DoSourcestatsReport(SST_Stats inst, RPT_SourcestatsReport *report, struct ti
}
/* ================================================== */
void
SST_CycleLogFile(void)
{
if (logfile && logfilename) {
fclose(logfile);
logfile = fopen(logfilename, "a");
if (!logfile) {
LOG(LOGS_WARN, LOGF_SourceStats, "Could not reopen logfile %s", logfilename);
}
logwrites = 0;
}
}
/* ================================================== */

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/sourcestats.h,v 1.13 2002/02/28 23:27:14 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -89,7 +85,7 @@ SST_GetSelectionData(SST_Stats inst, struct timeval *now,
double *best_offset, double *best_root_delay,
double *best_root_dispersion,
double *variance,
int *average_ok);
int *select_ok);
/* Get data needed when setting up tracking on this source */
extern void
@@ -125,6 +121,9 @@ SST_GetReferenceData(SST_Stats inst, struct timeval *now,
extern void SST_SlewSamples(SST_Stats inst, struct timeval *when, double dfreq, double doffset);
/* This routine is called when an indeterminate offset is introduced
into the local time. */
extern void SST_AddDispersion(SST_Stats inst, double dispersion);
/* Predict the offset of the local clock relative to a given source at
a given local cooked time. Positive indicates local clock is FAST
@@ -134,6 +133,11 @@ extern double SST_PredictOffset(SST_Stats inst, struct timeval *when);
/* Find the minimum round trip delay in the register */
extern double SST_MinRoundTripDelay(SST_Stats inst);
/* This routine determines if a new sample is good enough that it should be
accumulated */
extern int SST_IsGoodSample(SST_Stats inst, double offset, double delay,
double max_delay_dev_ratio, double clock_error, struct timeval *when);
extern void SST_SaveToFile(SST_Stats inst, FILE *out);
extern int SST_LoadFromFile(SST_Stats inst, FILE *in);
@@ -150,7 +154,7 @@ typedef enum {
extern SST_Skew_Direction SST_LastSkewChange(SST_Stats inst);
extern void SST_CycleLogFile(void);
extern int SST_Samples(SST_Stats inst);
#endif /* GOT_SOURCESTATS_H */

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/srcparams.h,v 1.10 2002/02/28 23:27:14 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -31,17 +27,33 @@
#ifndef GOT_SRCPARAMS_H
#define GOT_SRCPARAMS_H
#include "sources.h"
typedef struct {
int minpoll;
int maxpoll;
int online;
int auto_offline;
int presend_minpoll;
int iburst;
int min_stratum;
int poll_target;
unsigned long authkey;
double max_delay;
double max_delay_ratio;
double max_delay_dev_ratio;
SRC_SelectOption sel_option;
} SourceParameters;
#define SRC_DEFAULT_PORT 123
#define SRC_DEFAULT_MINPOLL 6
#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_MAXDELAYDEVRATIO 10.0
#define SRC_DEFAULT_MINSTRATUM 0
#define SRC_DEFAULT_POLLTARGET 6
#define INACTIVE_AUTHKEY 0UL
#endif /* GOT_SRCPARAMS_H */

View File

@@ -1,9 +1,4 @@
/*
$Header: /cvs/src/chrony/strerror.c,v 1.8 2002/02/28 23:27:14 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

4
sys.c
View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/sys.c,v 1.11 2002/02/28 23:27:14 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

4
sys.h
View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/sys.h,v 1.7 2002/02/28 23:27:14 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

View File

@@ -1,14 +1,10 @@
/*
$Header: /cvs/src/chrony/sys_linux.c,v 1.45 2003/10/04 19:56:40 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) John G. Hasler 2009
* Copyright (C) Miroslav Lichvar 2009
* Copyright (C) Miroslav Lichvar 2009-2011
*
* 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
@@ -113,24 +109,20 @@ txc.modes is set to ADJ_OFFSET_SS_READ. */
static int have_readonly_adjtime;
/* Flag indicating whether kernel supports PLL in nanosecond resolution.
If supported, it will be used instead of adjtime() for very small
adjustments. */
static int have_nanopll;
/* ================================================== */
static void handle_end_of_slew(void *anything);
/* ================================================== */
inline static int
our_round(double x) {
int y;
y = (int)(x + 0.5);
while ((double)y < x - 0.5) y++;
while ((double)y > x + 0.5) y--;
return y;
}
inline static long
our_lround(double x) {
int y;
our_round(double x) {
long y;
if (x > 0.0)
y = x + 0.5;
@@ -146,6 +138,9 @@ static double offset_register;
/* Flag set true if an adjtime slew was started and still may be running */
static int slow_slewing;
/* Flag set true if a PLL nano slew was started and still may be running */
static int nano_slewing;
/* Flag set true if a fast slew (one done by altering tick) is being
run at the moment */
static int fast_slewing;
@@ -182,6 +177,9 @@ static double delta_total_tick;
assuming it is resync'ed about once per day. (TBC) */
#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)
/* The amount by which we alter 'tick' when doing a large slew */
static int slew_delta_tick;
@@ -189,6 +187,155 @@ static int slew_delta_tick;
(sys_adjtimex() in the kernel bounds this to 10%) */
static int max_tick_bias;
/* The latest time at which system clock may still be slewed by previous
adjtime() call and maximum offset correction error it can cause */
static struct timeval slow_slew_error_end;
static int slow_slew_error;
/* Timeval at which the latest nano PLL adjustment was started and maximum
offset correction error it can cause */
static struct timeval nano_slew_error_start;
static int nano_slew_error;
/* The latest time at which 'tick' in kernel may be actually updated
and maximum offset correction error it can cause */
static struct timeval fast_slew_error_end;
static double fast_slew_error;
/* The rate at which frequency and tick values are updated in kernel. */
static int tick_update_hz;
/* ================================================== */
/* These routines are used to estimate maximum error in offset correction */
static void
update_slow_slew_error(int offset)
{
struct timeval now, newend;
if (offset == 0 && slow_slew_error == 0)
return;
if (gettimeofday(&now, NULL) < 0) {
LOG_FATAL(LOGF_SysLinux, "gettimeofday() failed");
}
if (offset < 0)
offset = -offset;
/* assume 500ppm rate and one sec delay, plus 10 percent for fast slewing */
UTI_AddDoubleToTimeval(&now, (offset + 999) / 500 * 1.1, &newend);
if (offset > 500)
offset = 500;
if (slow_slew_error > offset) {
double previous_left;
UTI_DiffTimevalsToDouble(&previous_left, &slow_slew_error_end, &now);
if (previous_left > 0.0) {
if (offset == 0)
newend = slow_slew_error_end;
offset = slow_slew_error;
}
}
slow_slew_error = offset;
slow_slew_error_end = newend;
}
static double
get_slow_slew_error(struct timeval *now)
{
double left;
if (slow_slew_error == 0)
return 0.0;
UTI_DiffTimevalsToDouble(&left, &slow_slew_error_end, now);
return left > 0.0 ? slow_slew_error / 1e6 : 0.0;
}
static void
update_nano_slew_error(long offset, int new)
{
struct timeval now;
double ago;
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;
if (offset < 0)
offset = -offset;
if (new || nano_slew_error_start.tv_sec > 0) {
if (gettimeofday(&now, NULL) < 0) {
LOG_FATAL(LOGF_SysLinux, "gettimeofday() failed");
}
}
/* When PLL offset is newly set, use the maximum of the old and new error.
Otherwise use the minimum, but only when the last update is older than
1.1 seconds to be sure the previous adjustment is already gone. */
if (!new) {
if (nano_slew_error > offset) {
if (nano_slew_error_start.tv_sec == 0) {
nano_slew_error = offset;
} else {
UTI_DiffTimevalsToDouble(&ago, &now, &nano_slew_error_start);
if (ago > 1.1) {
nano_slew_error_start.tv_sec = 0;
nano_slew_error = offset;
}
}
}
} else {
if (nano_slew_error < offset)
nano_slew_error = offset;
nano_slew_error_start = now;
}
}
static double
get_nano_slew_error(void)
{
if (nano_slew_error == 0)
return 0.0;
return nano_slew_error / 1e9;
}
static void
update_fast_slew_error(struct timeval *now)
{
double max_tick;
max_tick = current_total_tick +
(delta_total_tick > 0.0 ? delta_total_tick : 0.0);
UTI_AddDoubleToTimeval(now, 1e6 * max_tick / nominal_tick / tick_update_hz,
&fast_slew_error_end);
fast_slew_error = fabs(1e6 * delta_total_tick / nominal_tick / tick_update_hz);
}
static double
get_fast_slew_error(struct timeval *now)
{
double left;
if (fast_slew_error == 0.0)
return 0.0;
UTI_DiffTimevalsToDouble(&left, &fast_slew_error_end, now);
if (left < -10.0)
fast_slew_error = 0.0;
return left > 0.0 ? fast_slew_error : 0.0;
}
/* ================================================== */
/* This routine stops a fast slew, determines how long the slew has
been running for, and consequently how much adjustment has actually
@@ -198,44 +345,32 @@ static int max_tick_bias;
static void
stop_fast_slew(void)
{
struct timeval T1, T1d, T1a;
struct timezone tz;
double end_window;
struct timeval T1;
double fast_slew_done;
double slew_duration;
double introduced_dispersion;
/* Should never get here unless this is true */
if (!fast_slewing) {
CROAK("Should be fast slewing");
}
assert(fast_slewing);
/* Now set the thing off */
if (gettimeofday(&T1, &tz) < 0) {
CROAK("gettimeofday() failed in stop_fast_slew");
if (gettimeofday(&T1, NULL) < 0) {
LOG_FATAL(LOGF_SysLinux, "gettimeofday() failed");
}
if (TMX_SetTick(current_tick) < 0) {
CROAK("adjtimex() failed in stop_fast_slew");
}
if (gettimeofday(&T1d, &tz) < 0) {
CROAK("gettimeofday() failed in stop_fast_slew");
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
fast_slewing = 0;
UTI_AverageDiffTimevals(&T1, &T1d, &T1a, &end_window);
UTI_DiffTimevalsToDouble(&slew_duration, &T1a, &slew_start_tv);
UTI_DiffTimevalsToDouble(&slew_duration, &T1, &slew_start_tv);
/* Compute the dispersion we have introduced by changing tick this
way. If the two samples of gettimeofday differ, there is an
uncertainty window wrt when the frequency change actually applies
from. We handle this by adding dispersion to all statistics held
way. We handle this by adding dispersion to all statistics held
at higher levels in the system. */
introduced_dispersion = end_window * delta_total_tick;
lcl_InvokeDispersionNotifyHandlers(introduced_dispersion);
update_fast_slew_error(&T1);
lcl_InvokeDispersionNotifyHandlers(fast_slew_error);
fast_slew_done = delta_total_tick * slew_duration /
(current_total_tick + delta_total_tick);
@@ -244,6 +379,39 @@ stop_fast_slew(void)
}
/* ================================================== */
/* This routine reschedules fast slew timeout after frequency was changed */
static void
adjust_fast_slew(double old_tick, double old_delta_tick)
{
struct timeval tv, end_of_slew;
double fast_slew_done, slew_duration, dseconds;
assert(fast_slewing);
if (gettimeofday(&tv, NULL) < 0) {
LOG_FATAL(LOGF_SysLinux, "gettimeofday() failed");
}
UTI_DiffTimevalsToDouble(&slew_duration, &tv, &slew_start_tv);
fast_slew_done = old_delta_tick * slew_duration / (old_tick + old_delta_tick);
offset_register += fast_slew_wanted + fast_slew_done;
dseconds = -offset_register * (current_total_tick + delta_total_tick) / delta_total_tick;
if (dseconds > 3600 * 24 * 7)
dseconds = 3600 * 24 * 7;
UTI_AddDoubleToTimeval(&tv, dseconds, &end_of_slew);
slew_start_tv = tv;
fast_slew_wanted = offset_register;
offset_register = 0.0;
SCH_RemoveTimeout(slew_timeout_id);
slew_timeout_id = SCH_AddTimeout(&end_of_slew, handle_end_of_slew, NULL);
}
/* ================================================== */
/* This routine is called to start a clock offset adjustment */
@@ -254,42 +422,62 @@ initiate_slew(void)
double dseconds;
long tick_adjust;
long offset;
struct timeval T0, T0d, T0a;
struct timeval T0;
struct timeval end_of_slew;
struct timezone tz;
double start_window;
double introduced_dispersion;
/* Don't want to get here if we already have an adjust on the go! */
if (fast_slewing) {
CROAK("Should not be fast slewing");
}
assert(!fast_slewing);
if (offset_register == 0.0) {
return;
}
/* Cancel any standard adjtime that is running */
/* Cancel any slewing that is running */
if (slow_slewing) {
offset = 0;
if (TMX_ApplyOffset(&offset) < 0) {
CROAK("adjtimex() failed in accrue_offset");
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
offset_register -= (double) offset / 1.0e6;
slow_slewing = 0;
update_slow_slew_error(0);
} else if (nano_slewing) {
if (TMX_GetPLLOffsetLeft(&offset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
offset_register -= (double) offset / 1.0e9;
update_nano_slew_error(offset, 0);
offset = 0;
if (TMX_ApplyPLLOffset(offset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
nano_slewing = 0;
update_nano_slew_error(offset, 1);
}
if (fabs(offset_register) < MAX_ADJUST_WITH_ADJTIME) {
/* Use adjtime to do the shift */
offset = our_lround(1.0e6 * -offset_register);
if (have_nanopll && fabs(offset_register) < MAX_ADJUST_WITH_NANOPLL) {
/* Use PLL with fixed frequency to do the shift */
offset = 1.0e9 * -offset_register;
offset_register += offset * 1e-6;
if (TMX_ApplyPLLOffset(offset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
offset_register = 0.0;
nano_slewing = 1;
update_nano_slew_error(offset, 1);
} else if (fabs(offset_register) < MAX_ADJUST_WITH_ADJTIME) {
/* Use adjtime to do the shift */
offset = our_round(1.0e6 * -offset_register);
offset_register += offset / 1.0e6;
if (offset != 0) {
if (TMX_ApplyOffset(&offset) < 0) {
CROAK("adjtimex() failed in initiate_slew");
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
slow_slewing = 1;
update_slow_slew_error(offset);
}
} else {
@@ -322,41 +510,28 @@ initiate_slew(void)
dseconds = - offset_register * (current_total_tick + delta_total_tick) / delta_total_tick;
/* Now set the thing off */
if (gettimeofday(&T0, &tz) < 0) {
CROAK("gettimeofday() failed in initiate_slew");
if (gettimeofday(&T0, NULL) < 0) {
LOG_FATAL(LOGF_SysLinux, "gettimeofday() failed");
}
if (TMX_SetTick(slewing_tick) < 0) {
LOG(LOGS_INFO, LOGF_SysLinux, "c_t=%ld ta=%ld sl_t=%ld dtt=%e",
current_tick, tick_adjust, slewing_tick, delta_total_tick);
CROAK("adjtimex() failed to start big slew");
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
if (gettimeofday(&T0d, &tz) < 0) {
CROAK("gettimeofday() failed in initiate_slew");
}
/* Now work out the uncertainty in when we actually started the
slew. */
UTI_AverageDiffTimevals(&T0, &T0d, &T0a, &start_window);
/* Compute the dispersion we have introduced by changing tick this
way. If the two samples of gettimeofday differ, there is an
uncertainty window wrt when the frequency change actually applies
from. We handle this by adding dispersion to all statistics held
way. We handle this by adding dispersion to all statistics held
at higher levels in the system. */
introduced_dispersion = start_window * delta_total_tick;
lcl_InvokeDispersionNotifyHandlers(introduced_dispersion);
update_fast_slew_error(&T0);
lcl_InvokeDispersionNotifyHandlers(fast_slew_error);
fast_slewing = 1;
slew_start_tv = T0a;
slew_start_tv = T0;
/* Set up timeout for end of slew, limit to one week */
if (dseconds > 3600 * 24 * 7)
dseconds = 3600 * 24 * 7;
UTI_AddDoubleToTimeval(&T0a, dseconds, &end_of_slew);
UTI_AddDoubleToTimeval(&T0, dseconds, &end_of_slew);
slew_timeout_id = SCH_AddTimeout(&end_of_slew, handle_end_of_slew, NULL);
@@ -420,22 +595,29 @@ static void
apply_step_offset(double offset)
{
struct timeval old_time, new_time;
struct timezone tz;
double err;
if (fast_slewing) {
abort_slew();
}
if (gettimeofday(&old_time, &tz) < 0) {
CROAK("gettimeofday in apply_step_offset");
if (gettimeofday(&old_time, NULL) < 0) {
LOG_FATAL(LOGF_SysLinux, "gettimeofday() failed");
}
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
if (settimeofday(&new_time, &tz) < 0) {
CROAK("settimeofday in apply_step_offset");
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();
}
@@ -447,25 +629,19 @@ apply_step_offset(double offset)
convention is that this is called with a positive argument if the local
clock runs fast when uncompensated. */
static void
set_frequency(double freq_ppm) {
static double
set_frequency(double freq_ppm)
{
long required_tick;
long min_allowed_tick, max_allowed_tick;
double required_freq; /* what we use */
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 we in the middle of slewing the time by having the value of
tick altered, we have to stop doing that, because the timeout
expiry etc will change if we don't. */
if (fast_slewing) {
abort_slew();
}
if (freq_ppm < 0.0) {
neg = 1;
freq_ppm = -freq_ppm;
@@ -486,20 +662,42 @@ set_frequency(double freq_ppm) {
scaled_freq = -freq_scale * required_freq;
}
if (TMX_SetFrequency(scaled_freq, required_tick) < 0) {
char buffer[1024];
sprintf(buffer, "adjtimex failed for set_frequency, freq_ppm=%10.4e scaled_freq=%10.4e required_tick=%ld",
freq_ppm, scaled_freq, required_tick);
CROAK(buffer);
min_allowed_tick = nominal_tick - max_tick_bias + 5;
max_allowed_tick = nominal_tick + max_tick_bias - 5;
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);
if (required_tick < min_allowed_tick) {
required_tick = min_allowed_tick;
} else {
required_tick = max_allowed_tick;
}
}
current_tick = required_tick;
old_total_tick = current_total_tick;
current_total_tick = ((double)current_tick + required_freq/dhz) / 1.0e6 ;
initiate_slew(); /* Restart any slews that need to be restarted */
/* Don't change tick if we are fast slewing, just reschedule the timeout */
if (fast_slewing) {
required_tick = slewing_tick;
}
return;
if (TMX_SetFrequency(&scaled_freq, required_tick) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex failed for set_frequency, freq_ppm=%10.4e scaled_freq=%10.4e required_tick=%ld",
freq_ppm, scaled_freq, required_tick);
}
if (fast_slewing) {
double old_delta_tick;
old_delta_tick = delta_total_tick;
delta_total_tick = ((double)slewing_tick + required_freq/dhz) / 1.0e6 -
current_total_tick;
adjust_fast_slew(old_total_tick, old_delta_tick);
}
return dhz * (nominal_tick - current_tick) - scaled_freq / freq_scale;
}
/* ================================================== */
@@ -513,7 +711,7 @@ read_frequency(void)
double freq_term;
if (TMX_GetFrequency(&unscaled_freq) < 0) {
CROAK("adjtimex failed in read_frequency");
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
/* Use current_tick here rather than txc.tick, otherwise we're
@@ -538,46 +736,43 @@ read_frequency(void)
static void
get_offset_correction(struct timeval *raw,
double *corr)
double *corr, double *err)
{
/* Correction is given by these things :
1. Any value in offset register
2. Amount of fast slew remaining
3. Any amount of adjtime correction remaining */
3. Any amount of adjtime correction remaining
4. Any amount of nanopll correction remaining */
double adjtime_left;
double fast_slew_duration;
double fast_slew_achieved;
double fast_slew_remaining;
long offset, toffset;
long offset, noffset, toffset;
if (!slow_slewing) {
offset = 0;
} else {
again:
switch (have_readonly_adjtime) {
case 2:
if (TMX_GetOffsetLeft(&offset) < 0) {
LOG(LOGS_INFO, LOGF_SysLinux, "adjtimex() doesn't support ADJ_OFFSET_SS_READ");
have_readonly_adjtime = 0;
goto again;
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
break;
case 0:
toffset = 0;
if (TMX_ApplyOffset(&toffset) < 0) {
CROAK("adjtimex() failed in get_offset_correction");
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
offset = toffset;
if (TMX_ApplyOffset(&toffset) < 0) {
CROAK("adjtimex() failed in get_offset_correction");
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
break;
case 1:
if (TMX_GetOffsetLeftOld(&offset) < 0) {
CROAK("adjtimex() failed in get_offset_correction");
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
break;
default:
@@ -590,7 +785,16 @@ again:
}
}
adjtime_left = (double)offset / 1.0e6;
if (!nano_slewing) {
noffset = 0;
} else {
if (TMX_GetPLLOffsetLeft(&noffset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
if (noffset == 0) {
nano_slewing = 0;
}
}
if (fast_slewing) {
UTI_DiffTimevalsToDouble(&fast_slew_duration, raw, &slew_start_tv);
@@ -601,7 +805,13 @@ again:
fast_slew_remaining = 0.0;
}
*corr = - (offset_register + fast_slew_remaining) + adjtime_left;
*corr = - (offset_register + fast_slew_remaining) + offset / 1.0e6 + noffset / 1.0e9;
if (err) {
update_slow_slew_error(offset);
update_nano_slew_error(noffset, 0);
*err = get_slow_slew_error(raw) + get_fast_slew_error(raw) + get_nano_slew_error();;
}
return;
}
@@ -700,6 +910,7 @@ get_version_specific_details(void)
nominal_tick = (1000000L + (hz/2))/hz; /* Mirror declaration in kernel */
slew_delta_tick = nominal_tick / 12;
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);
@@ -745,6 +956,8 @@ 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? */
@@ -807,13 +1020,19 @@ get_version_specific_details(void)
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 need scaling */
/* 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.");
@@ -840,6 +1059,8 @@ get_version_specific_details(void)
void
SYS_Linux_Initialise(void)
{
long offset;
offset_register = 0.0;
fast_slewing = 0;
@@ -851,6 +1072,23 @@ SYS_Linux_Initialise(void)
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)) {
LOG(LOGS_INFO, LOGF_SysLinux, "adjtimex() doesn't support ADJ_OFFSET_SS_READ");
have_readonly_adjtime = 0;
}
if (have_nanopll && TMX_EnableNanoPLL() < 0) {
LOG(LOGS_INFO, LOGF_SysLinux, "adjtimex() doesn't support nanosecond PLL");
have_nanopll = 0;
}
TMX_SetSync(CNF_GetRTCSync());
}
/* ================================================== */

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/sys_linux.h,v 1.8 2002/02/28 23:27:15 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/sys_netbsd.c,v 1.2 2002/02/17 22:13:49 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -78,21 +74,20 @@ static void
clock_initialise(void)
{
struct timeval newadj, oldadj;
struct timezone tz;
offset_register = 0.0;
adjustment_requested = 0.0;
current_freq = 0.0;
if (gettimeofday(&T0, &tz) < 0) {
CROAK("gettimeofday() failed in clock_initialise()");
if (gettimeofday(&T0, NULL) < 0) {
LOG_FATAL(LOGF_SysNetBSD, "gettimeofday() failed");
}
newadj.tv_sec = 0;
newadj.tv_usec = 0;
if (adjtime(&newadj, &oldadj) < 0) {
CROAK("adjtime() failed in clock_initialise");
LOG_FATAL(LOGF_SysNetBSD, "adjtime() failed");
}
}
@@ -113,7 +108,6 @@ start_adjust(void)
{
struct timeval newadj, oldadj;
struct timeval T1;
struct timezone tz;
double elapsed, accrued_error;
double adjust_required;
struct timeval exact_newadj;
@@ -122,8 +116,8 @@ start_adjust(void)
double old_adjust_remaining;
/* Determine the amount of error built up since the last adjustment */
if (gettimeofday(&T1, &tz) < 0) {
CROAK("gettimeofday() failed in start_adjust");
if (gettimeofday(&T1, NULL) < 0) {
LOG_FATAL(LOGF_SysNetBSD, "gettimeofday() failed");
}
UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0);
@@ -151,7 +145,7 @@ start_adjust(void)
UTI_DiffTimevalsToDouble(&rounding_error, &newadj, &exact_newadj);
if (adjtime(&newadj, &oldadj) < 0) {
CROAK("adjtime() failed in start_adjust");
LOG_FATAL(LOGF_SysNetBSD, "adjtime() failed");
}
UTI_TimevalToDouble(&oldadj, &old_adjust_remaining);
@@ -169,7 +163,6 @@ static void
stop_adjust(void)
{
struct timeval T1;
struct timezone tz;
struct timeval zeroadj, remadj;
double adjustment_remaining, adjustment_achieved;
double elapsed, elapsed_plus_adjust;
@@ -178,11 +171,11 @@ stop_adjust(void)
zeroadj.tv_usec = 0;
if (adjtime(&zeroadj, &remadj) < 0) {
CROAK("adjtime() failed in stop_adjust");
LOG_FATAL(LOGF_SysNetBSD, "adjtime() failed");
}
if (gettimeofday(&T1, &tz) < 0) {
CROAK("gettimeofday() failed in stop_adjust");
if (gettimeofday(&T1, NULL) < 0) {
LOG_FATAL(LOGF_SysNetBSD, "gettimeofday() failed");
}
UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0);
@@ -221,18 +214,17 @@ static void
apply_step_offset(double offset)
{
struct timeval old_time, new_time, T1;
struct timezone tz;
stop_adjust();
if (gettimeofday(&old_time, &tz) < 0) {
CROAK("gettimeofday in apply_step_offset");
if (gettimeofday(&old_time, NULL) < 0) {
LOG_FATAL(LOGF_SysNetBSD, "gettimeofday() failed");
}
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
if (settimeofday(&new_time, &tz) < 0) {
CROAK("settimeofday in apply_step_offset");
if (settimeofday(&new_time, NULL) < 0) {
LOG_FATAL(LOGF_SysNetBSD, "settimeofday() failed");
}
UTI_AddDoubleToTimeval(&T0, offset, &T1);
@@ -244,12 +236,14 @@ apply_step_offset(double offset)
/* ================================================== */
static void
static double
set_frequency(double new_freq_ppm)
{
stop_adjust();
current_freq = new_freq_ppm * 1.0e-6;
start_adjust();
return current_freq * 1.0e6;
}
/* ================================================== */
@@ -264,11 +258,13 @@ read_frequency(void)
static void
get_offset_correction(struct timeval *raw,
double *corr)
double *corr, double *err)
{
stop_adjust();
*corr = -offset_register;
start_adjust();
if (err)
*err = 0.0;
}
/* ================================================== */
@@ -287,15 +283,15 @@ SYS_NetBSD_Initialise(void)
kt = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);
if (!kt) {
CROAK("Cannot open kvm\n");
LOG_FATAL(LOGF_SysNetBSD, "Cannot open kvm");
}
if (kvm_nlist(kt, nl) < 0) {
CROAK("Cannot read kernel symbols\n");
LOG_FATAL(LOGF_SysNetBSD, "Cannot read kernel symbols");
}
if (kvm_read(kt, nl[0].n_value, (char *)(&kern_tickadj), sizeof(int)) < 0) {
CROAK("Cannot read from _tickadj\n");
LOG_FATAL(LOGF_SysNetBSD, "Cannot read from _tickadj");
}
if (kvm_read(kt, nl[1].n_value, (char *)(&kern_bigadj), sizeof(long)) < 0) {

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/sys_netbsd.h,v 1.2 2002/02/17 22:13:49 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/sys_solaris.c,v 1.19 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -94,24 +90,23 @@ static void
clock_initialise(void)
{
struct timeval newadj, oldadj;
struct timezone tz;
offset_register = 0.0;
adjustment_requested = 0.0;
current_freq = 0.0;
if (gettimeofday(&T0, &tz) < 0) {
CROAK("gettimeofday() failed in clock_initialise()");
if (gettimeofday(&T0, NULL) < 0) {
LOG_FATAL(LOGF_SysSolaris, "gettimeofday() failed");
}
newadj = GET_ZERO;
if (adjtime(&newadj, &oldadj) < 0) {
CROAK("adjtime() failed in clock_initialise");
LOG_FATAL(LOGF_SysSolaris, "adjtime() failed");
}
if (adjtime(&newadj, &oldadj) < 0) {
CROAK("adjtime() failed in clock_initialise");
LOG_FATAL(LOGF_SysSolaris, "adjtime() failed");
}
return;
@@ -135,7 +130,6 @@ start_adjust(void)
{
struct timeval newadj, oldadj;
struct timeval T1;
struct timezone tz;
double elapsed, accrued_error;
double adjust_required;
struct timeval exact_newadj;
@@ -143,8 +137,8 @@ start_adjust(void)
double old_adjust_remaining;
/* Determine the amount of error built up since the last adjustment */
if (gettimeofday(&T1, &tz) < 0) {
CROAK("gettimeofday() failed in start_adjust");
if (gettimeofday(&T1, NULL) < 0) {
LOG_FATAL(LOGF_SysSolaris, "gettimeofday() failed");
}
UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0);
@@ -164,7 +158,7 @@ start_adjust(void)
UTI_DiffTimevalsToDouble(&rounding_error, &exact_newadj, &newadj);
if (adjtime(&newadj, &oldadj) < 0) {
CROAK("adjtime() failed in start_adjust");
LOG_FATAL(LOGF_SysSolaris, "adjtime() failed");
}
UTI_TimevalToDouble(&oldadj, &old_adjust_remaining);
@@ -182,7 +176,6 @@ static void
stop_adjust(void)
{
struct timeval T1;
struct timezone tz;
struct timeval zeroadj, remadj;
double adjustment_remaining, adjustment_achieved;
double elapsed, elapsed_plus_adjust;
@@ -191,11 +184,11 @@ stop_adjust(void)
zeroadj = GET_ZERO;
if (adjtime(&zeroadj, &remadj) < 0) {
CROAK("adjtime() failed in stop_adjust");
LOG_FATAL(LOGF_SysSolaris, "adjtime() failed");
}
if (gettimeofday(&T1, &tz) < 0) {
CROAK("gettimeofday() failed in stop_adjust");
if (gettimeofday(&T1, NULL) < 0) {
LOG_FATAL(LOGF_SysSolaris, "gettimeofday() failed");
}
UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0);
@@ -235,11 +228,10 @@ apply_step_offset(double offset)
{
struct timeval old_time, new_time, rounded_new_time, T1;
double rounding_error;
struct timezone tz;
stop_adjust();
if (gettimeofday(&old_time, &tz) < 0) {
CROAK("gettimeofday in apply_step_offset");
if (gettimeofday(&old_time, NULL) < 0) {
LOG_FATAL(LOGF_SysSolaris, "gettimeofday() failed");
}
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
@@ -259,8 +251,8 @@ apply_step_offset(double offset)
UTI_DiffTimevalsToDouble(&rounding_error, &rounded_new_time, &new_time);
if (settimeofday(&new_time, &tz) < 0) {
CROAK("settimeofday in apply_step_offset");
if (settimeofday(&new_time, NULL) < 0) {
LOG_FATAL(LOGF_SysSolaris, "settimeofday() failed");
}
UTI_AddDoubleToTimeval(&T0, offset, &T1);
@@ -273,12 +265,14 @@ apply_step_offset(double offset)
/* ================================================== */
static void
static double
set_frequency(double new_freq_ppm)
{
stop_adjust();
current_freq = new_freq_ppm * 1.0e-6;
start_adjust();
return current_freq * 1.0e6;
}
/* ================================================== */
@@ -293,11 +287,13 @@ read_frequency(void)
static void
get_offset_correction(struct timeval *raw,
double *corr)
double *corr, double *err)
{
stop_adjust();
*corr = -offset_register;
start_adjust();
if (err)
*err = 0.0;
return;
}
@@ -390,9 +386,7 @@ set_dosynctodr(unsigned long on_off)
kvm_t *kt;
unsigned long read_back;
if (on_off!=1 && on_off!=0) {
CROAK("on_off should be 0 or 1");
}
assert(on_off == 1 || on_off == 0);
kt = kvm_open(NULL, NULL, NULL, O_RDWR, NULL);
if (!kt) {
@@ -420,9 +414,7 @@ set_dosynctodr(unsigned long on_off)
kvm_close(kt);
if (read_back != on_off) {
CROAK("read_back should equal on_off");
}
assert(read_back == on_off);
#if 0
LOG(LOGS_INFO, LOGF_SysSolaris, "Set value of dosynctodr to %d", on_off);

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/sys_solaris.h,v 1.7 2002/02/28 23:27:15 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/sys_sunos.c,v 1.19 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -84,25 +80,24 @@ static void
clock_initialise(void)
{
struct timeval newadj, oldadj;
struct timezone tz;
offset_register = 0.0;
adjustment_requested = 0.0;
current_freq = 0.0;
if (gettimeofday(&T0, &tz) < 0) {
CROAK("gettimeofday() failed in clock_initialise()");
if (gettimeofday(&T0, NULL) < 0) {
LOG_FATAL(LOGF_SysSunOS, "gettimeofday() failed");
}
newadj.tv_sec = 0;
newadj.tv_usec = 0;
if (adjtime(&newadj, &oldadj) < 0) {
CROAK("adjtime() failed in clock_initialise");
LOG_FATAL(LOGF_SysSunOS, "adjtime() failed");
}
if (adjtime(&newadj, &oldadj) < 0) {
CROAK("adjtime() failed in clock_initialise");
LOG_FATAL(LOGF_SysSunOS, "adjtime() failed");
}
return;
@@ -126,7 +121,6 @@ start_adjust(void)
{
struct timeval newadj, oldadj;
struct timeval T1;
struct timezone tz;
double elapsed, accrued_error;
double adjust_required;
struct timeval exact_newadj;
@@ -135,8 +129,8 @@ start_adjust(void)
long remainder, multiplier;
/* Determine the amount of error built up since the last adjustment */
if (gettimeofday(&T1, &tz) < 0) {
CROAK("gettimeofday() failed in start_adjust");
if (gettimeofday(&T1, NULL) < 0) {
LOG_FATAL(LOGF_SysSunOS, "gettimeofday() failed");
}
UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0);
@@ -167,7 +161,7 @@ start_adjust(void)
UTI_DiffTimevalsToDouble(&rounding_error, &newadj, &exact_newadj);
if (adjtime(&newadj, &oldadj) < 0) {
CROAK("adjtime() failed in start_adjust");
LOG_FATAL(LOGF_SysSunOS, "adjtime() failed");
}
UTI_TimevalToDouble(&oldadj, &old_adjust_remaining);
@@ -185,7 +179,6 @@ static void
stop_adjust(void)
{
struct timeval T1;
struct timezone tz;
struct timeval zeroadj, remadj;
double adjustment_remaining, adjustment_achieved;
double gap;
@@ -195,11 +188,11 @@ stop_adjust(void)
zeroadj.tv_usec = 0;
if (adjtime(&zeroadj, &remadj) < 0) {
CROAK("adjtime() failed in stop_adjust");
LOG_FATAL(LOGF_SysSunOS, "adjtime() failed");
}
if (gettimeofday(&T1, &tz) < 0) {
CROAK("gettimeofday() failed in stop_adjust");
if (gettimeofday(&T1, NULL) < 0) {
LOG_FATAL(LOGF_SysSunOS, "gettimeofday() failed");
}
UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0);
@@ -238,17 +231,16 @@ static void
apply_step_offset(double offset)
{
struct timeval old_time, new_time, T1;
struct timezone tz;
stop_adjust();
if (gettimeofday(&old_time, &tz) < 0) {
CROAK("gettimeofday in apply_step_offset");
if (gettimeofday(&old_time, NULL) < 0) {
LOG_FATAL(LOGF_SysSunOS, "gettimeofday() failed");
}
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
if (settimeofday(&new_time, &tz) < 0) {
CROAK("settimeofday in apply_step_offset");
if (settimeofday(&new_time, NULL) < 0) {
LOG_FATAL(LOGF_SysSunOS, "settimeofday() failed");
}
UTI_AddDoubleToTimeval(&T0, offset, &T1);
@@ -260,12 +252,14 @@ apply_step_offset(double offset)
/* ================================================== */
static void
static double
set_frequency(double new_freq_ppm)
{
stop_adjust();
current_freq = new_freq_ppm * 1.0e-6;
start_adjust();
return current_freq * 1.0e6;
}
/* ================================================== */
@@ -280,11 +274,13 @@ read_frequency(void)
static void
get_offset_correction(struct timeval *raw,
double *corr)
double *corr, double *err)
{
stop_adjust();
*corr = -offset_register;
start_adjust();
if (err)
*err = 0.0;
return;
}
@@ -339,9 +335,7 @@ setup_kernel(unsigned long on_off)
unsigned long our_tick = 10000;
unsigned long default_tickadj = 625;
if (on_off!=1 && on_off!=0) {
CROAK("on_off should be 0 or 1");
}
assert(on_off == 1 || on_off == 0);
kt = kvm_open(NULL, NULL, NULL, O_RDWR, NULL);
if (!kt) {

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/sys_sunos.h,v 1.7 2002/02/28 23:27:15 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/sysincl.h,v 1.11 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************

101
tempcomp.c Normal file
View File

@@ -0,0 +1,101 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2011
*
* 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 temperature compensation.
*/
#include "conf.h"
#include "local.h"
#include "memory.h"
#include "util.h"
#include "logging.h"
#include "sched.h"
#include "tempcomp.h"
static SCH_TimeoutID timeout_id;
static LOG_FileID logfileid;
static char *filename;
static double update_interval;
static double T0, k0, k1, k2;
static void
read_timeout(void *arg)
{
FILE *f;
double temp, comp;
f = fopen(filename, "r");
if (f && fscanf(f, "%lf", &temp) == 1) {
comp = k0 + (temp - T0) * k1 + (temp - T0) * (temp - T0) * k2;
/* Don't allow corrections above 10 ppm */
if (fabs(comp) < 10.0) {
comp = LCL_SetTempComp(comp);
if (logfileid != -1) {
struct timeval now;
LCL_ReadCookedTime(&now, NULL);
LOG_FileWrite(logfileid, "%s %11.4e %11.4e",
UTI_TimeToLogForm(now.tv_sec), temp, comp);
}
}
}
if (f)
fclose(f);
timeout_id = SCH_AddTimeoutByDelay(update_interval, read_timeout, NULL);
}
void
TMC_Initialise(void)
{
CNF_GetTempComp(&filename, &update_interval, &T0, &k0, &k1, &k2);
if (filename == NULL)
return;
if (update_interval <= 0.0)
update_interval = 1.0;
logfileid = CNF_GetLogTempComp() ? LOG_FileOpen("tempcomp",
" Date (UTC) Time Temp. Comp.")
: -1;
read_timeout(NULL);
}
void
TMC_Finalise(void)
{
if (filename == NULL)
return;
SCH_RemoveTimeout(timeout_id);
Free(filename);
}

29
tempcomp.h Normal file
View File

@@ -0,0 +1,29 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2011
*
* 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 temperature compensation.
*/
extern void TMC_Initialise(void);
extern void TMC_Finalise(void);

29
util.c
View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/util.c,v 1.22 2003/09/28 22:21:17 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -442,13 +438,13 @@ UTI_TimeToLogForm(time_t t)
/* ================================================== */
void
UTI_AdjustTimeval(struct timeval *old_tv, struct timeval *when, struct timeval *new_tv, double dfreq, double doffset)
UTI_AdjustTimeval(struct timeval *old_tv, struct timeval *when, struct timeval *new_tv, double *delta_time, double dfreq, double doffset)
{
double elapsed, delta_time;
double elapsed;
UTI_DiffTimevalsToDouble(&elapsed, when, old_tv);
delta_time = elapsed * dfreq - doffset;
UTI_AddDoubleToTimeval(old_tv, delta_time, new_tv);
*delta_time = elapsed * dfreq - doffset;
UTI_AddDoubleToTimeval(old_tv, *delta_time, new_tv);
}
/* ================================================== */
@@ -506,9 +502,8 @@ UTI_TimevalNetworkToHost(Timeval *src, struct timeval *dest)
is only 32-bit */
if (sizeof (time_t) > 4 && sec_high == TV_NOHIGHSEC) {
struct timeval now;
struct timezone tz;
gettimeofday(&now, &tz);
gettimeofday(&now, NULL);
sec_high = now.tv_sec >> 16 >> 16;
}
dest->tv_sec = (time_t)sec_high << 16 << 16 | sec_low;
@@ -601,3 +596,17 @@ UTI_FloatHostToNetwork(double x)
}
/* ================================================== */
void
UTI_FdSetCloexec(int fd)
{
int flags;
flags = fcntl(fd, F_GETFD);
if (flags != -1) {
flags |= FD_CLOEXEC;
fcntl(fd, F_SETFD, flags);
}
}
/* ================================================== */

9
util.h
View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/util.h,v 1.15 2003/09/22 21:22:30 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -89,7 +85,7 @@ extern int UTI_CompareIPs(IPAddr *a, IPAddr *b, IPAddr *mask);
extern char *UTI_TimeToLogForm(time_t t);
/* Adjust time following a frequency/offset change */
extern void UTI_AdjustTimeval(struct timeval *old_tv, struct timeval *when, struct timeval *new_tv, double dfreq, double doffset);
extern void UTI_AdjustTimeval(struct timeval *old_tv, struct timeval *when, struct timeval *new_tv, double *delta, double dfreq, double doffset);
extern void UTI_TimevalToInt64(struct timeval *src, NTP_int64 *dest);
@@ -102,6 +98,9 @@ extern void UTI_TimevalHostToNetwork(struct timeval *src, Timeval *dest);
extern double UTI_FloatNetworkToHost(Float x);
extern Float UTI_FloatHostToNetwork(double x);
/* Set FD_CLOEXEC on descriptor */
extern void UTI_FdSetCloexec(int fd);
#if defined (INLINE_UTILITIES)
#define INLINE_STATIC inline static
#include "util.c"

View File

@@ -1,12 +1,9 @@
/*
$Header: /cvs/src/chrony/wrap_adjtimex.c,v 1.9 2002/11/19 21:33:42 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2002
* Copyright (C) Miroslav Lichvar 2011
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -39,8 +36,7 @@
#include "chrony_timex.h"
#include "wrap_adjtimex.h"
/* Save leap status between calls */
static int leap_status = 0;
static int status = 0;
int
TMX_SetTick(long tick)
@@ -66,17 +62,23 @@ TMX_ApplyOffset(long *offset)
}
int
TMX_SetFrequency(double freq, long tick)
TMX_SetFrequency(double *freq, long tick)
{
struct timex txc;
txc.modes = ADJ_TICK | ADJ_FREQUENCY | ADJ_STATUS;
txc.freq = (long)(freq * (double)(1 << SHIFT_USEC));
txc.freq = (long)(*freq * (double)(1 << SHIFT_USEC));
*freq = txc.freq / (double)(1 << SHIFT_USEC);
txc.tick = tick;
txc.status = STA_UNSYNC; /* Prevent any of the FLL/PLL stuff coming
up */
txc.status |= leap_status; /* Preserve leap bits */
txc.status = status;
if (!(status & STA_UNSYNC)) {
/* maxerror has to be reset periodically to prevent kernel
from enabling UNSYNC flag */
txc.modes |= ADJ_MAXERROR;
txc.maxerror = 0;
}
return adjtimex(&txc);
}
@@ -164,19 +166,76 @@ TMX_SetLeap(int leap)
{
struct timex txc;
status &= ~(STA_INS | STA_DEL);
if (leap > 0) {
leap_status = STA_INS;
status |= STA_INS;
} else if (leap < 0) {
leap_status = STA_DEL;
} else {
leap_status = 0;
status |= STA_DEL;
}
txc.modes = ADJ_STATUS;
txc.status = STA_UNSYNC | leap_status;
txc.status = status;
return adjtimex(&txc);
}
int TMX_SetSync(int sync)
{
struct timex txc;
if (sync) {
status &= ~STA_UNSYNC;
} else {
status |= STA_UNSYNC;
}
txc.modes = ADJ_STATUS;
txc.status = status;
return adjtimex(&txc);
}
int
TMX_EnableNanoPLL(void)
{
struct timex txc;
int result;
txc.modes = ADJ_STATUS | ADJ_OFFSET | ADJ_TIMECONST | ADJ_NANO;
txc.status = STA_PLL | STA_FREQHOLD;
txc.offset = 0;
txc.constant = 0;
result = adjtimex(&txc);
if (result < 0 || !(txc.status & STA_NANO) || txc.offset || txc.constant)
return -1;
status |= STA_PLL | STA_FREQHOLD;
return result;
}
int
TMX_ApplyPLLOffset(long offset)
{
struct timex txc;
txc.modes = ADJ_OFFSET | ADJ_TIMECONST | ADJ_NANO;
txc.offset = offset;
txc.constant = 0;
return adjtimex(&txc);
}
int
TMX_GetPLLOffsetLeft(long *offset)
{
struct timex txc;
int result;
txc.modes = 0;
result = adjtimex(&txc);
*offset = txc.offset;
return result;
}
#endif

View File

@@ -1,8 +1,4 @@
/*
$Header: /cvs/src/chrony/wrap_adjtimex.h,v 1.6 2002/11/19 21:33:42 richard Exp $
=======================================================================
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
@@ -70,12 +66,16 @@ struct tmx_params {
int TMX_SetTick(long tick);
int TMX_ApplyOffset(long *offset);
int TMX_SetFrequency(double freq, long tick);
int TMX_SetFrequency(double *freq, long tick);
int TMX_GetFrequency(double *freq);
int TMX_GetOffsetLeftOld(long *offset);
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_GetPLLOffsetLeft(long *offset);
#endif /* GOT_WRAP_ADJTIMEX_H */