Compare commits

...

627 Commits

Author SHA1 Message Date
Miroslav Lichvar
b862f3e64d Update NEWS 2014-08-21 10:06:09 +02:00
Miroslav Lichvar
4e66b5ce8a ntp: don't stop online burst when sending fails
Don't stop online burst for unreachable sources until sending succeeds.
This is mainly useful with iburst when chronyd is started before the
network is configured.
2014-08-20 16:54:26 +02:00
Miroslav Lichvar
d446950c6a ntp: don't adjust polling interval when sending fails 2014-08-20 16:54:26 +02:00
Miroslav Lichvar
e3c77f9b4b ntp: return with status from functions sending packets 2014-08-20 16:54:26 +02:00
Miroslav Lichvar
090ec985f3 doc: clarify description of -s option 2014-08-20 16:54:26 +02:00
Miroslav Lichvar
e63bd490b0 sched: improve time jump detection
To detect forward time jumps, use a timestamp made before calling
select() instead of the first timeout in the queue. Also, if the timeout
value is modified by select() (e.g. on Linux) use it to get a more
accurate estimate of the elapsed time.
2014-08-20 16:54:26 +02:00
Miroslav Lichvar
badf97d4ba ntp: restart timer when poll interval changes on reset 2014-08-20 16:54:26 +02:00
Miroslav Lichvar
ba283e6b6e ntp: add function to restart transmit timer 2014-08-20 16:54:26 +02:00
Miroslav Lichvar
0bdac2c7b3 sched: make sure scheduler parameter change handler is first
This is needed to allow other handlers to add new timers.
2014-08-20 16:54:26 +02:00
Miroslav Lichvar
58b211d707 local: use common function to invoke parameter change handlers
This was missing in commit b69b648d.
2014-08-19 11:30:32 +02:00
Miroslav Lichvar
068ce237af reference: always update driftfile on exit
This is useful with the new fallback function of the -s option to
restore the system time at which chronyd was previously stopped.
2014-08-19 10:46:35 +02:00
Miroslav Lichvar
a5e9e5d0df rtc: set clock to mtime of driftfile when RTC preinit fails
When the RTC preinit function fails, set the system clock to the time of
the last modification of the driftfile if it's in the future. This makes
the -s option somewhat useful on systems where RTC is not supported or
missing.

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

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

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

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

Also, reconnect the socket when the local address has changed.
2014-08-05 12:57:36 +02:00
Miroslav Lichvar
17d944c333 doc: mention linuxcaps support in FAQ 2014-07-29 18:10:40 +02:00
Miroslav Lichvar
6789b5165c doc: update FAQ 2014-07-01 14:49:00 +02:00
Miroslav Lichvar
d631d7e81f doc: use iburst option in examples 2014-07-01 12:56:23 +02:00
Miroslav Lichvar
c6245dc616 doc: update NEWS 2014-06-30 17:31:39 +02:00
Miroslav Lichvar
4b36799ce1 doc: update README 2014-06-30 17:20:06 +02:00
Miroslav Lichvar
d26bb9b4eb doc: update initstepslew description 2014-06-30 17:19:40 +02:00
Miroslav Lichvar
698404b02f doc: update FAQ 2014-06-30 16:45:32 +02:00
Miroslav Lichvar
d46d7ad947 Update configuration examples 2014-06-30 14:20:32 +02:00
Miroslav Lichvar
7c6630905d sched: exit with fatal message when there is nothing to do
With cmdport 0 and port 0, it's now possible that there is no descriptor
watched or timer running, i.e. chronyd doing nothing and only waiting to
be terminated. Replace the assertion with LOG_FATAL to exit properly.
2014-06-30 12:54:04 +02:00
Miroslav Lichvar
129aa587c6 cmdmon: don't create socket when cmdport is 0 2014-06-30 12:40:18 +02:00
Miroslav Lichvar
cc1c6c94e3 makefile: remove faq.php rule 2014-06-27 17:26:54 +02:00
Miroslav Lichvar
41266cbaa0 make_release: generate FAQ from chrony.txt 2014-06-27 16:20:10 +02:00
Miroslav Lichvar
fbfd261da6 make_release: generate INSTALL from chrony.txt 2014-06-27 16:20:10 +02:00
Miroslav Lichvar
71602b8ee6 make_release: add testing mode 2014-06-27 16:06:49 +02:00
Miroslav Lichvar
14cae239f6 doc: include faq.txt in main document 2014-06-27 16:06:49 +02:00
Miroslav Lichvar
2e9e309a0d doc: update installation chapter 2014-06-27 13:25:14 +02:00
Miroslav Lichvar
3fba33d5f5 doc: drop porting guide
Most of the information provided in this section looks obsolete.
Comments in the source code should be a better source.
2014-06-27 12:17:03 +02:00
Miroslav Lichvar
77a7162361 util: print timevals for debug messages as numbers 2014-06-27 11:42:22 +02:00
Miroslav Lichvar
75efa5174c Convert disabled log messages to debug or remove them 2014-06-27 10:17:35 +02:00
Miroslav Lichvar
c62afbe77b cmdmon: remove disabled code 2014-06-26 17:19:45 +02:00
Miroslav Lichvar
a6f0688f46 keys: fix determine_hash_delay() declaration 2014-06-26 17:12:32 +02:00
Miroslav Lichvar
5762d33e38 test: require latest clknetsim revision 2014-06-25 17:35:59 +02:00
Miroslav Lichvar
9c6d1c214f ntp: don't set address for sendmsg() with connected sockets 2014-06-25 15:36:14 +02:00
Miroslav Lichvar
a5c865937f doc: update NEWS 2014-06-06 16:42:20 +02:00
Miroslav Lichvar
f48fd84d76 make_release: fix man page preparation 2014-06-06 16:42:20 +02:00
Miroslav Lichvar
a8693a21f8 Check return value of chmod() and fcntl() 2014-06-06 12:07:31 +02:00
Miroslav Lichvar
9b630a0664 reference: fix adjusting of last reference update time
The timestamp is in cooked time, it needs to be adjusted on all changes,
not only on step.
2014-06-06 11:31:43 +02:00
Miroslav Lichvar
79ac20c161 client: fix printing of negative poll in sources report 2014-06-06 10:13:25 +02:00
Miroslav Lichvar
cb74f3e7ad Update copyright years 2014-06-05 18:06:56 +02:00
Miroslav Lichvar
c4865e2cb6 doc: update acknowledgements 2014-06-05 18:06:56 +02:00
Miroslav Lichvar
20d2363fb7 reference: rework makestep
Rework makestep to cancel accumulated offset and step with the new
offset instead of accumulating new offset first, canceling all
accumulated offset and making the step.

This avoids two large frequency changes to initiate and cancel a slew
before making the step.
2014-06-05 14:46:22 +02:00
Miroslav Lichvar
64ba5a5b65 test: extend 109-makestep 2014-06-05 14:26:07 +02:00
Miroslav Lichvar
9913851413 ntp: cook SO_TIMESTAMP timestamp
This is a partial revert of 8aa9eb19c8.
With the new generic driver cooking is cheap and it should be slighly
more accurate than reusing offset correction from the scheduler
timestamps.
2014-06-04 16:58:41 +02:00
Miroslav Lichvar
e9a8503c6b reference: cook timestamp when setting reference
This is a partial revert of 8aa9eb19c8.
With the new generic driver cooking is cheap and it should be slighly
more accurate than reusing offset correction from the scheduler
timestamps.
2014-06-04 16:58:41 +02:00
Miroslav Lichvar
a02d7555c2 test: add 113-leapsecond 2014-06-04 16:58:41 +02:00
Miroslav Lichvar
779b341b61 reference: announce leap second only on last day of June and December 2014-06-04 16:58:41 +02:00
Miroslav Lichvar
a646cf7923 logging: convert rate limited messages to debug messages 2014-06-04 12:26:27 +02:00
Miroslav Lichvar
0dea8d97f4 logging: move check of enabled debugging to DEBUG_LOG macro
This avoids unnecessary calls to the logging function when debugging
messages are not logged. The cost is a slight increase in the size of
the binary (when compiled with debug messages).
2014-06-04 12:12:04 +02:00
Miroslav Lichvar
97ba9e4d47 local: round log value of clock precision
This is similar to what the reference NTP implementation does. With 1us
clock resolution that gives -20 instead of -19.
2014-06-04 12:12:04 +02:00
Miroslav Lichvar
3f3ebd3b3b ntp: update comment in get_transmit_delay() 2014-06-03 18:10:27 +02:00
Miroslav Lichvar
571669ad6c test: update packet interval check for new clknetsim 2014-06-03 18:10:27 +02:00
Miroslav Lichvar
855eb09d58 test: check also minimum outgoing packet interval 2014-06-03 18:10:27 +02:00
Miroslav Lichvar
ead3ca14a0 main: delay switching to normal mode after initstepslew
This prevents polling interval shorter than the burst interval
if some configured servers were used also for initstepslew.
2014-06-03 18:10:27 +02:00
Miroslav Lichvar
34f12c0864 test: fix packet interval check 2014-06-03 14:59:21 +02:00
Miroslav Lichvar
28876d6afa test: always write packet log 2014-06-03 11:34:53 +02:00
Miroslav Lichvar
cea68ebc6f test: extend 005-externalstep 2014-06-02 18:26:01 +02:00
Miroslav Lichvar
a33a955163 local: reset daemon after unexpected time jump
Add a new change type and use it when an unexpected time jump is
detected in the scheduler to reset reference times, offset and slewing,
NCR instances (with their polling interval), synchronization status, and
drop all sourcestats, manual, refclock and RTC samples.

This should make the recovery more graceful if the estimated jump has a
large error (e.g. select didn't timeout, or after system suspend).
2014-06-02 17:38:32 +02:00
Miroslav Lichvar
a3e60c93da sched: try to detect also forward time jumps 2014-06-02 16:48:57 +02:00
Miroslav Lichvar
44c9744d69 local: replace is_step_change parameter of change handler with enum
Prepare for a new change type that will be added later.
2014-06-02 16:46:53 +02:00
Miroslav Lichvar
b69b648d18 local: refactor invocation of parameter change handlers 2014-06-02 16:46:53 +02:00
Miroslav Lichvar
3ebebac695 ntp: reset NCR instance thoroughly when switching to offline 2014-06-02 16:46:53 +02:00
Miroslav Lichvar
13d734c8d2 sourcestats: reset SST instance thoroughly when dropping samples 2014-06-02 16:46:53 +02:00
Miroslav Lichvar
c903c5f72b sourcestats: remove forgotten declaration 2014-06-02 16:46:53 +02:00
Miroslav Lichvar
b03c7581f2 configure: fix test code to be compilable with -Werror 2014-06-02 16:46:53 +02:00
Hattink, Tjalling [FINT]
2ed9853bcc rtc: more reliable method of reading rtc for initial trim
When chrony reads in the linux rtc for the first time to trim the system
clock, it only reads it once. As it is possible that the rtc updates
itself during the read operation, the reported rtc time could be false.
To prevent this I've added a loop that reads the rtc clock twice, if the
seconds do not match retry the two read operations. If they match you
can assume the read operation was successful.

This is based on the hwclock implementation of reading the rtc clock
from the util-linux package.
2014-06-02 16:15:17 +02:00
Miroslav Lichvar
26e00ffbeb refclock: don't include average dispersion in unfiltered samples
The dispersion of refclock samples before filtering now includes only
offset correction error and precision.

This should fix a problem where locked PPS got stuck with large average
dispersion and didn't accept new samples due failing check of offset
and dispersion.
2014-05-23 16:15:28 +02:00
Miroslav Lichvar
b745b6d546 refclock: add maxdispersion option
This can be used to prevent accumulation of samples with estimated
dispersion above given limit. By default, this limit is disabled.
2014-05-23 16:15:28 +02:00
Miroslav Lichvar
e147f2f11e sys: drop frequency scaling in Linux driver
Since the kernel USER_HZ constant was introduced and the internal HZ
can't be reliably detected in user-space, the frequency scaling constant
used with older kernels is just a random guess.

Remove the scaling completely and let the closed loop compensate for the
error. To prevent thrashing between two states when the system's
frequency error is close to a multiple of USER_HZ, stick to the current
tick value if it's next to the new required tick. This is used only on
archs where USER_HZ is 100 as the frequency adjustment is limited to 500
ppm.

The linux_hz and linux_freq_scale directives are no longer supported,
but allowed by the config parser.
2014-05-23 16:15:28 +02:00
Miroslav Lichvar
14687d003d sys: set tick_update_hz to 100 by default in Linux driver
We can't reliably detect the internal kernel HZ, it may not even be
fixed (CONFIG_NO_HZ). Use a fixed value of 100.
2014-05-23 16:15:28 +02:00
Miroslav Lichvar
e8bb95ba55 sys: avoid notification of neglible dispersion on slew update 2014-05-23 16:15:28 +02:00
Miroslav Lichvar
a43810533f doc: update description of refclock options 2014-05-23 16:15:24 +02:00
Miroslav Lichvar
98bbfdf73c refclock: fix sample validation with sub-second poll 2014-05-23 12:00:16 +02:00
Miroslav Lichvar
ee53d816ce reference: fix logging of initial unsynchronized tracking entry 2014-05-23 12:00:16 +02:00
Miroslav Lichvar
e176587e96 main: initialize reference mode properly 2014-05-23 12:00:16 +02:00
Tjalling Hattink
8210be0f17 refclock: honour leap second flag in the PPS refclock
This patch fixes leap second handling for the PPS refclock. Without the
patch the PPS refclock will always report LEAP_normal. But if a locked
refclock (the SHM clock in my case) does report a leap state it should
also be taken over by the PPS refclock, otherwise chrony will still use
LEAP_normal when the PPS clock is used as reference source.

The patch will copy the leap state from the refclock. In case the PPS
clock is not specifically locked to another refclock it will take over
the leap state from the local clock.

I've tested this patch by simulating a leap second through the samples
for the SHM clock, and with the patch you will see chrony properly jump
forward or backward on the leap second. Without the patch it will not do
this and the clock becomes desynchronized and no leap state is reported
upstream to other NTP clients.

Signed-off-by: Tjalling Hattink <t.hattink@fugro.nl>
2014-05-22 13:28:46 +02:00
Miroslav Lichvar
f88a712d01 sys: use maximum timeout for offsets below minimum correction
There is no need to try to correct offsets below the specified minimum
(1 nanosecond), let the clock drift away after crossing zero offset and
avoid unnecessary updates.
2014-05-22 13:28:46 +02:00
Miroslav Lichvar
9cf78b974a conf: add option to set maximum slew rate
With the generic driver, the maxslewrate directive sets the maximum
frequency offset that the driver is allowed to use to slew the time. By
default, it's set to 83333.333 (1/12). This is identical to what Linux
fast slewing used to use.
2014-05-22 13:28:46 +02:00
Miroslav Lichvar
3e1dc801b0 conf: change default corrtimeratio to 3.0
This improves the overall frequency accuracy of the clock at a slight
cost in the time accuracy.
2014-05-21 12:08:10 +02:00
Miroslav Lichvar
cf3c7b3bd6 sys: add apply_step_offset function to generic driver
Move the generic code away from the Linux driver and keep there only
stepping by adjtimex(ADJ_SETOFFSET).
2014-05-20 17:14:33 +02:00
Miroslav Lichvar
0b7f64cb33 test: update for recent changes in Linux driver 2014-05-20 17:14:33 +02:00
Miroslav Lichvar
ec4542bbe4 sys: convert Linux driver to use generic offset functions
Strip all slewing code (adjtime(), freq locked nano PLL, fast tick
slewing) from the Linux driver and use the new generic frequency only
slewing instead. The advantages include stable clock control with very
short update intervals, good control of the slewing frequency, cheap
cooking of raw time stamps and unlimited frequency offset.
2014-05-20 17:14:33 +02:00
Miroslav Lichvar
fc235a3f16 sys: introduce generic driver
This driver is intended to complete system-specific drivers that don't
have implemented all required driver functionality. Currently, it
implements offset functions working on top of system-specific frequency
functions. Offsets are corrected by changing frequency, similarly to
fast slewing implemented in the Linux driver.
2014-05-20 16:05:42 +02:00
Miroslav Lichvar
4cf8395470 test: make 110-chronyc even more tolerant 2014-05-16 18:51:06 +02:00
Miroslav Lichvar
fd03d823f2 doc: update faq.txt 2014-05-16 18:51:06 +02:00
Miroslav Lichvar
e65fa1aa7b client: don't override hostname with -4 or -6 after -h 2014-05-16 18:51:06 +02:00
Miroslav Lichvar
3de72917c3 client: set default hostname to 127.0.0.1 instead of localhost
This is to make sure chronyd will see the remote address as 127.0.0.1
and allow access even when localhost resolves to an address of a
non-loopback interface.
2014-05-16 18:51:06 +02:00
Miroslav Lichvar
b3b2f67d2f client: enable IP_RECVERR socket option
This is useful to get ECONNREFUSED when the host replies with ICMP port
unreachable message and avoid having to wait for timeout.
2014-05-16 18:51:06 +02:00
Miroslav Lichvar
c2dc25e062 sys: remove unused static variables in Linux driver 2014-05-16 18:50:58 +02:00
Miroslav Lichvar
ad9c360845 doc: update for separate client sockets 2014-04-30 18:48:43 +02:00
Miroslav Lichvar
a65686e83f doc: update chronyd -r and chronyc -h descriptions 2014-04-30 18:48:43 +02:00
Miroslav Lichvar
fe35de6931 main: switch errors in initialization to fatal errors 2014-04-30 18:47:53 +02:00
Miroslav Lichvar
3f1aea2f53 test: require latest clknetsim
This is needed for async name resolving and dropping root privileges.
2014-04-29 15:23:11 +02:00
Miroslav Lichvar
0c542dcd3d client: shorten default timeout with localhost and async resolving
When chronyd is compiled with asynchronous name resolving, it should
always respond quickly. Shorten the default chronyc timeout for
localhost.
2014-04-29 15:23:11 +02:00
Miroslav Lichvar
5483567190 nameserv: add asynchronous resolving with POSIX threads
Run getaddrinfo()/gethostbyname() in separate thread to avoid blocking.
Only one resolving thread is running at one time, so this should work
also on systems where the functions are not thread-safe.
2014-04-29 15:19:06 +02:00
Miroslav Lichvar
d243f1f8fe configure: check if getaddrinfo() is available
This allows disabling IPv6 support and keeping getaddrinfo().
2014-04-29 12:43:03 +02:00
Miroslav Lichvar
9b137b2e37 ntp: start resolving only from NSR_ResolveSources
Also, use macros to define the minimum and maximum resolving interval.
2014-04-29 12:43:03 +02:00
Miroslav Lichvar
6ee357d230 ntp: use async name resolving for NTP sources
Use the new asynchronous call to resolve addresses of NTP servers
configured by the server/peer directives. Introduce a callback to be
notified when the first resolving attempt ends to correctly finish
chronyd initialization (dumpfile reload and reference mode end).
2014-04-29 12:43:03 +02:00
Miroslav Lichvar
779e40ed66 ntp: delay initial transmission until first resolving ends
This will be needed to prevent loading of dump files after sources have
already accumulated samples and possibly reference was already updated
when async resolving of sources is implemented.
2014-04-29 12:42:45 +02:00
Miroslav Lichvar
be3439fef1 sourcestats: assert dump file is loaded with no accumulated samples 2014-04-29 12:07:38 +02:00
Miroslav Lichvar
ed96b4d49d nameserv: prepare for asynchronous resolving
Introduce a new function with callback to resolve names to IP addresses
asynchronously. For now, use a blocking wrapper around DNS_Name2IPAddress.
2014-04-29 12:07:38 +02:00
Miroslav Lichvar
5ca8aa7840 configure: sed Makefile with MYCPPFLAGS 2014-04-29 12:07:38 +02:00
Miroslav Lichvar
1eede1bc08 configure: replace unnecessary variables in Makefile 2014-04-29 12:07:38 +02:00
Miroslav Lichvar
cc86461d9b refclock: remove duplicated declaration 2014-04-29 12:07:38 +02:00
Miroslav Lichvar
29c5ca9091 cmdmon: fix doffset command with negative values on 64-bit systems 2014-04-28 14:12:05 +02:00
Miroslav Lichvar
86fbcdc62b reference: negate offset printed in maxchange log message
This makes it consistent with other log messages.
2014-04-11 16:09:43 +02:00
Miroslav Lichvar
e82220974e makefile: add dependency to check target 2014-04-10 18:22:34 +02:00
Miroslav Lichvar
46951b8598 main: setup access restrictions before initstepslew 2014-04-10 18:22:09 +02:00
Miroslav Lichvar
08faca03b7 ntp: close client socket when offline 2014-04-10 18:02:29 +02:00
Miroslav Lichvar
3217421797 ntp: close only client socket when destroying NCR instance 2014-04-10 17:50:24 +02:00
Miroslav Lichvar
7fa22d4c25 sources: ignore inactive sources in special mode ending 2014-04-10 17:50:24 +02:00
Miroslav Lichvar
8671002bd7 sources: add flag that source is active
When source is set as active, it's receiving reachability updates (e.g.
offline NTP sources are not active).

Also add function to count active sources.
2014-04-10 17:48:58 +02:00
Miroslav Lichvar
bc6b40568d ntp: reduce burst timeout to 2.0
With the new special mode ending it can be now equal to the burst
polling interval.
2014-04-10 17:16:30 +02:00
Miroslav Lichvar
3888b9dcec sources: rework special mode ending with unreachable sources
Instead of giving up when a source has 7 reach updates, continue as long
as at least one source has fewer than 7 updates and can still have 3
samples to be selectable in that number of updates.

When no sources are responding, it will give up sooner.
2014-04-10 17:16:13 +02:00
Miroslav Lichvar
ae104b5c28 regress: make minimum number of samples for regression public 2014-04-10 17:15:13 +02:00
Miroslav Lichvar
5cb7e6c9c3 sched: fix main loop to allow timeout handlers modify fd set or quit
With special reference update modes, the timeout handlers may add or
remove file descriptors from the read fd set, so it needs to be copied
for select() call after they are dispatched. Also, they can now request
quit, so the exit flag needs to be checked before select() to avoid
hanging.
2014-04-10 11:47:43 +02:00
Miroslav Lichvar
ff31702f74 configure: add option to set default user
The default user is root by default, which disables root dropping by
default. The user directive or the -u option can still be used to set
the user.
2014-04-09 16:30:06 +02:00
Miroslav Lichvar
3edd3fe5a4 main: support configuration commands on command line
If there are extra arguments on the chronyd command line, they will be
parsed as lines in a configuration file and the normal configuration file
will be ignored.
2014-04-09 15:16:35 +02:00
Miroslav Lichvar
4f3fb95981 conf: allow NULL as filename 2014-04-09 12:56:11 +02:00
Miroslav Lichvar
7c7ab95e2e conf: split line parsing from CNF_ReadFile 2014-04-09 12:36:13 +02:00
Miroslav Lichvar
70feea48f8 main: add -q/-Q options to set clock/print offset once and exit 2014-04-09 12:15:07 +02:00
Miroslav Lichvar
c546c48d0d reference: add UpdateOnce and PrintOnce modes 2014-04-09 12:14:47 +02:00
Miroslav Lichvar
0baf00e1c0 logging: print warning message when not compiled with debug support 2014-04-09 12:09:25 +02:00
Miroslav Lichvar
788e7fcd89 logging: set debug level instead of on/off
Prefix messages written to terminal with filename, line and function
name only with debug level 2 and higher.
2014-04-09 12:09:23 +02:00
Miroslav Lichvar
7c45b1d2a3 logging: update format of messages written to terminal
Move the time stamp to start of the line and print full date in ISO 8601
format.
2014-04-09 12:08:59 +02:00
Miroslav Lichvar
93b66ac141 reference: exit with non-zero code when maxchange limit is reached
Use ending of normal mode to signal a failure.
2014-04-09 09:59:58 +02:00
Miroslav Lichvar
610284dcc3 sources: log selection messages only in normal reference update mode
We don't want to see source selection messages when initstepslew is
running.
2014-04-09 09:59:58 +02:00
Miroslav Lichvar
60d8586b6d ntp: reduce burst timeout to 2.5 seconds
This reduces the maximum time initstepslew can take.
2014-04-09 09:59:58 +02:00
Miroslav Lichvar
70928dba52 ntp: set maximum number of iburst samples to size of reach register
Explicitly set the number of iburst samples to the size of the register
to make sure there are at least 7 reachability updates and the
initstepslew mode can be ended.
2014-04-09 09:59:57 +02:00
Miroslav Lichvar
7fda9c6723 ntp: drop initstepslew NTP implementation
The initstepslew code has its own minimal NTP implementation. Drop the
code, add a new initstepslew mode to the reference updating code and
use regular NTP sources with iburst flag for initstepslew addresses
instead. When an update is made or a source is found unreachable, log a
message, remove the initstepslew sources and switch to normal mode.

This reduces code duplication and makes initstepslew use features
implemented only in the main code like source combining or SO_TIMESTAMP
support.
2014-04-09 09:54:40 +02:00
Miroslav Lichvar
4932f9d077 sources: replace beginning flag with size of reachability register
This will allow to detect sources that are not reachable on start.
2014-04-08 17:00:47 +02:00
Miroslav Lichvar
0094128ca6 sources: split source selection from sample accumulation
This will allow postponing source selection and reference update, which
could be useful in burst modes.
2014-04-08 17:00:47 +02:00
Miroslav Lichvar
de5178575f git: update .gitignore 2014-04-08 17:00:47 +02:00
Miroslav Lichvar
9eac078c18 test: add missing run script 2014-04-08 17:00:47 +02:00
Miroslav Lichvar
05c5445fe2 conf: add bindacqaddress directive for client sockets 2014-04-03 15:47:32 +02:00
Miroslav Lichvar
f9d8b6f99e ntp: set only necessary socket options on client sockets 2014-04-03 13:36:25 +02:00
Miroslav Lichvar
597a37d66e test: add 112-port 2014-03-26 12:24:36 +01:00
Miroslav Lichvar
73e4986866 ntp: fix comment on NCR_ProcessUnknown 2014-03-26 11:24:25 +01:00
Miroslav Lichvar
91e74c704b ntp: accept packets from unknown sources only from server sockets 2014-03-26 11:18:18 +01:00
Miroslav Lichvar
727bf195d1 test: update for latest clknetsim
Latest clknetsim now allows source and destination port numbers to
differ. This fixes the tests to work with the recent changes that added
client NTP sockets.
2014-03-25 17:33:55 +01:00
Miroslav Lichvar
b13836e9cc ntp: don't create server sockets if port is configured to 0 2014-03-25 15:27:18 +01:00
Miroslav Lichvar
cf12d72f21 ntp: use separate connected sockets for each server
If acquisitionport is set to 0 (default), create and connect a new
socket for each server instead of using one socket per address family
for all servers.
2014-03-25 15:27:18 +01:00
Miroslav Lichvar
5c2bbaca3b ntp: use separate client sockets
Use separate sockets for NTP server or peer and client packets. The port
number is configured by the acquisitionport directive. With the default
value of 0 the port is assigned randomly by the kernel. It can be equal
to the value configured by the port directive to use the server sockets
for all packets as before.
2014-03-25 15:25:23 +01:00
Miroslav Lichvar
b717904f9e ntp: don't try to bind acquire socket if port is equal to ntp port 2014-03-25 15:24:38 +01:00
Miroslav Lichvar
f2c4ab09a8 ntp: check if packet was received by right socket 2014-03-25 15:24:38 +01:00
Miroslav Lichvar
9a657cd4a3 ntp: store socket in NTP instance
This is preparation for separate client sockets.
2014-03-25 15:22:59 +01:00
Miroslav Lichvar
308de81221 ntp: split local_ip_addr from NTP_Remote_Address struct 2014-03-25 11:34:35 +01:00
Miroslav Lichvar
6823109cfb ntp: set invalid socket fd by macro 2014-03-25 11:34:31 +01:00
Miroslav Lichvar
a02149cf65 doc: improve commandkey and keyfile descriptions 2014-03-21 15:49:00 +01:00
Miroslav Lichvar
7aa4bbf621 ntp: set minpoll from received KoD RATE at most to 10
Limit changing minpoll to a reasonable maximum in case the server is
broken or temporarily misconfigured.
2014-03-21 15:32:14 +01:00
Miroslav Lichvar
5afddad0d2 ntp: print warning when source is added with unknown key 2014-03-21 14:36:51 +01:00
Miroslav Lichvar
0380cf0c76 ntp: reset negative minpoll or maxpoll to default values 2014-03-21 13:25:14 +01:00
Miroslav Lichvar
6c2a1e62e0 cmdparse: don't allow NTP key ID of 0
Key number 0 is used as inactive key, prevent the user from
inadvertently not using authentication.
2014-03-21 13:20:37 +01:00
Miroslav Lichvar
6560628209 test: add 111-knownclient 2014-03-21 13:20:36 +01:00
Miroslav Lichvar
3cc81376a6 test: add port number check 2014-03-21 13:20:36 +01:00
Miroslav Lichvar
8d02e5f680 ntp: make use of NCR_ProcessUnknown in NCR_ProcessKnown
After recent changes the code in NCR_ProcessKnown is now identical and
can be replaced with NCR_ProcessUnknown call.
2014-03-21 13:20:34 +01:00
Miroslav Lichvar
f9e2213afd ntp: don't store tx time stamp when replying to known source 2014-03-21 13:20:31 +01:00
Miroslav Lichvar
8b362ba3e7 ntp: don't reply to known source if missing key or invalid auth
This is now similar to replying to unknown sources.
2014-03-21 13:20:29 +01:00
Miroslav Lichvar
eecec8fffa test: extend 105-ntpauth 2014-03-21 13:20:29 +01:00
Miroslav Lichvar
a26058d425 ntp: don't send requests with unknown key
There is no point in sending a request if the configured key is missing.
A reply would be ignored anyway.
2014-03-21 13:20:27 +01:00
Miroslav Lichvar
c14b81f3a9 ntp: remove unnecessary KEY_KeyKnown calls 2014-03-21 13:20:25 +01:00
Miroslav Lichvar
0059a43254 keys: don't cache position for unknown keys 2014-03-21 13:20:24 +01:00
Miroslav Lichvar
7dd3cc354d client: print positive signed freq and offset values with sign 2014-03-21 13:20:24 +01:00
Miroslav Lichvar
ce34aa0763 test: make 110-chronyc more tolerant 2014-03-21 13:20:24 +01:00
Miroslav Lichvar
7a512ad9c3 tempcomp: print warning message on error 2014-03-21 13:20:24 +01:00
Miroslav Lichvar
0a56c0e8c1 tempcomp: use macro to set maximum allowed compensation 2014-03-21 13:20:24 +01:00
Miroslav Lichvar
0b71504ee9 sourcestats: fix signedness in scanf format 2014-03-21 13:20:24 +01:00
Miroslav Lichvar
9479c6451e makefile: improve check rule 2014-03-21 13:20:20 +01:00
Miroslav Lichvar
115e83f3aa Add simulation tests
Use clknetsim to run multiple chronyd instances with simulated clocks
and network. It allows fast and reproducible testing, without real
network.

Included are several tests of performance in different clock/network
conditions, chronyd options, NTP authentication, chronyc, and past bug
fixes.
2014-02-27 18:34:52 +01:00
Miroslav Lichvar
ea526b96dd configure: suppress pkg-config errors 2014-02-05 08:53:15 +01:00
Miroslav Lichvar
726cf84e19 Check array index before reading 2014-02-04 16:02:21 +01:00
Miroslav Lichvar
dc8a46363f Merge branch '1.29-security' 2014-01-31 17:06:08 +01:00
Miroslav Lichvar
916ca7ab86 make_release: set owner and group in released tarball to root 2014-01-31 13:37:55 +01:00
Miroslav Lichvar
be036ed58a make_release: remove config.log and config.h 2014-01-31 13:37:52 +01:00
Miroslav Lichvar
2afdd4544d Update NEWS 2014-01-31 13:12:59 +01:00
Miroslav Lichvar
c4e61835d3 Update faq.txt 2014-01-30 15:59:45 +01:00
Miroslav Lichvar
e15ce69d08 Send cmdmon error replies only to allowed hosts
The status codes STT_BADPKTVERSION, STT_BADPKTLENGTH, STT_NOHOSTACCESS
were sent even to hosts that were not allowed by cmdallow. Deprecate
STT_NOHOSTACCESS and ignore packets from hosts not allowed by cmdallow
completely.
2014-01-30 15:59:45 +01:00
Miroslav Lichvar
d537ed11fd Support previous protocol version in chronyc
This adds compatibility with chronyd using the previous protocol version
(chrony versions 1.27, 1.28, 1.29).
2014-01-30 15:59:45 +01:00
Miroslav Lichvar
dba458d50c Add padding to cmdmon requests to prevent amplification attack
To prevent an attacker using chronyd in an amplification attack, change
the protocol to include padding in request packets so that the largest
possible reply is not larger than the request. Request packets that
don't include this padding are ignored as invalid.

This is an incompatible change in the protocol. Clients from chrony
1.27, 1.28 and 1.29 will receive NULL reply with STT_BADPKTVERSION and
print "Protocol version mismatch". Clients from 1.26 and older will not
receive a reply as it would be larger than the request if it was padded
to be compatible with their protocol.
2014-01-30 15:59:45 +01:00
Miroslav Lichvar
3e23430926 Set maximum number of samples in manual list reply to 16
In chronyd the maximum number of manual samples is 16, so there is no
need to keep room for 32 samples in the command reply. This limits the
maximum assumed size of the reply packet.
2014-01-30 15:59:45 +01:00
Miroslav Lichvar
3f507b782c Replace number and total fields in cmdmon reply packet with padding
They were not used for anything and there is no plan to change that.
2014-01-24 16:53:32 +01:00
Miroslav Lichvar
2fc3525fdf Don't read uninitialized memory in client packet length check
Before calling PKL_ReplyLength() check that the packet has full header.
This didn't change the outcome of the test if the packet was shorter as
the invalid result from PKL_ReplyLength() was either larger than length
of the packet or smaller than header length, failing the length check in
both cases.
2014-01-24 16:53:32 +01:00
Miroslav Lichvar
0f3e464202 Remove superfluous code in read_from_cmd_socket() 2014-01-24 16:53:32 +01:00
Miroslav Lichvar
925d7119ec Fix writing of drift and RTC files
Without sequence points the driftfile and RTC file could be closed
before new values were written.
2014-01-21 18:23:12 +01:00
Miroslav Lichvar
f456cd57b9 Fix selecting of sources with prefer option
List of selectable sources that is used in combining was trimmed to
sources with prefer option, but scoring algorithm considered all
selectable sources. When a source without prefer was selected and
no source was combined, it caused assertion failure.
2014-01-21 17:18:48 +01:00
Miroslav Lichvar
ea58500cef Remove superfluous code in SRC_SelectSource 2014-01-21 16:41:00 +01:00
Miroslav Lichvar
4048b200ed Fix error message when chronyc can't open keyfile 2014-01-21 14:51:32 +01:00
Miroslav Lichvar
54211f0f6e Update comment on setting poll in reply packet 2014-01-17 18:10:32 +01:00
Miroslav Lichvar
4b5f465026 Don't allow maxpoll to be set shorter than minpoll 2014-01-17 17:37:07 +01:00
Miroslav Lichvar
7efd1151cb Convert linux kernel info messages to debug 2014-01-17 17:30:06 +01:00
Miroslav Lichvar
19dbe52930 Update linux_freq_scale and linux_hz documentation 2014-01-10 15:56:53 +01:00
Miroslav Lichvar
2a981b7d39 Print error message on invalid syntax with all chronyc commands 2014-01-10 11:14:39 +01:00
Miroslav Lichvar
d34ebdb431 Simplify expression used in frequency accumulation 2014-01-09 18:31:35 +01:00
Miroslav Lichvar
60d0fa2993 Fix frequency accumulation again
This is a revert of commit 99d18abf updated for later changes. It seems
in that commit the calculation was changed to match the reversed dfreq
added in 1a7415a6, which itself was calculated incorrectly. Fix the
calculation of updated frequency and matching dfreq.
2014-01-09 18:30:14 +01:00
Miroslav Lichvar
8545ba733a Convert disabled log message in rtc_linux.c to DEBUG_LOG 2014-01-09 18:23:37 +01:00
Miroslav Lichvar
04c8a8c75d Update documentation on trimrtc command 2013-12-12 17:11:11 +01:00
Miroslav Lichvar
b7ed44f113 Improve description of refclock delay option 2013-12-11 17:59:14 +01:00
Miroslav Lichvar
46a39716b6 Fix default device in rtcdevice description 2013-12-11 11:25:00 +01:00
Miroslav Lichvar
e77b0070af Add option to read RTC LOCAL/UTC setting from hwclock's adjtime file 2013-12-11 11:22:04 +01:00
Miroslav Lichvar
3c5cf81e32 Replace /sbin/clock with /sbin/hwclock in documentation and comments 2013-12-10 17:54:05 +01:00
Miroslav Lichvar
be14dbffef Make naming of RTC config functions consistent 2013-12-10 17:54:05 +01:00
Miroslav Lichvar
b4f6a0f94a Fix ordering of sections in documentation 2013-11-29 17:34:38 +01:00
Miroslav Lichvar
c15acff39a Make section descriptions consistent in documentation 2013-11-29 17:34:32 +01:00
Miroslav Lichvar
ed0ac6e3f6 Write fatal messages also to stderr when started with -n 2013-11-28 18:17:50 +01:00
Miroslav Lichvar
6cc9c4940c Don't try to write to parent logging fd when closed 2013-11-28 18:11:37 +01:00
Miroslav Lichvar
0e8b27556d Merge config parsing functions for common data types 2013-11-28 17:33:20 +01:00
Miroslav Lichvar
162c6a49b5 Add option to trim RTC automatically 2013-11-27 17:35:00 +01:00
Miroslav Lichvar
61dbdd80b9 Fix REF_GetOurStratum description 2013-11-27 16:28:09 +01:00
Miroslav Lichvar
8df1bedb1b Remove forgotten macros 2013-11-27 16:11:19 +01:00
Miroslav Lichvar
b55e914273 Use N_SAMPLES_PER_REGRESSION macro in rtc_linux module 2013-11-27 15:43:17 +01:00
Miroslav Lichvar
1c3aff37de Convert TRACEON LOG messages to DEBUG_LOG 2013-11-27 14:35:41 +01:00
Miroslav Lichvar
4bbc5520b8 Add support for debug messages
Add new DEBUG_LOG macro for debug messages. The messages are enabled
when compiled with --enable-debug and they are printed when the -d
option is used twice.
2013-11-27 14:35:38 +01:00
Miroslav Lichvar
0731cd6950 Fix log messages 2013-11-26 18:41:51 +01:00
Miroslav Lichvar
f88e96599c Set printf format attribute for logging functions with gcc 2013-11-26 18:41:49 +01:00
Miroslav Lichvar
cd7bfa2510 Refactor logging
- merge LOG_Line_Function, LOG_Fatal_Function and LOG_Position
- use C99 variadic macros for LOG and LOG_FATAL
2013-11-26 18:40:43 +01:00
Miroslav Lichvar
ea418b2e18 Update see also in man pages 2013-11-26 13:34:12 +01:00
Miroslav Lichvar
c00d93a897 Add refclock trace messages 2013-11-26 11:56:53 +01:00
Miroslav Lichvar
bc361c48a0 Enable refclock error messages 2013-11-26 11:44:06 +01:00
Miroslav Lichvar
1f39169be3 Fix stratum with non-PPS SOCK refclock and local stratum 2013-11-25 17:58:35 +01:00
Miroslav Lichvar
030833087d Append -lcap to EXTRA_LIBS in configure 2013-11-15 13:22:45 +01:00
Miroslav Lichvar
c38dbcc6b5 Link with -lrt for clock_gettime() if needed 2013-11-15 13:22:43 +01:00
Miroslav Lichvar
ba1d548cc8 Fix compilation of PHC driver on systems without PTP_SYS_OFFSET 2013-11-15 10:08:47 +01:00
Miroslav Lichvar
7261d11bb0 Add assert for parameter m in RGR_FindBestRegression() 2013-10-10 16:37:40 +02:00
Miroslav Lichvar
f38872eab3 Fix regression validity check in handle_relock_after_trim() 2013-10-07 17:50:27 +02:00
Miroslav Lichvar
1939aae70e Fix id printed in duplicate key warning 2013-10-07 17:50:27 +02:00
Miroslav Lichvar
3f85d1dcc1 Remove unused code in manual.c 2013-10-07 17:50:27 +02:00
Miroslav Lichvar
922e2fe23b Fix Clang static analyzer warnings about never read values 2013-10-07 17:50:27 +02:00
Paul Menzel
d5a9c1535e rtc_linux.c: Remove useless assignment error = -1;
The Clang static analyzer scan-build from Debian clang version 3.4-1
found the following unneeded assignment.

        rtc_linux.c:756:5: warning: Value stored to 'error' is never read
            error = 1;
            ^       ~

Indeed, if in that if branch, the function returns without ever looking
at the variable `error`. So remove the line.
2013-10-07 16:42:03 +02:00
Miroslav Lichvar
169eee6792 Add dependency on chrony.txt to install target 2013-09-12 14:22:32 +02:00
Miroslav Lichvar
9c398051bb Add URLs to documentation for gpsd, radioclk and linuxpps 2013-08-14 19:02:49 +02:00
Miroslav Lichvar
1d289787b6 Add PHC refclock driver
Implement a driver which allows using PTP hardware clock (PHC) as a
reference clock. It uses the PTP_SYS_OFFSET ioctl or clock_gettime()
to measure the offset between the PTP clock and the system clock. Ten
readings are made for every driver poll and the fastest one is returned.

As PHCs are typically kept in TAI instead of UTC, it's necessary to set
the TAI/UTC offset manually by the offset option. This could be improved
by obtaining the offset automatically from the right/UTC timezone.
2013-08-14 18:52:23 +02:00
Miroslav Lichvar
b5658f4d9c Update NEWS 2013-08-08 15:58:07 +02:00
Miroslav Lichvar
ad58baa13b Drop support for SUBNETS_ACCESSED and CLIENT_ACCESSES commands
Support for the SUBNETS_ACCESSED and CLIENT_ACCESSES commands was
enabled in chronyd, but in chronyc it was always disabled and the
CLIENT_ACCESSES_BY_INDEX command was used instead. As there is no plan
to enable it in the future, remove the support completely.
2013-08-07 14:47:56 +02:00
Miroslav Lichvar
c6fdeeb6bb Don't send uninitialized data in command replies
The RPY_SUBNETS_ACCESSED and RPY_CLIENT_ACCESSES command replies can
contain uninitalized data from stack when the client logging is disabled
or a bad subnet is requested. These commands were never used by chronyc
and they require the client to be authenticated since version 1.25.
2013-08-07 14:46:16 +02:00
Miroslav Lichvar
7712455d9a Fix buffer overflow when processing crafted command packets
When the length of the REQ_SUBNETS_ACCESSED, REQ_CLIENT_ACCESSES
command requests and the RPY_SUBNETS_ACCESSED, RPY_CLIENT_ACCESSES,
RPY_CLIENT_ACCESSES_BY_INDEX, RPY_MANUAL_LIST command replies is
calculated, the number of items stored in the packet is not validated.

A crafted command request/reply can be used to crash the server/client.
Only clients allowed by cmdallow (by default only localhost) can crash
the server.

With chrony versions 1.25 and 1.26 this bug has a smaller security
impact as the server requires the clients to be authenticated in order
to process the subnet and client accesses commands. In 1.27 and 1.28,
however, the invalid calculated length is included also in the
authentication check which may cause another crash.
2013-08-07 13:39:02 +02:00
Miroslav Lichvar
a9a5f98406 Update chrony.conf.example2 2013-08-02 15:43:44 +02:00
Miroslav Lichvar
9ac8f64d89 Don't mention pre 2.2 Linux kernels in documentation 2013-08-02 15:43:44 +02:00
Miroslav Lichvar
0da5cf9163 Update NEWS 2013-07-17 16:19:45 +02:00
Miroslav Lichvar
f6a39d75a7 Treat address bind errors as non-fatal 2013-07-17 13:45:36 +02:00
Miroslav Lichvar
25aa9f5b42 Update chrony.spec.sample 2013-07-01 19:00:06 +02:00
Miroslav Lichvar
829b3adac3 Update copyright in chronyc GPL string 2013-07-01 17:53:27 +02:00
Miroslav Lichvar
4847a3a259 Update NEWS 2013-06-21 16:09:20 +02:00
Miroslav Lichvar
551541d9c8 Update example config files more 2013-06-21 16:09:20 +02:00
Miroslav Lichvar
f996f4c9fb Document port directive set to 0 as random port 2013-06-21 16:09:20 +02:00
Miroslav Lichvar
ac78ad60f3 Use texi2html only if it's available 2013-06-21 16:09:20 +02:00
Miroslav Lichvar
42d7cf8922 Don't ship faqgen.pl 2013-06-21 16:09:20 +02:00
Miroslav Lichvar
e811ba7b4c Fix possible leaks of temporary file names 2013-06-21 16:09:20 +02:00
Miroslav Lichvar
cb464cac4d Fix memset calls 2013-06-21 14:39:33 +02:00
Miroslav Lichvar
fa409ddc8f Update documentation 2013-06-20 18:00:32 +02:00
Miroslav Lichvar
821226e473 Update example config files 2013-06-20 17:23:32 +02:00
Miroslav Lichvar
0e298bedf6 Create /etc and /var/lib/chrony on installation 2013-06-20 14:47:06 +02:00
Miroslav Lichvar
aa76760268 Avoid sentences written in first person 2013-06-20 13:24:24 +02:00
Miroslav Lichvar
8bf87bbfde Update comparison with ntpd 2013-06-20 13:24:24 +02:00
Miroslav Lichvar
38e889c85c Remove fixed problems from FAQ 2013-06-19 14:40:20 +02:00
Miroslav Lichvar
d5b737cce8 Update copyright years 2013-06-19 12:50:26 +02:00
Miroslav Lichvar
6ba764b5be Don't call finalise functions on fatal error
Also, return with non-zero exit code.
2013-06-19 12:28:00 +02:00
Miroslav Lichvar
707b857b68 Combine source frequencies by skew 2013-06-19 12:11:27 +02:00
Miroslav Lichvar
f8d609fee5 Add minimum skew limit to sourcestats 2013-06-19 10:22:49 +02:00
Miroslav Lichvar
01f797ac05 Fix printing of outlier status 2013-06-18 16:13:17 +02:00
Miroslav Lichvar
6fa11a853a Add more entries to tracking log
Add number of combined sources, remaining offset correction from
previous update and estimated stddev of the combined offset.
2013-06-17 18:32:16 +02:00
Miroslav Lichvar
9c78ad708b Fix maxchange offset check 2013-06-17 18:32:16 +02:00
Miroslav Lichvar
57f8160d6c Call maybe_log_offset and update_leap_status after adjusting clock 2013-06-17 18:32:16 +02:00
Miroslav Lichvar
8d80ce444f Fix spelling 2013-06-17 18:26:48 +02:00
Miroslav Lichvar
95c3acf67e Log manual entries with MANU refid in tracking log 2013-06-17 18:26:48 +02:00
Miroslav Lichvar
561f7a66dd Fix log message to not include newline 2013-06-17 18:26:48 +02:00
Miroslav Lichvar
0193688671 Fix printing of negative offset with settime command 2013-06-17 18:26:48 +02:00
Miroslav Lichvar
6d7605a3d0 Reuse REF_SetReference code with manual reference 2013-06-17 18:26:47 +02:00
Miroslav Lichvar
e0171f6e96 Write freq and skew to drift file with six decimal places 2013-06-14 19:24:03 +02:00
Miroslav Lichvar
4ef1c6f2c8 Use fscanf to read drift file 2013-06-14 19:24:03 +02:00
Miroslav Lichvar
f7e2d7c2ec Modify minimum skew checking 2013-06-14 16:27:15 +02:00
Miroslav Lichvar
3d1be1cd75 Replace bzero with memset 2013-06-14 13:48:16 +02:00
Miroslav Lichvar
2d509eb8bd Remove changelog from conf.c 2013-06-14 13:44:15 +02:00
Miroslav Lichvar
6ca73bf670 Cleanup including of system headers 2013-06-14 13:41:16 +02:00
Miroslav Lichvar
f7802f0111 Don't abort on EINTR select errors 2013-06-14 12:37:24 +02:00
Miroslav Lichvar
2f3ef235a1 Replace LOG_FATAL call with assert in SCH_MailLoop 2013-06-14 12:35:51 +02:00
Miroslav Lichvar
1ad22e9a02 Don't apply outlyer penalty at beginning
Wait until the reach register is full to allow marking a source as
outlyer for 32 updates. This makes start nicer with iburst.
2013-06-13 18:20:53 +02:00
Miroslav Lichvar
6d2fb9f782 Add minsamples and maxsamples directives
Allow configuration of the maximum and minimum number of samples per
source.
2013-06-13 16:23:32 +02:00
Miroslav Lichvar
22e5ed44c2 Modify SST_GetSelectionData to return only necessary data 2013-06-12 16:06:33 +02:00
Miroslav Lichvar
9666831818 Use UTI_DiffTimevalsToDouble to calculate theta 2013-06-12 15:30:28 +02:00
Miroslav Lichvar
ff8e04f9ba Fix fabs use on delay 2013-06-12 15:30:28 +02:00
Miroslav Lichvar
52272f4dc5 Limit sources included in combining
Combine only sources whose distance is shorter than distance of the
selected source multiplied by the value of combinelimit and their
estimated frequencies are close to the frequency of the selected source.
Add outlyer status for sources which are selectable, but not included in
the combining. The status is displayed as '-' in the chronyc sources
output.
2013-06-12 10:25:46 +02:00
Miroslav Lichvar
18a66a2ba8 Resurrect source combining
This is based on the code that was removed in CVS revision 1.3 of
sources.c. The weighting is simplified and the code is moved to a new
function.
2013-06-11 16:36:50 +02:00
Miroslav Lichvar
8aa9eb19c8 Remove unnecessary adjtimex calls 2013-06-06 19:38:36 +02:00
Miroslav Lichvar
62027f1b47 Fix rounding in UTI_AddDoubleToTimeval with negative increments 2013-06-06 16:30:37 +02:00
Miroslav Lichvar
41805d572f Adjust last_select_ts on slew 2013-06-06 16:29:50 +02:00
Miroslav Lichvar
58f768928a Rename SCH_GetFileReadyTime() and extend it to return raw time 2013-06-05 18:07:05 +02:00
Miroslav Lichvar
0074135097 Drop duplicated int64_to_timeval() 2013-06-05 13:11:53 +02:00
Miroslav Lichvar
8eb7ce8581 Fix UTI_DoubleToInt32 to check for overflow 2013-06-05 13:05:54 +02:00
Miroslav Lichvar
2ceb3c89ca Move NTP_int32 conversion functions to util.c 2013-06-05 12:49:47 +02:00
Miroslav Lichvar
d46e2a69a1 Add --enable-trace to configure 2013-06-05 12:22:07 +02:00
Miroslav Lichvar
20f9454be3 Fix configure help message 2013-06-05 11:58:13 +02:00
Miroslav Lichvar
8092366897 Abort on parse errors in refclock directive 2013-06-05 11:48:48 +02:00
Miroslav Lichvar
066254b6c8 Fix burst command with specified address
This was broken in commit 0f8def4ca4.
2013-06-05 10:39:58 +02:00
Miroslav Lichvar
79811bf3e2 Allow hostnames in offline, online and burst commands 2013-06-05 10:39:58 +02:00
Miroslav Lichvar
32bf32e7d5 Don't use uninitialized value in receive_packet() 2013-06-05 09:56:37 +02:00
Miroslav Lichvar
df968ca47c Fix stratum setting when source with non-minimum stratum is selected 2013-06-05 09:55:00 +02:00
Miroslav Lichvar
cce7a5f15e Improve peer polling in symmetric mode
If the remote stratum is higher than ours, try to lock on the peer's
polling to minimize our response time by slightly extending our delay or
waiting for the peer to catch up with us as the random part in the
actual interval is reduced. If the remote stratum is equal to ours, try
to interleave evenly with the peer.
2013-06-05 09:32:20 +02:00
Miroslav Lichvar
288043c13b Save remote poll only with valid packets 2013-06-04 15:43:59 +02:00
Miroslav Lichvar
78ae4ebfaa Fix peer polling with shorter remote poll
If the remote peer uses a polling interval shorter than the local
minimum, the local peer will be unable to send any packets as the
timeout will be updated on every received valid packet and will never
expire.

Modify the delay calculation to aim at poll interval away since the last
transmit.

Also, share the delay calculation code with transmit_timeout().
2013-06-04 12:52:49 +02:00
Miroslav Lichvar
cf700a0084 Requeue transmit timeout only with valid packets 2013-06-04 12:45:47 +02:00
Miroslav Lichvar
60a25f6e71 Ignore packets from offline sources
Rework the logic in transmit_timeout() to change the online status on
the following timeout to allow ignoring packets from offline sources.
2013-06-03 18:57:55 +02:00
Miroslav Lichvar
3eff836b2e Set stratum from last sample instead of best 2013-06-03 18:57:54 +02:00
Miroslav Lichvar
2b9fe764d5 Drop unused SST_GetReferenceData() 2013-06-03 16:03:07 +02:00
Miroslav Lichvar
030e3b2dab Make receive_packet() more readable 2013-06-03 16:03:07 +02:00
Miroslav Lichvar
5079f6bbff In burst count only accumulated samples as good 2013-06-03 16:03:07 +02:00
Miroslav Lichvar
afceb9d24e Slew only non-zero local timestamps in ntp core 2013-06-03 16:03:07 +02:00
Miroslav Lichvar
a2656a20bc Fix poll timeout with symmetric peer and poll 0 2013-06-03 16:03:05 +02:00
Miroslav Lichvar
359d444343 Remove unncessary return statements 2013-05-21 15:08:34 +02:00
Miroslav Lichvar
d510154ba2 Add recommendation on password security to keyfile description 2013-05-21 14:02:45 +02:00
Miroslav Lichvar
1c901b82dc Add option to generate command key on start
With generatecommandkey directive, if no command key is found in the key
file on start, one will be generated automatically from /dev/urandom.
2013-05-21 14:02:31 +02:00
Miroslav Lichvar
ea3672df4e Fix some error messages 2013-05-20 18:21:30 +02:00
Miroslav Lichvar
72d0b3c913 Create sockets only in selected family with -4 or -6 option 2013-05-20 15:37:25 +02:00
Miroslav Lichvar
51a2d8dfd8 Set paths in documentation by configure 2013-05-16 14:20:16 +02:00
Miroslav Lichvar
bc25380950 Document default value of commandkey 2013-05-16 14:19:03 +02:00
Miroslav Lichvar
ae1e3bf73c Add option to authenticate automatically on chronyc start 2013-05-16 14:18:57 +02:00
Miroslav Lichvar
9673a2726c Refactor key parsing 2013-05-16 14:18:33 +02:00
Miroslav Lichvar
02524397c1 Try linking readline without ncurses first 2013-05-15 11:50:58 +02:00
Joachim Wiedorn
5e5dde1a67 Various spelling fixes
Reviewed-By: Rogério Theodoro de Brito <rbrito@ime.usp.br>
2013-05-15 11:43:25 +02:00
Miroslav Lichvar
0f8def4ca4 Refactor command parsing
- normalize command line before parsing
- compare whole words
- check for missing/extra arguments in config parsing
- use strdup for string allocation
- share code for reporting syntax errors
- avoid using function pointers
- cleanup the code a bit
2013-05-15 11:27:38 +02:00
Miroslav Lichvar
182ec04e24 Abort on errors when parsing config 2013-05-15 11:14:27 +02:00
Miroslav Lichvar
ebae435398 Log online/offline status change for burst sources too. 2013-05-15 11:03:18 +02:00
Miroslav Lichvar
52657945d8 Don't send uninitialized fields in dump and local requests 2013-05-15 11:02:53 +02:00
Miroslav Lichvar
12166f8a47 Accept float value as initstepslew threshold 2013-05-14 17:16:41 +02:00
Miroslav Lichvar
c5f1dd8615 Update .gitignore 2013-05-14 17:16:41 +02:00
Miroslav Lichvar
10e67e3c1d Terminate batch processing in chronyc on quit command 2013-05-07 17:01:16 +02:00
Miroslav Lichvar
4e8ceaae86 Define DEFAULT_CONF_FILE in config.h 2013-05-07 16:35:40 +02:00
Miroslav Lichvar
73d4eaafbb Reply to NTPv1 and NTPv2 packets with same version 2013-05-02 11:10:48 +02:00
Miroslav Lichvar
cf00179964 Reply to NTPv1 packets 2013-05-02 11:10:25 +02:00
Miroslav Lichvar
edda0c60b3 Add user directive for dropping root privileges
This is equivalent to the -u option.
2013-04-26 17:38:40 +02:00
Miroslav Lichvar
f2eb6b165a Add option to ignore initstepslew and makestep directives
When chronyd is started with -R, the initstepslew directive and the
makestep directive with a positive limit will be ignored. This is useful
when restarting chronyd to avoid unnecessary clock adjustments. It can
be used with -r.
2013-04-26 17:38:37 +02:00
victor lum
4933c216b2 Fix crash with duplicated initstepslew address
When there are duplicate ntp servers listed on the initstepslew line, 2
SourceRecords are created (sourceA and sourceB), and two timers are
created (timerA and timerB).  When ntp responses are received, only
sourceA is updated because of the way read_from_socket searches for a
matching record.  Eventually, the criteria for sourceA are met, causing
timerA to stop and n_completed_sources to increment.  timerB continues
to trigger, sending ntp poll messages to the ntp server.  Responses from
that server are assigned to sourceA, triggering the criteria for sourceA
and causing n_completed_sources to increment improperly.  Once this
happens enough times, n_complete_sources == number of servers and all
SourceRecords are deleted.  The next time timerB triggers, it attempts
to access sourceB, which was already been deleted, causing the core.
2013-04-26 14:36:17 +02:00
Miroslav Lichvar
0655def57f Fix crash in config parsing with too many servers 2013-04-26 14:17:21 +02:00
Miroslav Lichvar
6eafff2450 Update URL of NTP server list in example config 2013-03-08 14:39:20 +01:00
Miroslav Lichvar
0bb772c575 Fix delta calculation with extreme frequency offsets
This should prevent chronyd from getting stuck and refusing new samples
due to failing test4 when the current measured frequency offset is close
to 1.0. That can happen when the system clock is stepped forward behind
chronyd's back.
2013-03-08 14:39:13 +01:00
Miroslav Lichvar
b261693095 Use texi2html to generate html 2013-02-01 18:40:50 +01:00
Miroslav Lichvar
129db63e30 Update NEWS 2013-02-01 15:47:43 +01:00
Miroslav Lichvar
1759d89d8a Print error message when MD5 init fails in chronyc 2013-01-24 19:04:49 +01:00
Miroslav Lichvar
0540b17fb9 Replace printf calls with echo in configure 2013-01-24 19:04:49 +01:00
Miroslav Lichvar
8893dda350 Save compiler messages to config.log in configure 2013-01-24 18:57:39 +01:00
Miroslav Lichvar
b14689d59b Fix crash and hangs in RGR_FindBestRobustRegression 2012-11-29 16:23:22 +01:00
Miroslav Lichvar
1ca844af98 Check for errors when writing new drift files 2012-09-10 17:31:56 +02:00
Miroslav Lichvar
3059747c35 Add format string to printf in client.c 2012-09-10 17:31:56 +02:00
Miroslav Lichvar
bbbb3633a7 Add support for nanoseconds in SHM 2012-09-10 17:31:56 +02:00
Miroslav Lichvar
df6c2a432f Fuzz transmit timestamp
Add random bits below clock precision to the timestamp to make
it less predictable.
2012-05-23 12:06:16 +02:00
Miroslav Lichvar
d0acfc2652 Log uncooked offset in refclocks log for PPS samples 2012-03-13 13:17:03 +01:00
Miroslav Lichvar
711cda6aed Update NEWS 2012-02-28 13:11:56 +01:00
Miroslav Lichvar
0c738d84af Update copyright years 2012-02-28 13:11:56 +01:00
Miroslav Lichvar
be1e1dc441 Fix password handling in chronyc 2012-02-28 13:11:56 +01:00
Miroslav Lichvar
2a305d8e16 Fix compiler warnings 2012-02-27 16:08:21 +01:00
Miroslav Lichvar
15b6ab77ea Update configure help text 2012-02-27 15:45:27 +01:00
Miroslav Lichvar
6199822783 Test leap second timezone on start 2012-02-27 13:28:14 +01:00
Miroslav Lichvar
0b72b2940a Update documentation 2012-02-27 13:28:14 +01:00
Miroslav Lichvar
d4ce3f19c3 Reschedule fast slew timeout on offset change 2012-02-24 16:26:53 +01:00
Miroslav Lichvar
824e86a82f Add leap status to tracking log and report 2012-02-24 11:06:20 +01:00
Miroslav Lichvar
2a5c045c3d Add support for reading leap second data from tz database
leapsectz directive is used to set the name of the timezone in the
system tz database which chronyd can use to find out when will the next
leap second occur.  It will periodically check if dates Jun 30 23:59:60
and Dec 31 23:59:60 are valid in that timezone. This is mainly useful
with reference clocks which don't provide the leap second information.
It is not necessary to restart chronyd if the tz database is updated
with a new leap second at least 12 hours before the event.
2012-02-24 11:06:20 +01:00
Miroslav Lichvar
f7c65a4b88 Add maxchange directive
This directive sets the maximum allowed offset corrected on a clock
update.  The check is performed only after the specified number of
updates to allow a large initial adjustment of the system clock.  When
an offset larger than the specified maximum occurs, it will be ignored
for the specified number of times and then chronyd will give up
and exit (a negative value can be used to never exit).  In both cases
a message is sent to syslog.
2012-02-21 14:34:09 +01:00
Miroslav Lichvar
a8956f2f56 Move refclock slew and dispersion handler init 2012-02-14 18:13:15 +01:00
Miroslav Lichvar
91c9f84a01 Step system time in RTC preinit only with offsets over 1 second 2012-02-14 17:49:55 +01:00
Miroslav Lichvar
2be89bc6f2 Fix last commit 2012-02-14 14:47:57 +01:00
Miroslav Lichvar
d6c447a445 Better estimate RTC offset right after trim 2012-02-13 16:54:18 +01:00
Miroslav Lichvar
a60586eaad Return success on empty command 2012-02-10 18:30:11 +01:00
Miroslav Lichvar
d77356837a Support passwords encoded in HEX 2012-02-09 16:56:17 +01:00
Miroslav Lichvar
d6842301dd Update reported RMS offset quickly on start 2012-02-08 14:30:35 +01:00
Miroslav Lichvar
19b3c5be26 Extend tracking, sources and activity reports 2012-02-03 17:22:53 +01:00
Miroslav Lichvar
5fb5a89f02 Use +/- when logging skew on start 2012-02-03 17:22:52 +01:00
Miroslav Lichvar
9367e7b9af Fix logged offset in manual reference 2012-02-03 15:23:25 +01:00
Miroslav Lichvar
6673cadfa2 Check if struct in6_pktinfo is usable 2012-01-05 15:11:54 +01:00
Miroslav Lichvar
b485051b65 Fix reported number of runs to correspond to reported number of samples 2011-11-28 11:19:48 +01:00
Miroslav Lichvar
9a01ccc07f Add corrtimeratio directive
The corrtimeratio directive controls the ratio between the
duration in which the clock is slewed for an average correction
according to the source history and the interval in which the
corrections are done (usually the NTP polling interval).  Corrections
larger than the average take less time and smaller corrections take
more time, the amount of the correction and the correction time are
inversely proportional.

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

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

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

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

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

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

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

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

17
.gitignore vendored
View File

@@ -1,6 +1,21 @@
*.swp
.deps
.vimrc
*.o
*.swp
RELEASES
Makefile
chrony.conf.5
chrony.info
chrony.html
chrony.texi
chrony.txt
chronyc
chronyc.1
chronyd
chronyd.8
config.h
config.log
tags
version.h
/test/simulation/clknetsim
/test/simulation/tmp

93
INSTALL
View File

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

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
@@ -31,32 +27,32 @@ SBINDIR=@SBINDIR@
MANDIR=@MANDIR@
INFODIR=@INFODIR@
DOCDIR=@DOCDIR@
LOCALSTATEDIR=@LOCALSTATEDIR@
CHRONYVARDIR=@CHRONYVARDIR@
CC = @CC@
CCWARNFLAGS = @CCWARNFLAGS@
OPTFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@ @SYSDEFS@ @EXTRA_DEFS@
CFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@
DESTDIR=
HASH_OBJ = @HASH_OBJ@
OBJS = util.o sched.o regress.o local.o \
sys.o main.o ntp_io.o ntp_core.o ntp_sources.o \
sources.o sourcestats.o reference.o \
logging.o conf.o cmdmon.o md5.o keys.o \
nameserv.o acquire.o manual.o addrfilt.o \
logging.o conf.o cmdmon.o keys.o \
nameserv.o nameserv_async.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
broadcast.o refclock.o refclock_phc.o refclock_pps.o \
refclock_shm.o refclock_sock.o tempcomp.o $(HASH_OBJ)
EXTRA_OBJS=@EXTRA_OBJECTS@
CLI_OBJS = client.o md5.o nameserv.o getdate.o cmdparse.o \
pktlength.o util.o
CLI_OBJS = client.o nameserv.o getdate.o cmdparse.o \
pktlength.o util.o $(HASH_OBJ)
SRCS = $(patsubst %.o,%.c,$(OBJS))
EXTRA_SRCS = $(patsubst %.o,%.c,$(EXTRA_OBJS))
CLI_SRCS = $(patsubst %.o,%.c,$(CLI_OBJS))
ALL_OBJS = $(OBJS) $(EXTRA_OBJS) $(CLI_OBJS)
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
@@ -64,45 +60,43 @@ LIBS = @LIBS@
EXTRA_LIBS=@EXTRA_LIBS@
EXTRA_CLI_LIBS=@EXTRA_CLI_LIBS@
CFLAGS = $(CCWARNFLAGS) $(OPTFLAGS)
# Until we have a main procedure we can link, just build object files
# to test compilation
all : chronyd chronyc
chronyd : $(OBJS) $(EXTRA_OBJS)
$(CC) $(OPTFLAGS) -o chronyd $(OBJS) $(EXTRA_OBJS) $(LDFLAGS) $(LIBS) $(EXTRA_LIBS)
$(CC) $(CFLAGS) -o chronyd $(OBJS) $(EXTRA_OBJS) $(LDFLAGS) $(LIBS) $(EXTRA_LIBS)
chronyc : $(CLI_OBJS)
$(CC) $(OPTFLAGS) -o chronyc $(CLI_OBJS) $(LDFLAGS) @READLINE_LINK@ $(LIBS) $(EXTRA_CLI_LIBS)
conf.o : conf.c
$(CC) $(CFLAGS) $(CPPFLAGS) -DDEFAULT_CONF_DIR=\"$(SYSCONFDIR)\" -c $<
$(CC) $(CFLAGS) -o chronyc $(CLI_OBJS) $(LDFLAGS) $(LIBS) $(EXTRA_CLI_LIBS)
client.o : client.c
$(CC) $(CFLAGS) $(CPPFLAGS) @READLINE_COMPILE@ -c $<
.depend :
gcc -MM $(SRCS) $(EXTRA_SRCS) > .depend
$(HASH_OBJ) : $(patsubst %.o,%.c,$(HASH_OBJ))
$(CC) $(CFLAGS) $(CPPFLAGS) @HASH_COMPILE@ -c $<
distclean :
-rm -f *.o *.s chronyc chronyd core options.h Makefile *~
distclean : clean
-rm -f Makefile
-rm -f chrony.conf.5 chrony.texi chronyc.1 chronyd.8
clean :
-rm -f *.o *.s chronyc chronyd core *~
-rm -f *.o *.s chronyc chronyd core *~ chrony.info chrony.html chrony.txt
-rm -rf .deps
version.h : version.txt
./mkversion
getdate.c :
bison -o getdate.c getdate.y
getdate.c : ;
# This can be used to force regeneration of getdate.c
getdate :
bison -o getdate.c getdate.y
# For install, don't use the install command, because its switches
# seem to vary between systems.
install: chronyd chronyc
install: chronyd chronyc chrony.txt
[ -d $(DESTDIR)$(SYSCONFDIR) ] || mkdir -p $(DESTDIR)$(SYSCONFDIR)
[ -d $(DESTDIR)$(SBINDIR) ] || mkdir -p $(DESTDIR)$(SBINDIR)
[ -d $(DESTDIR)$(BINDIR) ] || mkdir -p $(DESTDIR)$(BINDIR)
[ -d $(DESTDIR)$(DOCDIR) ] || mkdir -p $(DESTDIR)$(DOCDIR)
@@ -110,6 +104,7 @@ install: chronyd chronyc
[ -d $(DESTDIR)$(MANDIR)/man5 ] || mkdir -p $(DESTDIR)$(MANDIR)/man5
[ -d $(DESTDIR)$(MANDIR)/man8 ] || mkdir -p $(DESTDIR)$(MANDIR)/man8
[ -d $(DESTDIR)$(DOCDIR) ] || mkdir -p $(DESTDIR)$(DOCDIR)
[ -d $(DESTDIR)$(CHRONYVARDIR) ] || mkdir -p $(DESTDIR)$(CHRONYVARDIR)
if [ -f $(DESTDIR)$(SBINDIR)/chronyd ]; then rm -f $(DESTDIR)$(SBINDIR)/chronyd ; fi
if [ -f $(DESTDIR)$(BINDIR)/chronyc ]; then rm -f $(DESTDIR)$(BINDIR)/chronyc ; fi
cp chronyd $(DESTDIR)$(SBINDIR)/chronyd
@@ -137,10 +132,8 @@ install: chronyd chronyc
%.s : %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -S $<
main.o logging.o client.o : version.h
# makeinfo v4 required to generate plain text and html
MAKEINFO:=makeinfo
check : chronyd chronyc
cd test/simulation && ./run
install-docs : docs
[ -d $(DESTDIR)$(DOCDIR) ] || mkdir -p $(DESTDIR)$(DOCDIR)
@@ -155,15 +148,19 @@ install-docs : docs
docs : chrony.txt chrony.html chrony.info
chrony.txt : chrony.texi
$(MAKEINFO) --no-headers --number-sections -o chrony.txt chrony.texi
makeinfo --no-headers --number-sections -o chrony.txt chrony.texi
chrony.html : chrony.texi
$(MAKEINFO) --no-split --html --number-sections -o chrony.html chrony.texi
command -v texi2html > /dev/null 2>&1 && texi2html chrony.texi || \
makeinfo --no-split --html --number-sections -o chrony.html chrony.texi
chrony.info : chrony.texi
$(MAKEINFO) chrony.texi
makeinfo chrony.texi
# This is only relevant if you're maintaining the website!
faq.php : faq.txt faqgen.pl
perl faqgen.pl < faq.txt > faq.php
.deps:
@mkdir .deps
.deps/%.d: %.c | .deps
@$(CC) -MM $(CPPFLAGS) -MT '$(<:%.c=%.o) $@' $< -o $@
-include $(ALL_OBJS:%.o=.deps/%.d)

182
NEWS
View File

@@ -1,3 +1,185 @@
New in version 1.31
===================
Enhancements
------------
* Support operation in other NTP eras (next era begins in 2036),
NTP time is mapped to [-50, +86] years around build date by default
* Restore time from driftfile with -s when RTC is missing/unsupported
* Close connected client sockets when not waiting for reply
* Use one client socket with random port when acquisitionport is 0
* Use NTP packets instead of UDP echo for presend
* Don't adjust polling interval when sending fails
* Allow binding to addresses that don't exist yet
* Improve detection of unexpected time jumps
Bug fixes
---------
* Reconnect client sockets for each request to follow changes
in network configuration automatically
* Restart timer when polling interval is changed on reset
New in version 1.30
===================
Enhancements
------------
* Add asynchronous name resolving with POSIX threads
* Add PTP hardware clock (PHC) refclock driver
* Add new generic clock driver to slew by adjusting frequency only
(without kernel PLL or adjtime) and use it on Linux
* Add rtcautotrim directive to trim RTC automatically
* Add hwclockfile directive to share RTC LOCAL/UTC setting with hwclock
* Add maxslewrate directive to set maximum allowed slew rate
* Add maxdispersion option for refclocks
* Add -q/-Q options to set clock/print offset once and exit
* Allow directives to be specified on chronyd command line
* Replace frequency scaling in Linux driver with retaining of tick
* Try to detect unexpected forward time jumps and reset state
* Exit with non-zero code when maxchange limit is reached
* Improve makestep to not start and stop slew unnecessarily
* Change default corrtimeratio to 3.0 to improve frequency accuracy
* Announce leap second only on last day of June and December
* Use separate connected client sockets for each NTP server
* Remove separate NTP implementation used for initstepslew
* Limit maximum minpoll set by KoD RATE to default maxpoll
* Don't send NTP requests with unknown key
* Print warning when source is added with unknown key
* Take leap second in PPS refclock from locked source
* Make reading of RTC for initial trim more reliable
* Don't create cmdmon sockets when cmdport is 0
* Add configure option to set default user to drop root privileges
* Add configure option to compile with debug messages
* Print debug messages when -d is used more than once
* Change format of messages written to terminal with -d
* Write fatal messages also to stderr with -n
* Use IP_RECVERR socket option in chronyc to not wait unnecessarily
* Shorten default chronyc timeout for localhost
* Change default hostname in chronyc from localhost to 127.0.0.1
* Print error message on invalid syntax with all chronyc commands
* Include simulation test suite using clknetsim
Bug fixes
---------
* Fix crash when selecting with multiple preferred sources
* Fix frequency calculation with large frequency offsets
* Fix code writing drift and RTC files to compile correctly
* Fix -4/-6 options in chronyc to not reset hostname set by -h
* Fix refclock sample validation with sub-second polling interval
* Set stratum correctly with non-PPS SOCK refclock and local stratum
* Modify dispersion accounting in refclocks to prevent PPS getting
stuck with large dispersion and not accepting new samples
New in version 1.29.1
=====================
Security fixes
--------------
* Modify chronyc protocol to prevent amplification attacks (CVE-2014-0021)
(incompatible with previous protocol version, chronyc supports both)
New in version 1.29
===================
Security fixes
--------------
* Fix crash when processing crafted commands (CVE-2012-4502)
(possible with IP addresses allowed by cmdallow and localhost)
* Don't send uninitialized data in SUBNETS_ACCESSED and CLIENT_ACCESSES
replies (CVE-2012-4503) (not used by chronyc)
Other changes
-------------
* Drop support for SUBNETS_ACCESSED and CLIENT_ACCESSES commands
New in version 1.28
===================
* Combine sources to improve accuracy
* Make config and command parser strict
* Add -a option to chronyc to authenticate automatically
* Add -R option to ignore initstepslew and makestep directives
* Add generatecommandkey, minsamples, maxsamples and user directives
* Improve compatibility with NTPv1 and NTPv2 clients
* Create sockets only in selected family with -4/-6 option
* Treat address bind errors as non-fatal
* Extend tracking log
* Accept float values as initstepslew threshold
* Allow hostnames in offline, online and burst commands
* Fix and improve peer polling
* Fix crash in config parsing with too many servers
* Fix crash with duplicated initstepslew address
* Fix delta calculation with extreme frequency offsets
* Set local stratum correctly
* Remove unnecessary adjtimex calls
* Set paths in documentation by configure
* Update chrony.spec
New in version 1.27
===================
* Support for stronger keys via NSS or libtomcrypt library
* Support reading leap second data from tz database
* Support for precise clock stepping on Linux
* Support for nanoseconds in SHM refclock
* Make offset corrections smoother on Linux
* Make transmit timestamps random below clock precision
* Add corrtimeratio and maxchange directives
* Extend tracking, sources and activity reports
* Wait in foreground process until daemon is fully initialized
* Fix crash with slow name resolving
* Fix iburst with jittery sources
* Fix offset stored in rtc data right after trimrtc
* Fix crash and hang with RTC or manual samples
* Don't use readonly adjtime on Linux kernels before 2.6.28
* Changed chronyc protocol, incompatible with older versions
New in version 1.26
===================
* Add compatibility with Linux 3.0 and later
* Use proper source address in NTP replies on multihomed IPv6 hosts
* Accept NTP packets with versions 4, 3 and 2
* Cope with unexpected backward time jumps
* Don't reset kernel frequency on start without drift file
* Retry on permanent DNS error by default
* Add waitsync command
New in version 1.25
===================
* Improve accuracy with NTP sources
* Improve accuracy with reference clocks
* Improve polling interval adjustment
* Improve stability with temporary asymmetric delays
* Improve source selection
* Improve initial synchronisation
* Add delayed server name resolving
* Add temperature compensation
* Add nanosecond slewing to Linux driver
* 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,
include 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
* Require password for clients command
* Update drift file at most once per hour
* Use system headers for Linux RTC support
* Reduce default chronyc timeout and make it configurable
* Avoid large values in chronyc sources and sourcestats output
* Add reselect command to force reselecting best source
* Add -m option to allow multiple commands on command line
New in version 1.24
===================

47
README
View File

@@ -2,6 +2,7 @@ This is the README for chrony.
What is chrony?
===============
Chrony is a pair of programs for maintaining the accuracy of computer
clocks.
@@ -10,7 +11,7 @@ time. This does most of the work.
chronyc is a command-line interface program which can be used to
monitor chronyd's performance and to change various operating
parateters whilst it is running.
parameters whilst it is running.
chronyd's main function is to obtain measurements of the true (UTC)
time from one of several sources, and correct the system clock
@@ -21,12 +22,12 @@ between measurements from the reference.
The reference time can be derived from Network Time Protocol (NTP)
servers, reference clocks, or wristwatch-and-keyboard (via chronyc).
The main source of information about the Network Time Protocol is
http://www.eecis.udel.edu/~ntp.
http://www.ntp.org.
It is designed so that it can work on computers which only have
intermittent access to reference sources, for example computers which
use a dial-up account to access the Internet. Of course, it will work
on computers with permanent connections too.
use a dial-up account to access the Internet or laptops. Of course, it
will work well on computers with permanent connections too.
In addition, on Linux it can monitor the system's real time clock
performance, so the system can maintain accurate time even across
@@ -48,10 +49,7 @@ What will chrony run on?
Chrony can be successfully built and run on
1. Linux v1.2.13, v2.0.x, 2.1.x (partially), 2.2.x, 2.3.x, 2.4.x, 2.6.x.
Real time clock support is limited to 2.0.32 onwards and to 2.2, 2.3,
2.4 and 2.6 series only. i386, x86_64, PowerPC are known to be
supported.
1. Linux 2.2.x, 2.3.x, 2.4.x, 2.6.x, 3.x
2. Solaris 2.5/2.5.1/2.6/2.7/2.8 (various platforms)
@@ -64,7 +62,7 @@ supported.
Any other system will require a porting exercise. You would need to
start from one of the existing system-specific drivers and look into
the quirks of certain system calls and the kernel on your target
system. (This is described in the manual).
system.
How do I set it up?
===================
@@ -88,12 +86,6 @@ through the URL
http://chrony.tuxfamily.org/
What can chrony not do?
=======================
Compared to the `reference' RFC1305 implementation xntpd, chronyd does
not support broadcast modes.
Where are new versions announced?
=================================
@@ -103,8 +95,7 @@ by sending mail with the subject "subscribe" to
chrony-announce-request@chrony.tuxfamily.org
These messages will be copied to chrony-users (see below). New versions
are announced also on Freshmeat (http://freshmeat.net/).
These messages will be copied to chrony-users (see below).
How can I get support for chrony?
and where can I discuss new features, possible bugs etc?
@@ -134,7 +125,6 @@ Richard P. Curnow <rc@rc0.org.uk>
Maintainers
===========
John Hasler <john@dhh.gt.org>
Miroslav Lichvar <mlichvar@redhat.com>
@@ -144,6 +134,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
@@ -185,6 +178,7 @@ Juergen Hannken-Illjes <hannken@eis.cs.tu-bs.de>
Port to NetBSD
John Hasler <john@dhh.gt.org>
Project and website at tuxfamily.org
Changes to support 64 bit machines (i.e. those where
sizeof(unsigned long) > 4)
Bug fix to initstepslew directive
@@ -192,12 +186,20 @@ John Hasler <john@dhh.gt.org>
Memory locking and real-time scheduler support
Fix fault where chronyd enters an endless loop
Tjalling Hattink <t.hattink@fugro.nl>
Fix scheduler to allow stepping clock from timeout handler
Patch to take leap second in PPS refclock from locked source
Patch to make reading of RTC for initial trim more reliable
Liam Hatton <me@liamhatton.com>
Advice on configuring for Linux on PPC
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 +211,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
@@ -241,5 +248,3 @@ Doug Woodward <dougw@whistler.com>
Many other people have contributed bug reports and suggestions. I'm
sorry I can't identify all of you individually.
vim:tw=72

784
acquire.c
View File

@@ -1,784 +0,0 @@
/*
$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.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
*
* 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.
*
**********************************************************************
=======================================================================
Processing to perform the equivalent of what ntpdate does. That is,
make a rapid-fire set of measurements to a designated set of
sources, and step or slew the local clock to bring it into line with
the result.
This is kept completely separate of the main chronyd processing, by
using a separate socket for sending/receiving the measurement
packets. That way, ntp_core.c can be kept completely independent of
this functionality.
A few of the finer points of how to construct valid RFC1305 packets
and validate responses for this case have been cribbed from the
ntpdate source.
*/
#include "sysincl.h"
#include "acquire.h"
#include "memory.h"
#include "sched.h"
#include "local.h"
#include "logging.h"
#include "ntp.h"
#include "util.h"
#include "main.h"
#include "conf.h"
/* ================================================== */
/* Interval between firing off the first sample to successive sources */
#define INTER_SOURCE_START (0.2)
#define MAX_SAMPLES 8
#define MAX_DEAD_PROBES 4
#define N_GOOD_SAMPLES 4
#define RETRANSMISSION_TIMEOUT (1.0)
typedef struct {
IPAddr ip_addr; /* Address of the server */
int sanity; /* Flag indicating whether source
looks sane or not */
int n_dead_probes; /* Number of probes sent to the server
since a good one */
int n_samples; /* Number of samples accumulated */
int n_total_samples; /* Total number of samples received
including useless ones */
double offsets[MAX_SAMPLES]; /* In seconds, positive means local
clock is fast of reference */
double root_distances[MAX_SAMPLES]; /* in seconds */
double inter_lo; /* Low end of estimated range of offset */
double inter_hi; /* High end of estimated range of offset */
NTP_int64 last_tx; /* Transmit timestamp in last packet
transmitted to source. */
int timer_running;
SCH_TimeoutID timeout_id;
} SourceRecord;
static SourceRecord *sources;
static int n_sources;
static int n_started_sources;
static int n_completed_sources;
static int init_slew_threshold = -1;
union sockaddr_in46 {
struct sockaddr_in in4;
#ifdef HAVE_IPV6
struct sockaddr_in6 in6;
#endif
struct sockaddr u;
};
static int sock_fd4 = -1;
#ifdef HAVE_IPV6
static int sock_fd6 = -1;
#endif
/* ================================================== */
static void (*saved_after_hook)(void *) = NULL;
static void *saved_after_hook_anything = NULL;
/* ================================================== */
typedef struct {
double offset;
enum {LO, HIGH} type;
int index;
} Endpoint;
typedef struct {
double lo;
double hi;
} Interval;
/* ================================================== */
static void read_from_socket(void *anything);
static void transmit_timeout(void *x);
static void wind_up_acquisition(void);
static void start_source_timeout_handler(void *not_used);
/* ================================================== */
static SCH_TimeoutID source_start_timeout_id;
/* ================================================== */
void
ACQ_Initialise(void)
{
return;
}
/* ================================================== */
void
ACQ_Finalise(void)
{
return;
}
/* ================================================== */
static int
prepare_socket(int family)
{
unsigned short port_number = CNF_GetAcquisitionPort();
int sock_fd;
socklen_t addrlen;
sock_fd = socket(family, SOCK_DGRAM, 0);
if (sock_fd < 0) {
LOG_FATAL(LOGF_Acquire, "Could not open socket : %s", strerror(errno));
}
if (port_number == 0) {
/* Don't bother binding this socket - we're not fussed what port
number it gets */
} else {
union sockaddr_in46 my_addr;
memset(&my_addr, 0, sizeof (my_addr));
switch (family) {
case AF_INET:
my_addr.in4.sin_family = family;
my_addr.in4.sin_port = htons(port_number);
my_addr.in4.sin_addr.s_addr = htonl(INADDR_ANY);
addrlen = sizeof (my_addr.in4);
break;
#ifdef HAVE_IPV6
case AF_INET6:
my_addr.in6.sin6_family = family;
my_addr.in6.sin6_port = htons(port_number);
my_addr.in6.sin6_addr = in6addr_any;
addrlen = sizeof (my_addr.in6);
break;
#endif
default:
assert(0);
}
if (bind(sock_fd, &my_addr.u, addrlen) < 0) {
LOG(LOGS_ERR, LOGF_Acquire, "Could not bind socket : %s\n", strerror(errno));
/* but keep running */
}
}
SCH_AddInputFileHandler(sock_fd, read_from_socket, (void *)(long)sock_fd);
return sock_fd;
}
/* ================================================== */
static void
initialise_io(int family)
{
if (family == IPADDR_INET4 || family == IPADDR_UNSPEC)
sock_fd4 = prepare_socket(AF_INET);
#ifdef HAVE_IPV6
if (family == IPADDR_INET6 || family == IPADDR_UNSPEC)
sock_fd6 = prepare_socket(AF_INET6);
#endif
}
/* ================================================== */
static void
finalise_io(void)
{
if (sock_fd4 >= 0) {
SCH_RemoveInputFileHandler(sock_fd4);
close(sock_fd4);
}
sock_fd4 = -1;
#ifdef HAVE_IPV6
if (sock_fd6 >= 0) {
SCH_RemoveInputFileHandler(sock_fd6);
close(sock_fd6);
}
sock_fd6 = -1;
#endif
return;
}
/* ================================================== */
static void
probe_source(SourceRecord *src)
{
NTP_Packet pkt;
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;
#if 0
printf("Sending probe to %s sent=%d samples=%d\n", UTI_IPToString(&src->ip_addr), src->n_probes_sent, src->n_samples);
#endif
pkt.lvm = (((LEAP_Unsynchronised << 6) & 0xc0) |
((version << 3) & 0x38) |
((my_mode) & 0x7));
pkt.stratum = 0;
pkt.poll = 4;
pkt.precision = -6; /* as ntpdate */
pkt.root_delay = double_to_int32(1.0); /* 1 second */
pkt.root_dispersion = double_to_int32(1.0); /* likewise */
pkt.reference_id = 0UL;
pkt.reference_ts.hi = 0; /* Set to 0 */
pkt.reference_ts.lo = 0; /* Set to 0 */
pkt.originate_ts.hi = 0; /* Set to 0 */
pkt.originate_ts.lo = 0; /* Set to 0 */
pkt.receive_ts.hi = 0; /* Set to 0 */
pkt.receive_ts.lo = 0; /* Set to 0 */
/* And do transmission */
memset(&his_addr, 0, sizeof (his_addr));
switch (src->ip_addr.family) {
case IPADDR_INET4:
his_addr.in4.sin_addr.s_addr = htonl(src->ip_addr.addr.in4);
his_addr.in4.sin_port = htons(123); /* Fixed for now */
his_addr.in4.sin_family = AF_INET;
addrlen = sizeof (his_addr.in4);
sock_fd = sock_fd4;
break;
#ifdef HAVE_IPV6
case IPADDR_INET6:
memcpy(&his_addr.in6.sin6_addr.s6_addr, &src->ip_addr.addr.in6,
sizeof (his_addr.in6.sin6_addr.s6_addr));
his_addr.in6.sin6_port = htons(123); /* Fixed for now */
his_addr.in6.sin6_family = AF_INET6;
addrlen = sizeof (his_addr.in6);
sock_fd = sock_fd6;
break;
#endif
default:
assert(0);
}
LCL_ReadCookedTime(&cooked, &local_time_err);
UTI_TimevalToInt64(&cooked, &pkt.transmit_ts);
if (sendto(sock_fd, (void *) &pkt, NTP_NORMAL_PACKET_SIZE,
0,
&his_addr.u, addrlen) < 0) {
LOG(LOGS_WARN, LOGF_Acquire, "Could not send to %s : %s",
UTI_IPToString(&src->ip_addr),
strerror(errno));
}
src->last_tx = pkt.transmit_ts;
++(src->n_dead_probes);
src->timer_running = 1;
src->timeout_id = SCH_AddTimeoutByDelay(RETRANSMISSION_TIMEOUT, transmit_timeout, (void *) src);
return;
}
/* ================================================== */
static void
transmit_timeout(void *x)
{
SourceRecord *src = (SourceRecord *) x;
src->timer_running = 0;
#if 0
printf("Timeout expired for server %s\n", UTI_IPToString(&src->ip_addr));
#endif
if (src->n_dead_probes < MAX_DEAD_PROBES) {
probe_source(src);
} else {
/* Source has croaked or is taking too long to respond */
++n_completed_sources;
if (n_completed_sources == n_sources) {
wind_up_acquisition();
}
}
}
/* ================================================== */
#define MAX_STRATUM 15
static void
process_receive(NTP_Packet *msg, SourceRecord *src, struct timeval *now)
{
unsigned long lvm;
int leap, version, mode;
double root_delay, root_dispersion;
double total_root_delay, total_root_dispersion, total_root_distance;
struct timeval local_orig, local_average, remote_rx, remote_tx, remote_average;
double remote_interval, local_interval;
double delta, theta, epsilon;
int n;
/* Most of the checks are from ntpdate */
/* Need to do something about authentication */
lvm = msg->lvm;
leap = (lvm >> 6) & 0x3;
version = (lvm >> 3) & 0x7;
mode = lvm & 0x7;
if ((leap == LEAP_Unsynchronised) ||
(version != 3) ||
(mode != MODE_SERVER && mode != MODE_PASSIVE)) {
return;
}
if (msg->stratum > MAX_STRATUM) {
return;
}
/* Check whether server is responding to our last request */
if ((msg->originate_ts.hi != src->last_tx.hi) ||
(msg->originate_ts.lo != src->last_tx.lo)) {
return;
}
/* Check that the server is sane */
if (((msg->originate_ts.hi == 0) && (msg->originate_ts.lo == 0)) ||
((msg->receive_ts.hi == 0) && (msg->receive_ts.lo) == 0)) {
return;
}
root_delay = int32_to_double(msg->root_delay);
root_dispersion = int32_to_double(msg->root_dispersion);
UTI_Int64ToTimeval(&src->last_tx, &local_orig);
UTI_Int64ToTimeval(&msg->receive_ts, &remote_rx);
UTI_Int64ToTimeval(&msg->transmit_ts, &remote_tx);
UTI_AverageDiffTimevals(&remote_rx, &remote_tx, &remote_average, &remote_interval);
UTI_AverageDiffTimevals(&local_orig, now, &local_average, &local_interval);
delta = local_interval - remote_interval;
/* Defined as positive if we are fast. Note this sign convention is
opposite to that used in ntp_core.c */
UTI_DiffTimevalsToDouble(&theta, &local_average, &remote_average);
/* Could work out epsilon - leave till later */
epsilon = 0.0;
total_root_delay = fabs(delta) + root_delay;
total_root_dispersion = epsilon + root_dispersion;
total_root_distance = 0.5 * fabs(total_root_delay) + total_root_dispersion;
n = src->n_samples;
#if 0
printf("Sample %d theta=%.6f delta=%.6f root_del=%.6f root_disp=%.6f root_dist=%.6f\n",
n, theta, delta, total_root_delay, total_root_dispersion, total_root_distance);
#endif
src->offsets[n] = theta;
src->root_distances[n] = total_root_distance;
++(src->n_samples);
}
/* ================================================== */
static void
read_from_socket(void *anything)
{
int status;
ReceiveBuffer msg;
union sockaddr_in46 his_addr;
int sock_fd;
socklen_t his_addr_len;
int flags;
int message_length;
IPAddr remote_ip;
int i, ok;
struct timeval now;
SourceRecord *src;
flags = 0;
message_length = sizeof(msg);
his_addr_len = sizeof(his_addr);
/* Get timestamp */
SCH_GetFileReadyTime(&now);
sock_fd = (long)anything;
status = recvfrom (sock_fd, (char *)&msg, message_length, flags,
&his_addr.u, &his_addr_len);
if (status < 0) {
LOG(LOGS_WARN, LOGF_Acquire, "Error reading from socket, %s", strerror(errno));
return;
}
switch (his_addr.u.sa_family) {
case AF_INET:
remote_ip.family = IPADDR_INET4;
remote_ip.addr.in4 = ntohl(his_addr.in4.sin_addr.s_addr);
break;
#ifdef HAVE_IPV6
case AF_INET6:
remote_ip.family = IPADDR_INET6;
memcpy(&remote_ip.addr.in6, his_addr.in6.sin6_addr.s6_addr,
sizeof (remote_ip.addr.in6));
break;
#endif
default:
assert(0);
}
#if 0
printf("Got message from %s\n", UTI_IPToString(&remote_ip));
#endif
/* Find matching host */
ok = 0;
for (i=0; i<n_sources; i++) {
if (UTI_CompareIPs(&remote_ip, &sources[i].ip_addr, NULL) == 0) {
ok = 1;
break;
}
}
if (ok) {
src = sources + i;
++src->n_total_samples;
src->n_dead_probes = 0; /* reset this when we actually receive something */
/* If we got into this function, we know the retransmission timeout has not
expired for the source */
if (src->timer_running) {
SCH_RemoveTimeout(src->timeout_id);
src->timer_running = 0;
}
process_receive(&msg.ntp_pkt, src, &now);
/* Check if server done and requeue timeout */
if ((src->n_samples >= N_GOOD_SAMPLES) ||
(src->n_total_samples >= MAX_SAMPLES)) {
++n_completed_sources;
#if 0
printf("Source %s completed\n", UTI_IPToString(&src->ip_addr));
#endif
if (n_completed_sources == n_sources) {
wind_up_acquisition();
}
} else {
/* Send the next probe */
probe_source(src);
}
}
}
/* ================================================== */
static void
start_next_source(void)
{
probe_source(sources + n_started_sources);
#if 0
printf("Trying to start source %s\n", UTI_IPToString(&sources[n_started_sources].ip_addr));
#endif
n_started_sources++;
if (n_started_sources < n_sources) {
source_start_timeout_id = SCH_AddTimeoutByDelay(INTER_SOURCE_START, start_source_timeout_handler, NULL);
}
}
/* ================================================== */
static int
endpoint_compare(const void *a, const void *b)
{
const Endpoint *aa = (const Endpoint *) a;
const Endpoint *bb = (const Endpoint *) b;
if (aa->offset < bb->offset) {
return -1;
} else if (aa->offset > bb->offset) {
return +1;
} else {
return 0;
}
}
/* ================================================== */
static void
process_measurements(void)
{
SourceRecord *s;
Endpoint *eps;
int i, j;
int n_sane_sources;
double lo, hi;
double inter_lo, inter_hi;
int depth;
int best_depth;
int n_at_best_depth;
Interval *intervals;
double estimated_offset;
int index1, index2;
n_sane_sources = 0;
/* First, get a consistent interval for each source. Those for
which this is not possible are considered to be insane. */
for (i=0; i<n_sources; i++) {
s = sources + i;
/* If we got no measurements, the source is insane */
if (s->n_samples == 0) {
s->sanity = 0;
} else {
s->sanity = 1; /* so far ... */
lo = s->offsets[0] - s->root_distances[0];
hi = s->offsets[0] + s->root_distances[0];
inter_lo = lo;
inter_hi = hi;
for (j=1; j<s->n_samples; j++) {
lo = s->offsets[j] - s->root_distances[j];
hi = s->offsets[j] + s->root_distances[j];
if ((inter_hi <= lo) || (inter_lo >= hi)) {
/* Oh dear, we won't get an interval for this source */
s->sanity = 0;
break;
} else {
inter_lo = (lo < inter_lo) ? inter_lo : lo;
inter_hi = (hi > inter_hi) ? inter_hi : hi;
}
}
if (s->sanity) {
s->inter_lo = inter_lo;
s->inter_hi = inter_hi;
}
}
if (s->sanity) {
++n_sane_sources;
}
}
/* Now build the endpoint list, similar to the RFC1305 clock
selection algorithm. */
eps = MallocArray(Endpoint, 2*n_sane_sources);
intervals = MallocArray(Interval, n_sane_sources);
j = 0;
for (i=0; i<n_sources; i++) {
s = sources + i;
if (s->sanity) {
eps[j].offset = s->inter_lo;
eps[j].type = LO;
eps[j].index = i;
eps[j+1].offset = s->inter_hi;
eps[j+1].type = HIGH;
eps[j+1].index = i;
j += 2;
}
}
qsort(eps, 2*n_sane_sources, sizeof(Endpoint), endpoint_compare);
/* Now do depth searching algorithm */
n_at_best_depth = best_depth = depth = 0;
for (i=0; i<2*n_sane_sources; i++) {
#if 0
fprintf(stderr, "Endpoint type %s source index %d [ip=%s] offset=%.6f\n",
(eps[i].type == LO) ? "LO" : "HIGH",
eps[i].index,
UTI_IPToString(&sources[eps[i].index].ip_addr),
eps[i].offset);
#endif
switch (eps[i].type) {
case LO:
depth++;
if (depth > best_depth) {
best_depth = depth;
n_at_best_depth = 0;
intervals[0].lo = eps[i].offset;
} else if (depth == best_depth) {
intervals[n_at_best_depth].lo = eps[i].offset;
} else {
/* Nothing to do */
}
break;
case HIGH:
if (depth == best_depth) {
intervals[n_at_best_depth].hi = eps[i].offset;
n_at_best_depth++;
}
depth--;
break;
}
}
if (best_depth > 0) {
if ((n_at_best_depth % 2) == 1) {
index1 = (n_at_best_depth - 1) / 2;
estimated_offset = 0.5 * (intervals[index1].lo + intervals[index1].hi);
} else {
index2 = (n_at_best_depth / 2);
index1 = index2 - 1;
estimated_offset = 0.5 * (intervals[index1].lo + intervals[index2].hi);
}
/* Apply a step change to the system clock. As per sign
convention in local.c and its children, a positive offset means
the system clock is fast of the reference, i.e. it needs to be
stepped backwards. */
if (fabs(estimated_offset) > (double) init_slew_threshold) {
LOG(LOGS_INFO, LOGF_Acquire, "System's initial offset : %.6f seconds %s of true (step)",
fabs(estimated_offset),
(estimated_offset >= 0) ? "fast" : "slow");
LCL_ApplyStepOffset(estimated_offset);
} else {
LOG(LOGS_INFO, LOGF_Acquire, "System's initial offset : %.6f seconds %s of true (slew)",
fabs(estimated_offset),
(estimated_offset >= 0) ? "fast" : "slow");
LCL_AccumulateOffset(estimated_offset);
}
} else {
LOG(LOGS_WARN, LOGF_Acquire, "No intersecting endpoints found");
}
Free(intervals);
Free(eps);
}
/* ================================================== */
static void
wind_up_acquisition(void)
{
/* Now process measurements */
process_measurements();
Free(sources);
finalise_io();
if (saved_after_hook) {
(saved_after_hook)(saved_after_hook_anything);
}
}
/* ================================================== */
static void
start_source_timeout_handler(void *not_used)
{
start_next_source();
}
/* ================================================== */
void
ACQ_StartAcquisition(int n, IPAddr *ip_addrs, int threshold, void (*after_hook)(void *), void *anything)
{
int i, ip4, ip6;
saved_after_hook = after_hook;
saved_after_hook_anything = anything;
init_slew_threshold = threshold;
n_started_sources = 0;
n_completed_sources = 0;
n_sources = n;
sources = MallocArray(SourceRecord, n);
for (i = ip4 = ip6 = 0; i < n; i++) {
sources[i].ip_addr = ip_addrs[i];
sources[i].n_samples = 0;
sources[i].n_total_samples = 0;
sources[i].n_dead_probes = 0;
if (ip_addrs[i].family == IPADDR_INET4)
ip4++;
else if (ip_addrs[i].family == IPADDR_INET6)
ip6++;
}
initialise_io((ip4 && ip6) ? IPADDR_UNSPEC : (ip4 ? IPADDR_INET4 : IPADDR_INET6));
/* Start sampling first source */
start_next_source();
return;
}
/* ================================================== */

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.
**********************************************************************
@@ -50,9 +46,13 @@ typedef struct {
typedef struct {
IPAddr ip_addr;
IPAddr local_ip_addr;
unsigned short port;
} NTP_Remote_Address;
typedef struct {
IPAddr ip_addr;
int sock_fd;
} NTP_Local_Address;
#endif /* GOT_ADDRESSING_H */

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.
**********************************************************************
@@ -32,6 +28,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "addrfilt.h"
@@ -118,8 +116,6 @@ close_node(TableNode *node)
Free(node->extended);
node->extended = NULL;
}
return;
}
@@ -143,7 +139,6 @@ open_node(TableNode *node)
child_node->extended = NULL;
}
}
return;
}
/* ================================================== */
@@ -410,7 +405,6 @@ static void print_node(TableNode *node, uint32_t *addr, int ip_len, int shift, i
print_node(sub_node, new_addr, ip_len, shift - 4, subnet_bits + 4);
}
}
return;
}
@@ -425,7 +419,6 @@ static void print_table(ADF_AuthTable table)
memset(addr, 0, sizeof (addr));
printf("IPv6 table:\n");
print_node(&table->base6, addr, 4, 124, 0);
return;
}
/* ================================================== */

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.
**********************************************************************
@@ -28,6 +24,8 @@
Deal with broadcast server functions.
*/
#include "config.h"
#include "sysincl.h"
#include "memory.h"
@@ -42,6 +40,7 @@
typedef struct {
NTP_Remote_Address addr;
NTP_Local_Address local_addr;
int interval;
} Destination;
static Destination *destinations = 0;
@@ -51,7 +50,6 @@ static int max_destinations = 0;
void
BRD_Initialise(void)
{
return; /* Nothing to do */
}
/* ================================================== */
@@ -59,7 +57,6 @@ BRD_Initialise(void)
void
BRD_Finalise(void)
{
return; /* Nothing to do */
}
/* ================================================== */
@@ -75,15 +72,14 @@ timeout_handler(void *arbitrary)
int leap;
int are_we_synchronised, our_stratum;
NTP_Leap leap_status;
unsigned long our_ref_id;
uint32_t our_ref_id, ts_fuzz;
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,
@@ -94,7 +90,7 @@ timeout_handler(void *arbitrary)
if (are_we_synchronised) {
leap = (int) leap_status;
} else {
leap = 3;
leap = LEAP_Unsynchronised;
}
message.lvm = ((leap << 6) &0xc0) | ((version << 3) & 0x38) | (MODE_BROADCAST & 0x07);
@@ -104,25 +100,26 @@ timeout_handler(void *arbitrary)
/* If we're sending a client mode packet and we aren't synchronized yet,
we might have to set up artificial values for some of these parameters */
message.root_delay = double_to_int32(our_root_delay);
message.root_dispersion = double_to_int32(our_root_dispersion);
message.root_delay = UTI_DoubleToInt32(our_root_delay);
message.root_dispersion = UTI_DoubleToInt32(our_root_dispersion);
message.reference_id = htonl((NTP_int32) our_ref_id);
/* Now fill in timestamps */
UTI_TimevalToInt64(&our_ref_time, &message.reference_ts);
UTI_TimevalToInt64(&our_ref_time, &message.reference_ts, 0);
message.originate_ts.hi = 0UL;
message.originate_ts.lo = 0UL;
message.receive_ts.hi = 0UL;
message.receive_ts.lo = 0UL;
LCL_ReadCookedTime(&local_transmit, &local_time_err);
UTI_TimevalToInt64(&local_transmit, &message.transmit_ts);
NIO_SendNormalPacket(&message, &d->addr);
ts_fuzz = UTI_GetNTPTsFuzz(message.precision);
LCL_ReadCookedTime(&local_transmit, NULL);
UTI_TimevalToInt64(&local_transmit, &message.transmit_ts, ts_fuzz);
NIO_SendNormalPacket(&message, &d->addr, &d->local_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);
@@ -145,11 +142,13 @@ BRD_AddDestination(IPAddr *addr, unsigned short port, int interval)
}
destinations[n_destinations].addr.ip_addr = *addr;
destinations[n_destinations].addr.local_ip_addr.family = IPADDR_UNSPEC;
destinations[n_destinations].addr.port = port;
destinations[n_destinations].local_addr.ip_addr.family = IPADDR_UNSPEC;
destinations[n_destinations].local_addr.sock_fd =
NIO_GetServerSocket(&destinations[n_destinations].addr);
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.
**********************************************************************

142
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.
**********************************************************************
@@ -35,6 +31,7 @@
#include "sysincl.h"
#include "addressing.h"
#include "hash.h"
/* This is the default port to use for CANDM, if no alternative is
defined */
@@ -86,7 +83,12 @@
#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 REQ_RESELECTDISTANCE 49
#define N_REQUEST_TYPES 50
/* Special utoken value used to log on with first exchange being the
password. (This time value has long since gone by) */
@@ -162,6 +164,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 +235,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;
@@ -275,22 +298,10 @@ typedef struct {
uint32_t bits_specd;
} REQ_SubnetsAccessed_Subnet;
#define MAX_SUBNETS_ACCESSED 8
typedef struct {
uint32_t n_subnets;
REQ_SubnetsAccessed_Subnet subnets[MAX_SUBNETS_ACCESSED];
} REQ_SubnetsAccessed;
/* This is based on the response size rather than the
request size */
#define MAX_CLIENT_ACCESSES 8
typedef struct {
uint32_t n_clients;
IPAddr client_ips[MAX_CLIENT_ACCESSES];
} REQ_ClientAccesses;
typedef struct {
uint32_t first_index;
uint32_t n_indices;
@@ -314,6 +325,15 @@ typedef struct {
int32_t EOR;
} REQ_Activity;
typedef struct {
int32_t EOR;
} REQ_Reselect;
typedef struct {
Float distance;
int32_t EOR;
} REQ_ReselectDistance;
/* ================================================== */
#define PKT_TYPE_CMD_REQUEST 1
@@ -334,15 +354,30 @@ typedef struct {
Version 4 : IPv6 addressing added, 64-bit time values, sourcestats
and tracking reports extended, added flags to NTP source request,
trimmed source report, replaced fixed-point format with floating-point
and used also instead of integer microseconds
and used also instead of integer microseconds, new commands: modify stratum,
modify polltarget, modify maxdelaydevratio, reselect, reselectdistance
Version 5 : auth data moved to the end of the packet to allow hashes with
different sizes, extended sources, tracking and activity reports, dropped
subnets accessed and client accesses
Version 6 : added padding to requests to prevent amplification attack,
changed maximum number of samples in manual list to 16
*/
#define PROTO_VERSION_NUMBER 4
#define PROTO_VERSION_NUMBER 6
/* The oldest protocol version that is compatible enough with
the current version to report a version mismatch */
#define PROTO_VERSION_MISMATCH_COMPAT 4
/* The oldest protocol versions that are compatible enough with the current
version to report a version mismatch for the server and the client */
#define PROTO_VERSION_MISMATCH_COMPAT_SERVER 5
#define PROTO_VERSION_MISMATCH_COMPAT_CLIENT 4
/* The first protocol version using padding in requests */
#define PROTO_VERSION_PADDING 6
/* The maximum length of padding in request packet, currently
defined by CLIENT_ACCESSES_BY_INDEX and MANUAL_LIST */
#define MAX_PADDING_LENGTH 396
/* ================================================== */
@@ -358,7 +393,6 @@ typedef struct {
uint32_t sequence; /* Client's sequence number */
uint32_t utoken; /* Unique token per incarnation of daemon */
uint32_t token; /* Command token (to prevent replay attack) */
uint32_t auth[4]; /* MD5 authentication of the packet */
union {
REQ_Online online;
@@ -369,6 +403,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;
@@ -389,15 +426,24 @@ typedef struct {
REQ_RTCReport rtcreport;
REQ_TrimRTC trimrtc;
REQ_CycleLogs cyclelogs;
REQ_SubnetsAccessed subnets_accessed;
REQ_ClientAccesses client_accesses;
REQ_ClientAccessesByIndex client_accesses_by_index;
REQ_ManualList manual_list;
REQ_ManualDelete manual_delete;
REQ_MakeStep make_step;
REQ_Activity activity;
REQ_Reselect reselect;
REQ_ReselectDistance reselect_distance;
} data; /* Command specific parameters */
/* The following fields only set the maximum size of the packet.
There are no holes between them and the actual data. */
/* Padding used to prevent traffic amplification */
uint8_t padding[MAX_PADDING_LENGTH];
/* Authentication data */
uint8_t auth[MAX_HASH_LENGTH];
} CMD_Request;
/* ================================================== */
@@ -435,6 +481,7 @@ typedef struct {
#define STT_BADSUBNET 7
#define STT_ACCESSALLOWED 8
#define STT_ACCESSDENIED 9
/* Deprecated */
#define STT_NOHOSTACCESS 10
#define STT_SOURCEALREADYKNOWN 11
#define STT_TOOMANYSOURCES 12
@@ -463,14 +510,20 @@ 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_OUTLIER 5
#define RPY_SD_FLAG_NOSELECT 0x1
#define RPY_SD_FLAG_PREFER 0x2
typedef struct {
IPAddr ip_addr;
uint16_t poll;
int16_t poll;
uint16_t stratum;
uint16_t state;
uint16_t mode;
uint16_t flags;
uint16_t reachability;
uint32_t since_sample;
Float orig_latest_meas;
Float latest_meas;
@@ -481,14 +534,18 @@ typedef struct {
typedef struct {
uint32_t ref_id;
IPAddr ip_addr;
uint32_t stratum;
uint16_t stratum;
uint16_t leap_status;
Timeval ref_time;
Float current_correction;
Float last_offset;
Float rms_offset;
Float freq_ppm;
Float resid_freq_ppm;
Float skew_ppm;
Float root_delay;
Float root_dispersion;
Float last_update_interval;
int32_t EOR;
} RPY_Tracking;
@@ -529,11 +586,6 @@ typedef struct {
uint32_t bitmap[8];
} RPY_SubnetsAccessed_Subnet;
typedef struct {
uint32_t n_subnets;
RPY_SubnetsAccessed_Subnet subnets[MAX_SUBNETS_ACCESSED];
} RPY_SubnetsAccessed;
typedef struct {
IPAddr ip;
uint32_t client_hits;
@@ -545,19 +597,15 @@ typedef struct {
uint32_t last_cmd_hit_ago;
} RPY_ClientAccesses_Client;
typedef struct {
uint32_t n_clients;
RPY_ClientAccesses_Client clients[MAX_CLIENT_ACCESSES];
} RPY_ClientAccesses;
typedef struct {
uint32_t n_indices; /* how many indices there are in the server's table */
uint32_t next_index; /* the index 1 beyond those processed on this call */
uint32_t n_clients; /* the number of valid entries in the following array */
RPY_ClientAccesses_Client clients[MAX_CLIENT_ACCESSES];
int32_t EOR;
} RPY_ClientAccessesByIndex;
#define MAX_MANUAL_LIST_SAMPLES 32
#define MAX_MANUAL_LIST_SAMPLES 16
typedef struct {
Timeval when;
@@ -569,6 +617,7 @@ typedef struct {
typedef struct {
uint32_t n_samples;
RPY_ManualListSample samples[MAX_MANUAL_LIST_SAMPLES];
int32_t EOR;
} RPY_ManualList;
typedef struct {
@@ -576,6 +625,7 @@ typedef struct {
int32_t offline;
int32_t burst_online;
int32_t burst_offline;
int32_t unresolved;
int32_t EOR;
} RPY_Activity;
@@ -587,15 +637,13 @@ typedef struct {
uint16_t command; /* Which command is being replied to */
uint16_t reply; /* Which format of reply this is */
uint16_t status; /* Status of command processing */
uint16_t number; /* Which packet this is in reply sequence */
uint16_t total; /* Number of replies to expect in this sequence */
uint16_t pad1; /* Get up to 4 byte alignment */
uint16_t pad1; /* Padding for compatibility and 4 byte alignment */
uint16_t pad2;
uint16_t pad3;
uint32_t sequence; /* Echo of client's sequence number */
uint32_t utoken; /* Unique token per incarnation of daemon */
uint32_t token; /* New command token (only if command was successfully
authenticated) */
uint32_t auth[4]; /* MD5 authentication of the packet */
union {
RPY_Null null;
RPY_N_Sources n_sources;
@@ -604,13 +652,15 @@ typedef struct {
RPY_Tracking tracking;
RPY_Sourcestats sourcestats;
RPY_Rtc rtc;
RPY_SubnetsAccessed subnets_accessed;
RPY_ClientAccesses client_accesses;
RPY_ClientAccessesByIndex client_accesses_by_index;
RPY_ManualList manual_list;
RPY_Activity activity;
} data; /* Reply specific parameters */
/* authentication of the packet, there is no hole after the actual data
from the data union, this field only sets the maximum auth size */
uint8_t auth[MAX_HASH_LENGTH];
} CMD_Reply;
/* ================================================== */

View File

@@ -1,4 +1,4 @@
.TH CHRONY 1 "December 04, 2009" chrony "User's Manual"
.TH CHRONY 1 "@MAN_DATE@" "chrony @VERSION@" "User's Manual"
.SH NAME
chrony \- programs for keeping computer clocks accurate
@@ -21,7 +21,7 @@ to the Internet, and it can also act as an RFC1305-compatible NTP server.
.SH USAGE
\fIchronyc\fR is a command-line interface program which can be used to
monitor \fIchronyd\fR's performance and to change various operating
parateters whilst it is running.
parameters whilst it is running.
\fIchronyd\fR's main function is to obtain measurements of the true (UTC)
time from one of several sources, and correct the system clock
@@ -32,16 +32,16 @@ between measurements from the reference.
The reference time can be derived from either Network Time Protocol
(NTP) servers, reference clocks, or wristwatch-and-keyboard (via \fIchronyc\fR).
The main source of information about the Network Time Protocol is
\fIhttp://www.eecis.udel.edu/~ntp\fR.
\fIhttp://www.ntp.org\fR.
It is designed so that it can work on computers which only have
intermittent access to reference sources, for example computers which
use a dial-up account to access the Internet. Of course, it will work
on computers with permanent connections too.
use a dial-up account to access the Internet or laptops. Of course, it
will work well on computers with permanent connections too.
In addition, for Linux 2.0.x (for x >= 32) or 2.2 onwards, chronyd can monitor
the system's real time clock performance, so the system can maintain accurate
time even across reboots.
In addition, on Linux it can monitor the system's real time clock
performance, so the system can maintain accurate time even across
reboots.
Typical accuracies available between 2 machines are
@@ -55,7 +55,8 @@ With a good reference clock the accuracy can reach one microsecond.
.SH "SEE ALSO"
.BR chronyc(1),
.BR chrony(1)
.BR chrony.conf(5),
.BR chronyd(8)
.I http://chrony.tuxfamily.org/

View File

@@ -1,9 +1,9 @@
.TH chrony.conf 5 "December 04, 2009" chrony "Configuration Files"
.TH chrony.conf 5 "@MAN_DATE@" "chrony @VERSION@" "Configuration Files"
.SH NAME
chrony.conf \- chronyd configuration file
.SH SYNOPSIS
.B /etc/chrony.conf
.B @SYSCONFDIR@/chrony.conf
.SH DESCRIPTION
\fIchrony\fR is a pair of programs for maintaining the accuracy of computer
@@ -12,7 +12,7 @@ boot time.
Assuming that you have found some servers, you need to set up a
configuration file to run \fIchrony\fR. The (compiled-in) default location
for this file is \fB/etc/chrony.conf\fR. Assuming that your ntp servers
for this file is \fB@SYSCONFDIR@/chrony.conf\fR. Assuming that your ntp servers
are called `a.b.c' and `d.e.f', your \fBchrony.conf\fR file could contain
as a minimum
@@ -22,16 +22,19 @@ as a minimum
However, you will probably want to include some of the other directives
described in detail in the documentation supplied with the distribution
(\fIchrony.txt\fR and \fIchrony.texi\fR). The following directives will be
particularly useful : `driftfile', `commandkey', `keyfile'. The smallest
useful configuration file would look something like
(\fIchrony.txt\fR and \fIchrony.texi\fR). The following directives may be
particularly useful : `driftfile', `generatecommandkey', `keyfile', `makestep'.
Also, the `iburst' server option is useful to speed up the initial
synchronization. The smallest useful configuration file would look something
like
server a.b.c
server d.e.f
server g.h.i
keyfile /etc/chrony.keys
commandkey 1
driftfile /etc/chrony.drift
server a.b.c iburst
server d.e.f iburst
server g.h.i iburst
keyfile @SYSCONFDIR@/chrony.keys
generatecommandkey
driftfile @CHRONYVARDIR@/drift
makestep 10 3
.SH "SEE ALSO"

View File

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

View File

@@ -1,38 +1,43 @@
%global chrony_version @@VERSION@@
%if 0%(echo %{chrony_version} | grep -q pre && echo 1)
%global prerelease %(echo %{chrony_version} | sed 's/.*-//')
%endif
Summary: An NTP client/server
Name: chrony
Version: @@VERSION@@
Release: 1
Source: chrony-%{version}.tar.gz
Copyright: GPL
Version: %(echo %{chrony_version} | sed 's/-.*//')
Release: %{!?prerelease:1}%{?prerelease:0.1.%{prerelease}}
Source: chrony-%{version}%{?prerelease:-%{prerelease}}.tar.gz
License: GPLv2
Group: Applications/Utilities
Packager: Richard P. Curnow <rc@rc0.org.uk>
BuildRoot: %{_tmppath}/%{name}-%{version}-root-%(id -u -n)
Requires: info
%description
A pair of programs for keeping computer clocks accurate. chronyd is a
background (daemon) program and chronyc is a command-line interface to it.
Time reference sources for chronyd can be RFC1305 NTP servers, human (via
keyboard and chronyc), and the computer's real-time clock at boot time (Linux
only). chronyd can determine the rate at which the computer gains or loses
time and compensate for it whilst no external reference is present. chronyd's
use of NTP servers can be switched on and off (through chronyc) to support
computers with dial-up/intermittent access to the Internet. chronyd can also
act as an RFC1305-compatible NTP server.
chrony is a client and server for the Network Time Protocol (NTP).
This program keeps your computer's clock accurate. It was specially
designed to support systems with intermittent Internet connections,
but it also works well in permanently connected environments. It can
also use hardware reference clocks, the system real-time clock, or
manual input as time references.
%prep
%setup
%setup -q -n %{name}-%{version}%{?prerelease:-%{prerelease}}
%build
./configure --prefix=%{_prefix} --mandir=%{_mandir}
make CC=gcc CFLAGS=-O2 prefix=%{_prefix}
make chrony.txt prefix=%{_prefix}
make chrony.info prefix=%{_prefix}
./configure \
--prefix=%{_prefix} \
--bindir=%{_bindir} \
--sbindir=%{_sbindir} \
--infodir=%{_infodir} \
--mandir=%{_mandir}
make
make chrony.txt
make chrony.info
%install
rm -rf $RPM_BUILD_ROOT
cd $RPM_BUILD_DIR/chrony-%{version}
make install DESTDIR=$RPM_BUILD_ROOT prefix=%{_prefix}
make install DESTDIR=$RPM_BUILD_ROOT
rm -rf $RPM_BUILD_ROOT%{_docdir}
mkdir -p $RPM_BUILD_ROOT%{_infodir}
cp chrony.info* $RPM_BUILD_ROOT%{_infodir}
@@ -47,6 +52,6 @@ cp chrony.info* $RPM_BUILD_ROOT%{_infodir}
%doc README
%doc chrony.txt
%doc COPYING
%doc examples/chrony.conf.example
%doc examples/chrony.conf.example*
%doc examples/chrony.keys.example

File diff suppressed because it is too large Load Diff

View File

@@ -35,8 +35,13 @@ 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_SETOFFSET 0x0100 /* add 'time' to current time */
#define ADJ_NANO 0x2000 /* select nanosecond resolution */
#define ADJ_TICK 0x4000 /* tick value */
#define ADJ_OFFSET_SINGLESHOT 0x8001 /* old-fashioned adjtime */
#define ADJ_OFFSET_SS_READ 0xa001 /* read-only adjtime */
@@ -59,6 +64,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

@@ -1,4 +1,4 @@
.TH CHRONYC 1 "December 04, 2009" chrony "User's Manual"
.TH CHRONYC 1 "@MAN_DATE@" "chrony @VERSION@" "User's Manual"
.SH NAME
chronyc \- command-line interface for chronyd
@@ -12,7 +12,7 @@ clocks.
\fBchronyc\fR is a command-line interface program which can be used to
monitor \fIchronyd\fR's performance and to change various operating
parateters whilst it is running.
parameters whilst it is running.
.SH USAGE
A detailed description of all commands supported by \fBchronyc\fR is available
@@ -24,7 +24,7 @@ A summary of the options supported by \fBchronyc\fR is included below.
.TP
\fB\-h\fR \fIhostname\fR
specify hostname
specify hostname (default 127.0.0.1)
.TP
\fB\-p\fR \fIport-number\fR
specify port-number
@@ -38,14 +38,24 @@ 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
\fB\-f\fR \fIconf-file\fR
This option can be used to specify an alternate location for the
configuration file (default \fI@SYSCONFDIR@/chrony.conf\fR). The configuration file is
needed for the \fB-a\fR option.
.TP
\fB\-a\fR
With this option chronyc will try to authenticate automatically on
start. It will read the configuration file, read the command key from the
keyfile and run the authhash and password commands.
.TP
\fIcommand\fR
specify command. If no command is given, chronyc will read commands
interactively.
.SH VERSION
1.24
.SH BUGS
To report bugs, please visit \fIhttp://chrony.tuxfamily.org\fR
@@ -63,4 +73,3 @@ Man Pages Project". Please see \fIhttp://www.netmeister.org/misc/m2p2/index.htm
for details.
The complete chrony documentation is supplied in texinfo format.

View File

@@ -1,10 +1,10 @@
.TH CHRONYD 8 "December 04, 2009" chrony "System Administration"
.TH CHRONYD 8 "@MAN_DATE@" "chrony @VERSION@" "System Administration"
.SH NAME
chronyd \- chrony background daemon
.SH SYNOPSIS
.B chronyd
[\fIOPTIONS\fR]
[\fIOPTIONS\fR] [\fIconfiguration commands\fR]
.SH DESCRIPTION
\fIchrony\fR is a pair of programs for maintaining the accuracy of computer
@@ -21,16 +21,19 @@ gains or loses time, and compensates for this.
.SH USAGE
\fBchronyd\fR is usually started at boot-time and requires superuser
priviliges.
privileges.
If \fBchronyd\fR has been installed to its default location
\fI/usr/local/sbin/chronyd\fR, starting it is simply a matter of entering the
\fI@SBINDIR@/chronyd\fR, starting it is simply a matter of entering the
command:
\fI/usr/local/sbin/chronyd\fR
\fI@SBINDIR@/chronyd\fR
Information messages and warnings will be logged to syslog.
If no configuration commands are specified on the command line,
\fBchronyd\fR will read the commands from the configuration file
(default \fI@SYSCONFDIR@/chrony.conf\fR).
.SH OPTIONS
A summary of the options supported by \fBchronyd\fR is included below.
@@ -45,14 +48,19 @@ 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
to syslog.
to syslog. When \fBchronyd\fR was compiled with debugging support,
this option can be used twice to print also debugging messages.
.TP
\fB\-f\fR \fIconf-file\fR
This option can be used to specify an alternate location for the
configuration file (default \fI/etc/chrony.conf\fR).
configuration file (default \fI@SYSCONFDIR@/chrony.conf\fR).
.TP
.B \-r
This option will reload sample histories for each of the servers being used.
@@ -65,63 +73,76 @@ systems where the kernel can maintain clock compensation whilst not under
On systems where this is not the case, e.g. Solaris and SunOS the option
should not be used.
.TP
.B \-R
When this option is used, the \fIinitstepslew\fR directive and the
\fImakestep\fR directive used with a positive limit will be ignored. This
option is useful when restarting \fBchronyd\fR and can be used in conjunction
with the \fB-r\fR option.
.TP
.B \-s
This option will set the system clock from the computer's real-time
clock. This is analogous to supplying the \fI-s\fR flag to the
\fI/sbin/clock\fR program during the Linux boot sequence.
\fI/sbin/hwclock\fR program during the Linux boot sequence.
Support for real-time clocks is limited at present - the criteria
are described in the section on the \fIrtcfile\fR directive in the
documentation supplied with the distribution.
If \fBchronyd\fR cannot support the real time clock on your computer,
this option cannot be used and a warning message will be logged to
the syslog.
If used in conjunction with the \fB-r\fR flag, \fBchronyd\fR will attempt
to preserve the old samples after setting the system clock from
the real time clock. This can be used to allow \fBchronyd\fR to
the real time clock (RTC). This can be used to allow \fBchronyd\fR to
perform long term averaging of the gain or loss rate across system
reboots, and is useful for dial-up systems that are shut down when
not in use. For this to work well, it relies on \fBchronyd\fR having
been able to determine accurate statistics for the difference
between the real time clock and system clock last time the
computer was on.
between the RTC and system clock last time the computer was on.
If \fBchronyd\fR doesn't support the RTC on your computer or there is no RTC
installed, the system clock will be set with this option forward to the time of
the last modification of the drift file (specified by the \fIdriftfile\fR
directive) to restore the system time at which \fBchronyd\fR was previously
stopped.
.TP
\fB\-u\fR \fIuser\fR
When this option is used, chronyd will drop root privileges to the specified
user. So far, it works only on Linux when compiled with capabilities support.
This option sets the name of the user to which will \fBchronyd\fR switch to
drop root privileges if compiled with Linux capabilities support (default
\fB@DEFAULT_USER@\fR).
.TP
.B \-q
When run in this mode, chronyd will set the system clock once
and exit. It will not detach from the terminal.
.TP
.B \-Q
This option is similar to \fB\-q\fR, but it will only print the offset and
not correct the clock.
.TP
.B \-v
This option displays \fBchronyd\fR's version number to the terminal and exits
.TP
.B \-4
Resolve hostnames only to IPv4 addresses.
Resolve hostnames only to IPv4 addresses and create only IPv4 sockets.
.TP
.B \-6
Resolve hostnames only to IPv6 addresses.
Resolve hostnames only to IPv6 addresses and create only IPv6 sockets.
.SH FILES
\fI/etc/chrony.conf\fR
.SH VERSION
Version 1.24
\fI@SYSCONFDIR@/chrony.conf\fR
.SH BUGS
To report bugs, please visit \fIhttp://chrony.tuxfamily.org/\fR
.SH "SEE ALSO"
\fBchronyd\fR is documented in detail in the documentation supplied with the
distribution (\fIchrony.txt\fR and \fIchrony.texi\fR) and is also available
from \fIhttp://go.to/chrony\fR
distribution (\fIchrony.txt\fR and \fIchrony.texi\fR).
.BR chrony(1),
.BR chronyc(1),
.BR chrony.conf(5),
.BR clock(8),
.BR xntpd(8),
.BR hwclock(8),
.BR ntpd(8)
.I http://chrony.tuxfamily.org/
.SH AUTHOR
Richard Curnow <rc@rc0.org.uk>

1375
client.c

File diff suppressed because it is too large Load Diff

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.
**********************************************************************
@@ -35,6 +31,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "clientlog.h"
#include "conf.h"
@@ -176,7 +174,6 @@ CLG_Initialise(void)
void
CLG_Finalise(void)
{
return;
}
/* ================================================== */

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.
**********************************************************************

711
cmdmon.c

File diff suppressed because it is too large Load Diff

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.
**********************************************************************
@@ -33,7 +29,7 @@
#include "addressing.h"
extern void CAM_Initialise(void);
extern void CAM_Initialise(int family);
extern void CAM_Finalise(void);

View File

@@ -1,12 +1,9 @@
/*
$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.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2013
*
* 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
@@ -30,57 +27,57 @@
*/
#include "config.h"
#include "sysincl.h"
#include "cmdparse.h"
#include "memory.h"
#include "nameserv.h"
#define MAXLEN 2047
#define SMAXLEN "2047"
#include "util.h"
/* ================================================== */
CPS_Status
CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
{
char *hostname, *cmd;
int ok, n, done;
char cmd[MAXLEN+1], hostname[MAXLEN+1];
CPS_Status result;
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)) {
ok = 1;
}
}
hostname = line;
line = CPS_SplitWord(line);
if (!ok) {
if (!*hostname) {
result = CPS_BadHost;
ok = 0;
} else {
line += n;
/* Parse subfields */
ok = 1;
done = 0;
do {
if (sscanf(line, "%" SMAXLEN "s%n", cmd, &n) == 1) {
line += n;
if (!strncasecmp(cmd, "port", 4)) {
cmd = line;
line = CPS_SplitWord(line);
if (*cmd) {
if (!strcasecmp(cmd, "port")) {
if (sscanf(line, "%hu%n", &src->port, &n) != 1) {
result = CPS_BadPort;
ok = 0;
@@ -88,7 +85,7 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
} else {
line += n;
}
} else if (!strncasecmp(cmd, "minpoll", 7)) {
} else if (!strcasecmp(cmd, "minpoll")) {
if (sscanf(line, "%d%n", &src->params.minpoll, &n) != 1) {
result = CPS_BadMinpoll;
ok = 0;
@@ -96,7 +93,7 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
} else {
line += n;
}
} else if (!strncasecmp(cmd, "maxpoll", 7)) {
} else if (!strcasecmp(cmd, "maxpoll")) {
if (sscanf(line, "%d%n", &src->params.maxpoll, &n) != 1) {
result = CPS_BadMaxpoll;
ok = 0;
@@ -104,7 +101,7 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
} else {
line += n;
}
} else if (!strncasecmp(cmd, "presend", 7)) {
} else if (!strcasecmp(cmd, "presend")) {
if (sscanf(line, "%d%n", &src->params.presend_minpoll, &n) != 1) {
result = CPS_BadPresend;
ok = 0;
@@ -112,8 +109,15 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
} else {
line += n;
}
/* This MUST come before the following one ! */
} else if (!strncasecmp(cmd, "maxdelayratio", 13)) {
} else if (!strcasecmp(cmd, "maxdelaydevratio")) {
if (sscanf(line, "%lf%n", &src->params.max_delay_dev_ratio, &n) != 1) {
result = CPS_BadMaxdelaydevratio;
ok = 0;
done = 1;
} else {
line += n;
}
} else if (!strcasecmp(cmd, "maxdelayratio")) {
if (sscanf(line, "%lf%n", &src->params.max_delay_ratio, &n) != 1) {
result = CPS_BadMaxdelayratio;
ok = 0;
@@ -121,7 +125,7 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
} else {
line += n;
}
} else if (!strncasecmp(cmd, "maxdelay", 8)) {
} else if (!strcasecmp(cmd, "maxdelay")) {
if (sscanf(line, "%lf%n", &src->params.max_delay, &n) != 1) {
result = CPS_BadMaxdelay;
ok = 0;
@@ -129,20 +133,48 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
} else {
line += n;
}
} else if (!strncasecmp(cmd, "key", 3)) {
if (sscanf(line, "%lu%n", &src->params.authkey, &n) != 1) {
} else if (!strcasecmp(cmd, "key")) {
if (sscanf(line, "%lu%n", &src->params.authkey, &n) != 1 ||
src->params.authkey == INACTIVE_AUTHKEY) {
result = CPS_BadKey;
ok = 0;
done = 1;
} else {
line += n;
}
} else if (!strncasecmp(cmd, "offline", 7)) {
} else if (!strcasecmp(cmd, "offline")) {
src->params.online = 0;
} else if (!strncasecmp(cmd, "auto_offline", 12)) {
} else if (!strcasecmp(cmd, "auto_offline")) {
src->params.auto_offline = 1;
} else if (!strcasecmp(cmd, "iburst")) {
src->params.iburst = 1;
} else if (!strcasecmp(cmd, "minstratum")) {
if (sscanf(line, "%d%n", &src->params.min_stratum, &n) != 1) {
result = CPS_BadMinstratum;
ok = 0;
done = 1;
} else {
line += n;
}
} else if (!strcasecmp(cmd, "polltarget")) {
if (sscanf(line, "%d%n", &src->params.poll_target, &n) != 1) {
result = CPS_BadPolltarget;
ok = 0;
done = 1;
} else {
line += n;
}
} else if (!strcasecmp(cmd, "noselect")) {
src->params.sel_option = SRC_SelectNoselect;
} else if (!strcasecmp(cmd, "prefer")) {
src->params.sel_option = SRC_SelectPrefer;
} else {
result = CPS_BadOption;
ok = 0;
@@ -154,9 +186,97 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
} while (!done);
}
if (ok) {
src->name = strdup(hostname);
}
return result;
}
/* ================================================== */
void
CPS_NormalizeLine(char *line)
{
char *p, *q;
int space = 1, first = 1;
/* Remove white-space at beginning and replace white-spaces with space char */
for (p = q = line; *p; p++) {
if (isspace(*p)) {
if (!space)
*q++ = ' ';
space = 1;
continue;
}
/* Discard comment lines */
if (first && strchr("!;#%", *p))
break;
*q++ = *p;
space = first = 0;
}
/* Strip trailing space */
if (q > line && q[-1] == ' ')
q--;
*q = '\0';
}
/* ================================================== */
char *
CPS_SplitWord(char *line)
{
char *p = line, *q = line;
/* Skip white-space before the word */
while (*q && isspace(*q))
q++;
/* Move the word to the beginning */
while (*q && !isspace(*q))
*p++ = *q++;
/* Find the next word */
while (*q && isspace(*q))
q++;
*p = '\0';
/* Return pointer to the next word or NUL */
return q;
}
/* ================================================== */
int
CPS_ParseKey(char *line, unsigned long *id, const char **hash, char **key)
{
char *s1, *s2, *s3, *s4;
s1 = line;
s2 = CPS_SplitWord(s1);
s3 = CPS_SplitWord(s2);
s4 = CPS_SplitWord(s3);
/* Require two or three words */
if (!*s2 || *s4)
return 0;
if (sscanf(s1, "%lu", id) != 1)
return 0;
if (*s3) {
*hash = s2;
*key = s3;
} else {
*hash = "MD5";
*key = s2;
}
return 1;
}

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,20 +38,30 @@ 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;
/* Parse a command to add an NTP server or peer */
extern CPS_Status CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src);
extern CPS_Status CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src);
/* Remove extra white-space and comments */
extern void CPS_NormalizeLine(char *line);
/* Terminate first word and return pointer to the next word */
extern char *CPS_SplitWord(char *line);
/* Parse a key from keyfile */
extern int CPS_ParseKey(char *line, unsigned long *id, const char **hash, char **key);
#endif /* GOT_CMDPARSE_H */

1415
conf.c

File diff suppressed because it is too large Load Diff

48
conf.h
View File

@@ -1,12 +1,9 @@
/*
$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.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2013-2014
*
* 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,46 +30,62 @@
#include "addressing.h"
extern void CNF_SetRestarted(int);
extern char *CNF_GetRtcDevice(void);
extern void CNF_ReadFile(const char *filename);
extern void CNF_ParseLine(const char *filename, int number, char *line);
extern void CNF_AddInitSources(void);
extern void CNF_AddSources(void);
extern void CNF_AddBroadcasts(void);
extern void CNF_AddRefclocks(void);
extern void CNF_ProcessInitStepSlew(void (*after_hook)(void *), void *anything);
extern unsigned short CNF_GetAcquisitionPort(void);
extern unsigned short CNF_GetNTPPort(void);
extern int CNF_GetAcquisitionPort(void);
extern int CNF_GetNTPPort(void);
extern char *CNF_GetDriftFile(void);
extern char *CNF_GetLogDir(void);
extern char *CNF_GetDumpDir(void);
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);
extern int CNF_GetGenerateCommandKey(void);
extern int CNF_GetDumpOnExit(void);
extern int CNF_GetManualEnabled(void);
extern int CNF_GetCommandPort(void);
extern int CNF_GetRTCOnUTC(void);
extern int CNF_GetRtcOnUtc(void);
extern int CNF_GetRtcSync(void);
extern void CNF_GetMakeStep(int *limit, double *threshold);
extern void CNF_GetMaxChange(int *delay, int *ignore, double *offset);
extern void CNF_GetLogChange(int *enabled, double *threshold);
extern void CNF_GetMailOnChange(int *enabled, double *threshold, char **user);
extern int CNF_GetNoClientLog(void);
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_GetBindAcquisitionAddress(int family, IPAddr *addr);
extern void CNF_GetBindCommandAddress(int family, IPAddr *addr);
extern char *CNF_GetPidFile(void);
extern void CNF_GetLinuxHz(int *set, int *hz);
extern void CNF_GetLinuxFreqScale(int *set, double *freq_scale);
extern char *CNF_GetLeapSecTimezone(void);
/* Value returned in ppm, as read from file */
extern double CNF_GetMaxUpdateSkew(void);
extern double CNF_GetMaxClockError(void);
extern double CNF_GetCorrectionTimeRatio(void);
extern double CNF_GetMaxSlewRate(void);
extern double CNF_GetReselectDistance(void);
extern double CNF_GetStratumWeight(void);
extern double CNF_GetCombineLimit(void);
extern int CNF_AllowLocalReference(int *stratum);
extern void CNF_SetupAccessRestrictions(void);
@@ -80,4 +93,17 @@ 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);
extern char *CNF_GetUser(void);
extern int CNF_GetMaxSamples(void);
extern int CNF_GetMinSamples(void);
extern double CNF_GetRtcAutotrim(void);
extern char *CNF_GetHwclockFile(void);
extern int CNF_GetInitSources(void);
extern double CNF_GetInitStepThreshold(void);
#endif /* GOT_CONF_H */

368
configure vendored
View File

@@ -4,9 +4,12 @@
# chronyd/chronyc - Programs for keeping computer clocks accurate.
#
# Copyright (C) Richard P. Curnow 1997-2003
# Copyright (C) Miroslav Lichvar 2009, 2012-2014
#
# =======================================================================
rm -f config.h config.log
# This configure script determines the operating system type and version
if [ "x${CC}" = "x" ]; then
@@ -24,11 +27,11 @@ fi
MYCPPFLAGS="${CPPFLAGS}"
if [ "x${MYCC}" = "xgcc" ]; then
CCWARNFLAGS="-Wmissing-prototypes -Wall"
else
CCWARNFLAGS=""
MYCFLAGS="${MYCFLAGS} -Wmissing-prototypes -Wall"
fi
MYLDFLAGS="${LDFLAGS}"
# ======================================================================
# FUNCTIONS
@@ -40,7 +43,7 @@ test_code () {
ldflags=$4
code=$5
printf "Checking for $name : "
echo -n "Checking for $name : "
(
for h in $headers; do
@@ -51,23 +54,30 @@ test_code () {
echo "return 0; }"
) > docheck.c
${MYCC} ${MYCFLAGS} ${MYCPPFLAGS} $cflags -o docheck docheck.c $ldflags >/dev/null 2>&1
echo "docheck.c:" >> config.log
cat docheck.c >> config.log
echo $MYCC $MYCFLAGS $MYCPPFLAGS $cflags -o docheck docheck.c $ldflags \
$MYLDFLAGS >> config.log
$MYCC $MYCFLAGS $MYCPPFLAGS $cflags -o docheck docheck.c $ldflags \
$MYLDFLAGS >> config.log 2>&1
if [ $? -eq 0 ]
then
printf "Yes\n"
echo "Yes"
result=0
else
printf "No\n"
echo "No"
result=1
fi
rm -f docheck.c docheck
echo >> config.log
return $result
}
#}}}
#{{{ usage
usage () {
cat <<EOF;
\`configure' configures tdl to adapt to many kinds of systems.
cat <<EOF
\`configure' configures this package to adapt to many kinds of systems.
Usage: ./configure [OPTION]...
@@ -95,10 +105,20 @@ For better control, use the options below.
--readline-inc-dir=DIR Specify where readline include directory is
--readline-lib-dir=DIR Specify where readline lib directory is
--with-ncurses-library=DIR Specify where ncurses lib directory is
--without-nss Don't use NSS even if it is available
--without-tomcrypt Don't use libtomcrypt even if it is available
--disable-ipv6 Disable IPv6 support
--disable-phc Disable PHC support
--disable-pps Disable PPS API support
--disable-rtc Don't include RTC even on Linux
--disable-linuxcaps Disable Linux capabilities support
--disable-asyncdns Disable asynchronous name resolving
--disable-forcednsretry Don't retry on permanent DNS error
--with-ntp-era=SECONDS Specify earliest assumed NTP time in seconds
since 1970-01-01 [50*365 days ago]
--with-user=USER Specify default chronyd user [root]
--with-sendmail=PATH Path to sendmail binary [/usr/lib/sendmail]
--enable-debug Enable debugging support
Fine tuning of the installation directories:
--sysconfdir=DIR chrony.conf location [/etc]
@@ -108,6 +128,8 @@ Fine tuning of the installation directories:
--infodir=DIR info documentation [DATAROOTDIR/info]
--mandir=DIR man documentation [DATAROOTDIR/man]
--docdir=DIR documentation root [DATAROOTDIR/doc/chrony]
--localstatedir=DIR modifiable single-machine data [/var]
--chronyvardir=DIR location for chrony data [LOCALSTATEDIR/lib/chrony]
Overriding system detection when cross-compiling:
--host-system=OS Specify system name (uname -s)
@@ -129,6 +151,15 @@ EOF
}
#}}}
#{{{
add_def () {
if [ "x$2" = "x" ]; then
echo "#define $1 1" >> config.h
else
echo "#define $1 $2" >> config.h
fi
}
#}}}
# ======================================================================
@@ -144,26 +175,36 @@ EXTRA_OBJECTS=""
EXTRA_DEFS=""
SYSDEFS=""
# Support for readline (on by default)
debug=0
feat_readline=1
try_readline=1
try_editline=1
try_nss=1
try_tomcrypt=1
feat_rtc=1
try_rtc=0
feat_linuxcaps=1
try_linuxcaps=0
readline_lib=""
readline_inc=""
ncurses_lib=""
feat_ipv6=1
feat_phc=1
try_phc=0
feat_pps=1
try_setsched=0
try_lockmem=0
feat_asyncdns=1
feat_forcednsretry=1
ntp_era_split=""
default_user="root"
mail_program="/usr/lib/sendmail"
for option
do
case "$option" in
--trace )
EXTRA_DEFS="-DTRACEON"
--enable-debug )
debug=1
;;
--disable-readline )
feat_readline=0
@@ -210,18 +251,48 @@ do
--docdir=* )
SETDOCDIR=`echo $option | sed -e 's/^.*=//;'`
;;
--localstatedir=* )
SETLOCALSTATEDIR=`echo $option | sed -e 's/^.*=//;'`
;;
--chronyvardir=* )
SETCHRONYVARDIR=`echo $option | sed -e 's/^.*=//;'`
;;
--disable-rtc)
feat_rtc=0
;;
--disable-ipv6)
feat_ipv6=0
;;
--disable-phc)
feat_phc=0
;;
--disable-pps)
feat_pps=0
;;
--disable-linuxcaps)
feat_linuxcaps=0
;;
--disable-asyncdns)
feat_asyncdns=0
;;
--disable-forcednsretry)
feat_forcednsretry=0
;;
--with-ntp-era=* )
ntp_era_split=`echo $option | sed -e 's/^.*=//;'`
;;
--with-user=* )
default_user=`echo $option | sed -e 's/^.*=//;'`
;;
--with-sendmail=* )
mail_program=`echo $option | sed -e 's/^.*=//;'`
;;
--without-nss )
try_nss=0
;;
--without-tomcrypt )
try_tomcrypt=0
;;
--host-system=* )
OPERATINGSYSTEM=`echo $option | sed -e 's/^.*=//;'`
;;
@@ -248,37 +319,31 @@ case $SYSTEM in
4.* )
EXTRA_OBJECTS="sys_sunos.o strerror.o"
EXTRA_LIBS="-lkvm"
SYSDEFS="-DSUNOS"
add_def SUNOS
echo "Configuring for SunOS (" $SYSTEM "version" $VERSION ")"
;;
5.* )
EXTRA_OBJECTS="sys_solaris.o"
EXTRA_LIBS="-lsocket -lnsl -lkvm -lelf"
EXTRA_CLI_LIBS="-lsocket -lnsl"
SYSDEFS="-DSOLARIS"
add_def SOLARIS
echo "Configuring for Solaris (" $SYSTEM "SunOS version" $VERSION ")"
if [ $VERSION = "5.3" ]; then
SYSDEFS="$SYSDEFS -DHAS_NO_BZERO"
echo "Using memset() instead of bzero()"
fi
;;
esac
;;
Linux* )
EXTRA_OBJECTS="sys_linux.o wrap_adjtimex.o"
if [ $feat_rtc -eq 1 ] ; then
EXTRA_OBJECTS="$EXTRA_OBJECTS rtc_linux.o"
EXTRA_DEFS="$EXTRA_DEFS -DFEAT_RTC=1"
fi
EXTRA_OBJECTS="sys_generic.o sys_linux.o wrap_adjtimex.o"
try_linuxcaps=1
try_rtc=1
try_setsched=1
try_lockmem=1
SYSDEFS="-DLINUX"
try_phc=1
add_def LINUX
echo "Configuring for " $SYSTEM
if [ "${MACHINE}" = "alpha" ]; then
echo "Enabling -mieee"
# FIXME: Should really test for GCC
SYSDEFS="$SYSDEFS -mieee -DALPHA"
MYCFLAGS="$MYCFLAGS -mieee"
fi
;;
@@ -287,7 +352,7 @@ case $SYSTEM in
# be supported with the SunOS 4.x driver files.
EXTRA_OBJECTS="sys_sunos.o strerror.o"
EXTRA_LIBS="-lkvm"
SYSDEFS="-DSUNOS"
add_def SUNOS
echo "Configuring for $SYSTEM (using SunOS driver)"
;;
NetBSD-* )
@@ -302,13 +367,13 @@ case $SYSTEM in
EXTRA_OBJECTS="sys_solaris.o"
EXTRA_LIBS="-lsocket -lnsl -lkvm -lelf"
EXTRA_CLI_LIBS="-lsocket -lnsl"
SYSDEFS="-DSOLARIS"
add_def SOLARIS
echo "Configuring for Solaris (" $SYSTEM "SunOS version" $VERSION ")"
;;
CYGWIN32_NT-i[3456]86 )
EXTRA_OBJECTS="sys_winnt.o"
EXTRA_LIBS=""
SYSDEFS="-DWINNT"
add_def WINNT
echo "Configuring for Windows NT (Cygwin32)"
;;
* )
@@ -317,6 +382,40 @@ case $SYSTEM in
;;
esac
if test_code '64-bit time_t' 'time.h' '' '' '
char x[sizeof(time_t) > 4 ? 1 : -1] = {0};
return x[0];'
then
add_def HAVE_LONG_TIME_T 1
if [ "x$ntp_era_split" != "x" ]; then
split_seconds=$ntp_era_split
split_days=0
else
split_seconds=`date '+%s'`
if [ "x$split_seconds" = "" ]; then
echo "Could not get current time, --with-ntp-era option is needed"
exit 1
fi
split_days=$((50 * 365))
fi
add_def NTP_ERA_SPLIT "(${split_seconds}LL - $split_days * 24 * 3600)"
date_format='+%Y-%m-%dT%H:%M:%SZ'
# Print the full NTP interval if a suitable date is found
if [ "x`date -u -d '1970-01-01 UTC 9 days ago 5 seconds 3 seconds' \
$date_format 2> /dev/null`" = "x1969-12-23T00:00:08Z" ]
then
time1="`date -u -d "1970-01-01 UTC $split_days days ago $split_seconds seconds" \
$date_format`"
time2="`date -u -d "1970-01-01 UTC $split_days days ago $split_seconds seconds 4294967296 seconds" \
$date_format`"
echo "NTP time mapped to $time1/$time2"
fi
fi
MATHCODE='return (int) pow(2.0, log(sqrt((double)argc)));'
if test_code 'math' 'math.h' '' '' "$MATHCODE"; then
LIBS=""
@@ -324,17 +423,17 @@ else
if test_code 'math in -lm' 'math.h' '' '-lm' "$MATHCODE"; then
LIBS="-lm"
else
printf "Can't compile/link a program which uses sqrt(), log(), pow(), bailing out\n"
echo "Can't compile/link a program which uses sqrt(), log(), pow(), bailing out"
exit 1
fi
fi
if test_code '<stdint.h>' 'stdint.h' '' '' ''; then
SYSDEFS="${SYSDEFS} -DHAS_STDINT_H"
add_def HAS_STDINT_H
fi
if test_code '<inttypes.h>' 'inttypes.h' '' '' ''; then
SYSDEFS="${SYSDEFS} -DHAS_INTTYPES_H"
add_def HAS_INTTYPES_H
fi
if [ $feat_ipv6 = "1" ] && \
@@ -344,17 +443,57 @@ if [ $feat_ipv6 = "1" ] && \
n.sin6_addr = in6addr_any;
return !inet_ntop(AF_INET6, &n.sin6_addr.s6_addr, p, sizeof(p));'
then
SYSDEFS="${SYSDEFS} -DHAVE_IPV6"
add_def HAVE_IPV6
if test_code 'in6_pktinfo' 'sys/socket.h netinet/in.h' '' '' '
return sizeof(struct in6_pktinfo);'
then
add_def HAVE_IN6_PKTINFO
else
if test_code 'in6_pktinfo with _GNU_SOURCE' 'sys/socket.h netinet/in.h' \
'-D_GNU_SOURCE' '' 'return sizeof(struct in6_pktinfo);'
then
add_def _GNU_SOURCE
add_def HAVE_IN6_PKTINFO
fi
fi
fi
if [ $feat_pps = "1" ] && \
test_code 'PPS API' 'timepps.h' '' '' '
pps_handle_t h;
if test_code 'getaddrinfo()' 'sys/types.h sys/socket.h netdb.h' '' '' \
'return getaddrinfo(0, 0, 0, 0);'
then
add_def HAVE_GETADDRINFO
fi
if [ $feat_asyncdns = "1" ] && \
test_code 'pthread' 'pthread.h' '-pthread' '' \
'return pthread_create((void *)1, NULL, (void *)1, NULL);'
then
add_def FEAT_ASYNCDNS
add_def USE_PTHREAD_ASYNCDNS
MYCFLAGS="$MYCFLAGS -pthread"
fi
timepps_h=""
if [ $feat_pps = "1" ]; then
if test_code '<sys/timepps.h>' 'sys/timepps.h' '' '' ''; then
timepps_h="sys/timepps.h"
add_def HAVE_SYS_TIMEPPS_H
else
if test_code '<timepps.h>' 'timepps.h' '' '' ''; then
timepps_h="timepps.h"
add_def HAVE_TIMEPPS_H
fi
fi
fi
if [ "x$timepps_h" != "x" ] && \
test_code 'PPSAPI' "string.h $timepps_h" '' '' '
pps_handle_t h = 0;
pps_info_t i;
struct timespec ts;
return time_pps_fetch(&h, PPS_TSFMT_TSPEC, &i, &ts);'
return time_pps_fetch(h, PPS_TSFMT_TSPEC, &i, &ts);'
then
SYSDEFS="${SYSDEFS} -DHAVE_PPSAPI"
add_def HAVE_PPSAPI
fi
if [ $feat_linuxcaps = "1" ] && [ $try_linuxcaps = "1" ] && \
@@ -364,8 +503,32 @@ if [ $feat_linuxcaps = "1" ] && [ $try_linuxcaps = "1" ] && \
'' '-lcap' \
'prctl(PR_SET_KEEPCAPS, 1);cap_set_proc(cap_from_text("cap_sys_time=ep"));'
then
EXTRA_DEFS="${EXTRA_DEFS} -DFEAT_LINUXCAPS=1"
EXTRA_LIBS="-lcap"
add_def FEAT_LINUXCAPS
EXTRA_LIBS="$EXTRA_LIBS -lcap"
fi
if [ $feat_rtc = "1" ] && [ $try_rtc = "1" ] && \
test_code '<linux/rtc.h>' 'sys/ioctl.h linux/rtc.h' '' '' \
'ioctl(1, RTC_UIE_ON&RTC_UIE_OFF&RTC_RD_TIME&RTC_SET_TIME, 0&RTC_UF);'
then
EXTRA_OBJECTS="$EXTRA_OBJECTS rtc_linux.o"
add_def FEAT_RTC
fi
if [ $feat_phc = "1" ] && [ $try_phc = "1" ] && \
test_code '<linux/ptp_clock.h>' 'sys/ioctl.h linux/ptp_clock.h' '' '' \
'ioctl(1, PTP_CLOCK_GETCAPS, 0);'
then
if test_code 'clock_gettime()' 'time.h' '' '' 'clock_gettime(0, NULL);'; then
add_def FEAT_PHC
else
if test_code 'clock_gettime() in -lrt' 'time.h' '' '-lrt' \
'clock_gettime(0, NULL);'
then
EXTRA_LIBS="$EXTRA_LIBS -lrt"
add_def FEAT_PHC
fi
fi
fi
if [ $try_setsched = "1" ] && \
@@ -376,7 +539,7 @@ if [ $try_setsched = "1" ] && \
sched_get_priority_max(SCHED_FIFO);
sched_setscheduler(0, SCHED_FIFO, &sched);'
then
SYSDEFS="${SYSDEFS} -DHAVE_SCHED_SETSCHEDULER"
add_def HAVE_SCHED_SETSCHEDULER
fi
if [ $try_lockmem = "1" ] && \
@@ -387,7 +550,12 @@ if [ $try_lockmem = "1" ] && \
setrlimit(RLIMIT_MEMLOCK, &rlim);
mlockall(MCL_CURRENT|MCL_FUTURE);'
then
SYSDEFS="${SYSDEFS} -DHAVE_MLOCKALL"
add_def HAVE_MLOCKALL
fi
if [ $feat_forcednsretry = "1" ]
then
add_def FORCE_DNSRETRY
fi
READLINE_COMPILE=""
@@ -398,20 +566,68 @@ if [ $feat_readline = "1" ]; then
"$readline_inc" "$readline_lib -ledit" \
'add_history(readline("prompt"));'
then
READLINE_COMPILE="-DFEAT_READLINE=1 -DUSE_EDITLINE=1 $readline_inc"
add_def FEAT_READLINE
add_def USE_EDITLINE
READLINE_COMPILE="$readline_inc"
READLINE_LINK="$readline_lib -ledit"
fi
fi
if [ "x$READLINE_LINK" = "x" ] && [ $try_readline = "1" ]; then
if test_code readline 'stdio.h readline/readline.h readline/history.h' \
"$readline_inc" "$readline_lib -lreadline" \
'add_history(readline("prompt"));'
then
add_def FEAT_READLINE
READLINE_COMPILE="$readline_inc"
READLINE_LINK="$readline_lib -lreadline"
fi
fi
if [ "x$READLINE_LINK" = "x" ] && [ $try_readline = "1" ]; then
if test_code 'readline with -lncurses' \
'stdio.h readline/readline.h readline/history.h' \
"$readline_inc" "$readline_lib $ncurses_lib -lreadline -lncurses" \
'add_history(readline("prompt"));'
then
READLINE_COMPILE="-DFEAT_READLINE=1 $readline_inc"
add_def FEAT_READLINE
READLINE_COMPILE="$readline_inc"
READLINE_LINK="$readline_lib $ncurses_lib -lreadline -lncurses"
fi
fi
EXTRA_CLI_LIBS="$EXTRA_CLI_LIBS $READLINE_LINK"
fi
HASH_OBJ="hash_intmd5.o"
HASH_COMPILE=""
HASH_LINK=""
if [ $try_nss = "1" ]; then
test_cflags="`pkg-config --cflags nss 2> /dev/null`"
test_link="`pkg-config --libs-only-L nss 2> /dev/null` -lfreebl3"
if test_code 'NSS' 'nss.h hasht.h nsslowhash.h' \
"$test_cflags" "$test_link" \
'NSSLOWHASH_Begin(NSSLOWHASH_NewContext(NSSLOW_Init(), HASH_AlgSHA512));'
then
HASH_OBJ="hash_nss.o"
HASH_COMPILE="$test_cflags"
HASH_LINK="$test_link"
LIBS="$LIBS $HASH_LINK"
add_def GENERATE_SHA1_KEY
fi
fi
if [ "x$HASH_LINK" = "x" ] && [ $try_tomcrypt = "1" ]; then
if test_code 'tomcrypt' 'tomcrypt.h' '-I/usr/include/tomcrypt' '-ltomcrypt' \
'hash_memory_multi(find_hash("md5"), NULL, NULL, NULL, 0, NULL, 0);'
then
HASH_OBJ="hash_tomcrypt.o"
HASH_COMPILE="-I/usr/include/tomcrypt"
HASH_LINK="-ltomcrypt"
LIBS="$LIBS $HASH_LINK"
add_def GENERATE_SHA1_KEY
fi
fi
SYSCONFDIR=/etc
@@ -459,26 +675,52 @@ if [ "x$SETDOCDIR" != "x" ]; then
DOCDIR=$SETDOCDIR
fi
sed -e "s%@EXTRA_OBJECTS@%${EXTRA_OBJECTS}%;\
s%@CC@%${MYCC}%;\
s%@CFLAGS@%${MYCFLAGS}%;\
s%@CCWARNFLAGS@%${CCWARNFLAGS}%;\
s%@CPPFLAGS@%${CPPFLAGS}%;\
s%@LIBS@%${LIBS}%;\
s%@LDFLAGS@%${LDFLAGS}%;\
s%@EXTRA_LIBS@%${EXTRA_LIBS}%;\
s%@SYSDEFS@%${SYSDEFS}%;\
s%@EXTRA_DEFS@%${EXTRA_DEFS}%;\
s%@EXTRA_CLI_LIBS@%${EXTRA_CLI_LIBS}%;\
s%@READLINE_COMPILE@%${READLINE_COMPILE}%;\
s%@READLINE_LINK@%${READLINE_LINK}%;\
s%@SYSCONFDIR@%${SYSCONFDIR}%;\
s%@BINDIR@%${BINDIR}%;\
s%@SBINDIR@%${SBINDIR}%;\
s%@DOCDIR@%${DOCDIR}%;\
s%@MANDIR@%${MANDIR}%;\
s%@INFODIR@%${INFODIR}%;"\
< Makefile.in > Makefile
LOCALSTATEDIR=/var
if [ "x$SETLOCALSTATEDIR" != "x" ]; then
LOCALSTATEDIR=$SETLOCALSTATEDIR
fi
CHRONYVARDIR=${LOCALSTATEDIR}/lib/chrony
if [ "x$SETCHRONYVARDIR" != "x" ]; then
CHRONYVARDIR=$SETCHRONYVARDIR
fi
add_def DEBUG $debug
add_def DEFAULT_CONF_FILE "\"$SYSCONFDIR/chrony.conf\""
add_def DEFAULT_USER "\"$default_user\""
add_def MAIL_PROGRAM "\"$mail_program\""
if [ -f version.txt ]; then
add_def CHRONY_VERSION "\"`cat version.txt`\""
else
add_def CHRONY_VERSION "\"DEVELOPMENT\""
fi
for f in Makefile chrony.conf.5 chrony.texi chronyc.1 chronyd.8
do
echo Creating $f
sed -e "s%@EXTRA_OBJECTS@%${EXTRA_OBJECTS}%;\
s%@CC@%${MYCC}%;\
s%@CFLAGS@%${MYCFLAGS}%;\
s%@CPPFLAGS@%${MYCPPFLAGS}%;\
s%@LIBS@%${LIBS}%;\
s%@LDFLAGS@%${MYLDFLAGS}%;\
s%@EXTRA_LIBS@%${EXTRA_LIBS}%;\
s%@EXTRA_CLI_LIBS@%${EXTRA_CLI_LIBS}%;\
s%@READLINE_COMPILE@%${READLINE_COMPILE}%;\
s%@HASH_OBJ@%${HASH_OBJ}%;\
s%@HASH_COMPILE@%${HASH_COMPILE}%;\
s%@SYSCONFDIR@%${SYSCONFDIR}%;\
s%@BINDIR@%${BINDIR}%;\
s%@SBINDIR@%${SBINDIR}%;\
s%@DOCDIR@%${DOCDIR}%;\
s%@MANDIR@%${MANDIR}%;\
s%@INFODIR@%${INFODIR}%;\
s%@LOCALSTATEDIR@%${LOCALSTATEDIR}%;\
s%@CHRONYVARDIR@%${CHRONYVARDIR}%;\
s%@DEFAULT_USER@%${default_user}%;"\
< ${f}.in > $f
done
# =======================================================================
# vim:et:sw=2:ht=2:sts=2:fdm=marker:cms=#%s

View File

@@ -40,21 +40,21 @@
# more 'NTP servers'. You will probably find that your Internet Service
# Provider or company have one or more NTP servers that you can specify.
# Failing that, there are a lot of public NTP servers. There is a list
# you can access at
# http://www.eecis.udel.edu/~mills/ntp/servers.htm.
# you can access at http://support.ntp.org/bin/view/Servers/WebHome or
# you can use servers from the pool.ntp.org project.
! server ntp0.your-isp.com
! server ntp1.your-isp.com
! server ntp.public-server.org
! server 0.pool.ntp.org iburst
! server 1.pool.ntp.org iburst
! server 2.pool.ntp.org iburst
# However, for dial-up use you probably want these instead. The word
# 'offline' means that the server is not visible at boot time. Use
# chronyc's 'online' command to tell chronyd that these servers have
# become visible after you go on-line.
! server ntp0.your-isp.com offline
! server ntp1.your-isp.com offline
! server ntp.public-server.org offline
! server 0.pool.ntp.org offline
! server 1.pool.ntp.org offline
! server 2.pool.ntp.org offline
# You may want to specify NTP 'peers' instead. If you run a network
# with a lot of computers and want several computers running chrony to
@@ -89,7 +89,7 @@
# immediately so that it doesn't gain or lose any more time. You
# generally want this, so it is uncommented.
driftfile /etc/chrony.drift
driftfile /var/lib/chrony/drift
# If you want to use the program called chronyc to configure aspects of
# chronyd's operation once it is running (e.g. tell it the Internet link
@@ -106,6 +106,9 @@ keyfile /etc/chrony.keys
commandkey 1
# With this directive a random password will be generated automatically.
generatecommandkey
# chronyd can save the measurement history for the servers to files when
# it it exits. This is useful in 2 situations:
#
@@ -122,7 +125,7 @@ commandkey 1
# Enable these two options to use this.
! dumponexit
! dumpdir /var/log/chrony
! dumpdir /var/lib/chrony
# chronyd writes its process ID to a file. If you try to start a second
# copy of chronyd, it will detect that the process named in the file is
@@ -133,17 +136,16 @@ commandkey 1
#######################################################################
### INITIAL CLOCK CORRECTION
# This option is only useful if your NTP servers are visible at boot
# time. This probably means you are on a LAN. If so, the following
# option will choose the best-looking of the servers and correct the
# system time to that. The value '10' means that if the error is less
# This option is useful to quickly correct the clock on start if it's
# off by a large amount. The value '10' means that if the error is less
# than 10 seconds, it will be gradually removed by speeding up or
# slowing down your computer's clock until it is correct. If the error
# is above 10 seconds, an immediate time jump will be applied to correct
# it. Some software can get upset if the system clock jumps (especially
# backwards), so be careful!
# it. The value '1' means the step is allowed only on the first update
# of the clock. Some software can get upset if the system clock jumps
# (especially backwards), so be careful!
! initstepslew 10 ntp0.your-company.com ntp1.your-company.com ntp2.your-company.com
! makestep 10 1
#######################################################################
### LOGGING
@@ -255,13 +257,6 @@ commandkey 1
# put into chronyc to allow you to modify chronyd's parameters. By
# default all you can do is view information about chronyd's operation.
# Some people have reported that the need the following line to allow
# chronyc to work even on the same machine. This should not be
# necessary, and the problem is being investigated. You can leave this
# line enabled, as it's benign otherwise.
cmdallow 127.0.0.1
#######################################################################
### REAL TIME CLOCK
# chronyd can characterise the system's real-time clock. This is the
@@ -273,7 +268,7 @@ cmdallow 127.0.0.1
# You need to have 'enhanced RTC support' compiled into your Linux
# kernel. (Note, these options apply only to Linux.)
! rtcfile /etc/chrony.rtc
! rtcfile /var/lib/chrony/rtc
# Your RTC can be set to keep Universal Coordinated Time (UTC) or local
# time. (Local time means UTC +/- the effect of your timezone.) If you

View File

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

View File

@@ -1,27 +1,29 @@
#######################################################################
# $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,
# you will require a single key (the 'commandkey') so that you can supply a
# password to chronyc to enable you to modify chronyd's operation whilst it is
# running.
# after editing it to set up the key(s) you want to use. It should be readable
# only by root or the user chronyd drops the root privileges to. In most
# situations, you will require a single key (the 'commandkey') so that you can
# supply a password to chronyc to enable you to modify chronyd's operation
# whilst it is running.
#
# Copyright 2002 Richard P. Curnow
#
#######################################################################
# A valid key line looks like this
######################################################################
1 a_key
# Examples of valid keys:
# It must consist of an integer, followed by whitespace, followed by a block of
# text with no spaces in it. (You cannot put a space in a key). If you wanted
# to use the above line as your commandkey (i.e. chronyc password), you would
# put the following line into chrony.conf (remove the # from the start):
#1 ALongAndRandomPassword
#2 MD5 HEX:B028F91EA5C38D06C2E140B26C7F41EC
#3 SHA1 HEX:1DC764E0791B11FA67EFC7ECBC4B0D73F68A070C
# commandkey 1
# The keys should be random for maximum security. If you wanted to use a key
# with ID 1 as your commandkey (i.e. chronyc password) you would put
# "commandkey 1" into chrony.conf. If no commandkey is present in the keys
# file and the generatecommandkey directive is specified in chrony.conf,
# a random commandkey will be generated and added to the keys file
# automatically on chronyd start.
# You might want to define more keys if you use the MD5 authentication facility
# You might want to define more keys if you use the authentication facility
# in the network time protocol to authenticate request/response packets between
# trusted clients and servers.

366
faq.txt
View File

@@ -1,366 +0,0 @@
@@PROLOGUE
<html>
<head>
<title>Frequently asked questions</title>
<meta name="description" content="Chrony FAQ (frequently asked questions)">
<meta name="keywords" content="chrony,network time protocol,NTP,RFC 1305,dial-up connection,real time clock,RTC,Linux,FAQ,frequently asked questns">
<?php
$root = ".";
include "$root/styles.php";
?>
</head>
<body>
<?php
include 'main_banner.php';
include 'header.php';
?>
<?php pretty_h1("Introduction") ?>
<p>
This is a set of questions and answers to common problems and issues.
<p>
As we receive more emails about the software, we will add new questions
to this page.
<hr>
<p>
The developers can be reached via the chrony-dev mailing list. See
<a href="#question_1.4">question 1.4.</a> for details.
<hr>
<br clear=all>
@@ENDPROLOGUE
S: Administrative issues
Q: Where can I get chrony source code?
Tarballs are available via the <b>Download</b> link on the Chrony
Web site. For the current development from the developers' version control
system see the <b>Git</b> link on the Web site.
Q: Are there any packaged versions of chrony?
We are aware of packages for Debian, Fedora, Gentoo, Mandriva, Slackware,
and Ubuntu. We are not involved with how these are built or distributed.
Q: Where is the home page?
It is currently at <a href="http://chrony.tuxfamily.org/">http://chrony.tuxfamily.org/</a>.
Q: Is there a mailing list?
Yes, it's currently at chrony-users@chrony.tuxfamily.org. There is a low-volume
list called chrony-announce which is just for announcements of new releases or
similar matters of high importance. You can join the lists by sending a
message with the subject subscribe to <a href="mailto:chrony-users-request@chrony.tuxfamily.org">chrony-users-request@chrony.tuxfamily.org</a> or
<a href="mailto:chrony-announce-request@chrony.tuxfamily.org">chrony-announce-request@chrony.tuxfamily.org</a> respectively.
For those who want to contribute to the development of chrony, there is a
developers' mailing list. You can subscribe by sending mail with the
subject subscribe to
<a href="mailto:chrony-dev-request@chrony.tuxfamily.org">chrony-dev-request@chrony.tuxfamily.org</a>.
Q: What licence is applied to chrony?
Starting from version 1.15, chrony is licensed under the GNU General Public
License, Version 2. Versions prior to 1.15 were licensed under a custom BSD-like
license.
S: Chrony compared to other programs
Q: How does chrony compare to xntpd?
If your computer is permenently connected, or connected for long periods (that
is, for the several hours it takes xntpd to settle down), or you need to
support hardware reference clocks to your computer, then xntpd will work fine.
Apart from not supporting hardware clocks, chrony will work fine too.
If your computer connects to the 'net for 5 minutes once a day (or something
like that), or you turn your (Linux v2.0) computer off when you're not using
it, or you want to use NTP on an isolated network with no hardware clocks in
sight, chrony will work much better for you.
The reason I wrote chrony was that I could not get xntpd to do
anything sensible on my PC at home, which is connected to the 'net for
about 5 minutes once or twice a day, mainly to upload/download email
and news. Nowadays it is also turned off for 22-23 hours a day, when
not in use. I wanted a program which would :
- slew the time to correct it when I go online and NTP servers become visible
- determine the rate at which the computer gains or loses time and use this
information to keep it reasonably correct between connects to the 'net. This
has to be done using a method that does not care about the intermittent
availability of the references or the fact the computer is turned off between
groups of measurements..
- maintain the time across reboots, by working out the error and drift rate of
the computer's real-time clock and using this information to set the system
clock correctly at boot up. (In the last few months, it became impossible for
me to leave my computer powered permanently.)
Also, when working with isolated networks with no true time references
at all, I found xntpd gave me no help with managing the local clock's
gain/loss rate on the NTP master node (which I set from my watch). I
added some automated support in chrony to deal with this.
S: Compilation issues
Q:How do I apply source patches?
Sometimes we release source patches rather than a full version when we need to
provide a fix for small problems. Supposing you have chrony-1.X.tar.gz and a
source patch chrony-1.X-1.X.1.gz. The steps required are:
tar xzvf ../chrony-1.X.tar.gz
cd chrony-1.X
gunzip < ../../chrony-1.X-1.X.1.gz | patch -p1
./configure
make
make install
Q:Can I compile chrony with an ANSI-C compiler that is not GCC v2.x?
I have had reports that chrony can be compiled with GCC v1.42, by using the
following trick when running make
make CC='gcc -D__FUNCTION__=\"function_not_available\"'
(this gets around the lack of a __FUNCTION__ macro in GCC v1.)
The same trick may be enough to allow other compilers to be used.
Q: I get errors like 'client.c:44: readline/readline.h: file not found'
Read the section about 'readline' in the INSTALL file or in chrony.txt. You
may need to disable readline support (e.g. if you haven't got readline
installed at all, or just don't want it), or specify the location of the
readline files (e.g. if you've installed them in a non-standard place).
Q: I have RedHat 7.3 and can't compile rtc_linux.c (error in spinlock.h)
The following solution has been found for this. Enter the following 3 commands
(as root):
cd /usr/include/
mv linux linux.rh
ln -s /usr/src/linux/include/linux ./linux
The problem seems to be that RedHat provide their own kernel header files in
/usr/include/linux. Besides differing from those used by your current kernel,
if you compiled it yourself, they also seem to have been changed in a way that
causes a problem compiling chrony. Chrony compiles fine with standard kernel
header files.
There have also been reports that just replacing the file
/usr/src/linux/spinlock.h by the equivalent file from a vanilla kernel source
tree is sufficient to fix the problem.
Note : from version 1.21 onwards, this problem no longer exists. The kernel
header files are no longer included.
S: Selection of NTP servers
Q: I have several computers on a LAN. Should I make one the master, or make them all clients of an external server?
I think the best configuration is to make one computer the master, with the
others as clients of it. Add a 'local' directive to the master's chrony.conf
file. This configuration will be better because
* the load on the external connection is less
* the load on the external NTP server(s) is less
* if your external connection goes down, the computers on the LAN will maintain
a common time with each other.
S: Addressing issues
Q: I get the following error message : "Could not get IP adress for localhost"
Add a line like the following to your /etc/hosts file
127.0.0.1 localhost
Q: I have problems if I put the names of my NTP servers in the chrony.conf file.
If you have no connection to the Internet at boot time, chrony won't be able to
turn the names into IP addresses when it starts. There seem to be 2 solutions:
1. Put the numeric IP addresses in the chrony.conf file
or
2. Put the server->IP address mappings in your /etc/hosts file and ensure that
/etc/host.conf reads 'order hosts,bind'.
The problem is that chronyd (currently) isn't designed in a way that allows
hostname->IP address lookups during normal operation. I hope to work on this
problem very soon.
S: My computer is not synchronising.
This is the most common problem. There are a number of reasons, see the
following questions.
Q: Behind a firewall?
If there is a firewall between you and the NTP server you're trying to use,
the packets may be blocked. Try using a tool like etherfind or tcpdump to see
if you're getting responses from the server. If you have an external modem,
see if the receive light blinks straight after the transmit light (when the
link is quiet apart from the NTP traffic.) Try adding 'log measurements' to
the chrony.conf file and look in the measurements.log file after chrony has
been running for a short period. See if any measurements appear.
Most people run chronyd on the firewall itself, to avoid all issues of UDP
packet forwarding and/or masquerading.
Q: Do you have a non-permanant (i.e. intermittent) Internet connection?
Check that you're using chronyc's 'online' and 'offline' commands
appropriately. Again, check in measurements.log to see if you're getting any
data back from the server.
Q: In measurements.log, do the '7' and '8' flag columns always show zero?
Do you have a 'local stratum X' directive in the chrony.conf file? If X is
lower than the stratum of the server you're trying to use, this situation will
arise. You should always make X quite high (e.g. 10) in this directive.
S: Issues with chronyd
Q: chronyd crashes after a syslog message "adjtimex failed for set frequency"
The usual cause is that the kernel is running with a different value of 'HZ'
(the timer interrupt rate) than the value that was found in the kernel header
files when chrony was compiled. The chrony.conf file can include options to
modify the HZ value (see the discussion of linux_hz and linux_freq_scale in the
documentation), however the problem is to find the value of HZ being used.
S: Issues with chronyc
Q: I keep getting the error '510 No command access from this host --- Reply not authenticated'.
Make sure that the chrony.conf file (on the computer where chronyd is running)
has a 'cmdallow' entry for the computer you are running chronyc on. This
shouldn't be necessary for localhost, but some people still seem to need an
entry like 'cmdallow 127.0.0.1'. (It would be good to understand why problem
only affects some people).
Q: I cannot log in from chronyc to carry out privileged tasks.
This is the second most common problem.
Perhaps your /etc/chrony.keys file is badly formatted. Make sure that the
final line has a line feed at the end, otherwise the key on that line will work
as though the last character is missing. (Note, this bug was fixed in version
1.16.)
Q: When I enter a command and hit &lt;Return&gt;, chronyc hangs
This probably means that chronyc cannot communicate with chronyd.
Perhaps chronyd is not running. Try using the ps command (e.g. on Linux, 'ps
-auxw') to see if it's running. Or try 'netstat -a' and see if the ports
123/udp and 323/udp are listening. If chronyd is not running, you may have a
problem with the way you are trying to start it (e.g. at boot time).
Perhaps you have a firewall set up in a way that blocks packets on port
323/udp. You need to amend the firewall configuration in this case.
Q: Is the chronyc&lt;-&gt;chronyd protocol documented anywhere?
Only by the source code :-) See cmdmon.c (chronyd side) and client.c (chronyc
side).
S: Real-time clock issues.
Q: What is the real-time clock (RTC)?
This is the clock which keeps the time even when your computer is turned off.
It works with 1 second resolution. chronyd can monitor the rate at which the
real-time clock gains or loses time, and compensate for it when you set the
system time from it at the next reboot. See the documentation for details.
Q: I want to use chronyd's real-time clock support. Must I disable hwclock?
The hwclock program is often set-up by default in the boot and shutdown scripts
with many Linux installations. If you want to use chronyd's real-time clock
support, the important thing is to disable hwclock in the <b>shutdown</b>
procedure. If you don't, it will over-write the RTC with a new value, unknown
to chronyd. At the next reboot, chronyd will compensate this (wrong) time with
its estimate of how far the RTC has drifted whilst the power was off, giving a
meaningless initial system time.
There is no need to remove hwclock from the boot process, as long as chronyd is
started after it has run.
Q: I just keep getting the '513 RTC driver not running' message
For the real time clock support to work, you need the following three things:
* a kernel that is supported (e.g. 2.2 onwards)
* enhanced RTC support compiled into the kernel
* an 'rtcfile' directive in your chrony.conf file.
S: Problems with isolated networks.
Q: When I use the 'settime' command, chronyd crashes.
If you enter times that are too far away from the real time, chronyd will
think the system clock runs fast or slow by an excessive amount. The required
compensation factor will be outside the bounds for the adjtimex() system call.
chronyd will crash when it tries to apply such an excessive adjustment.
S: Microsoft Windows
Q: Does chrony support Windows?
No. The chronyc program (the command-line client used for configuring
chronyd while it is running) has been successfully built and run under Cygwin
in the past. chronyd is not portable, because part of it is very
system-dependent. It needs adapting to work with Windows' equivalent of the
adjtimex() call, and it needs to be made to work as an NT service.
Q: Are there any plans to support Windows?
We have no plans to do this. Anyone is welcome to pick this work up and
contribute it back to the project.
Q: What alternative NTP clients are there for Windows?
Some of the names we've seen mentioned are
- Automachron
- NetTime (nettime.sourceforge.net)
S: NTP-specific issues
Q: Can chrony be driven from broadcast NTP servers?
No. I remember looking at how they worked when I was first writing chrony.
Since the 'target market' then was dial-up systems, broadcast packets were not
relevant so I didn't bother working out how to deal with the complexities of
doing the delay estimation.
I no longer have root access to a LAN environment to develop and test broadcast
server support. Neither have I the time to work on this. I would be very
happy to accept a patch from anyone who can develop, test and debug the
necessary changes!
Q: Can chronyd transmit broadcast NTP packets (e.g. to synchronise other computers on a private LAN)?
Yes. Starting from version 1.17, chrony has this capability.
Q: Can chrony keep the system clock a fixed offset away from real time?
I have not experimented much, but I don't believe this would be possible as
the program currently stands.
Q: What happens if the network connection is dropped without using chronyc's 'offline' command first?
In this case chronyd will keep trying to access the server(s) that it thinks
are online. Eventually it will decide that they are unreachable and no longer
consider itself synchronised to them. If you have other computers on your LAN
accessing the computer that is affected this way, they too will become
'unsynchronised', unless you have the 'local' directive set up on the master
computer.
The 'auto_offline' option to the 'server' entry in the chrony.conf file may be
useful to avoid this situation.
S: Development
Q: Can I get the source via git from anywhere?
Yes. See the Git link at <a
href="http://chrony.tuxfamily.org/">http://chrony.tuxfamily.org</a> for
information.
S: Linux-specific issues
Q: Why does the source code include kernel header files?
The program needs to see the definitions of structures used to interact with
the real time clock (via /dev/rtc) and with the adjtimex() system call. Sadly
this has led to a number of compilation problems with newer kernels which have
been increasingly hard to fix in a way that makes the code compilable on all
Linux kernel versions (from 2.0 up anyway, I doubt 1.x still works.) Hopefully
the situation will not deteriorate further with future kernel versions.
Q: I get "Could not open /dev/rtc, Device or resource busy" in my syslog file.
Check that you haven't accidentally got two copies of chronyd running (perhaps
defined in different start-up scripts.)
S: Solaris-specific issues
Q: On Solaris 2.8, I get an error message about not being able to open kvm to change dosynctodr.
(The dosynctodr variable controls whether Solaris couples the equivalent of its
BIOS clock into its system clock at regular intervals). The Solaris port of
chrony was developed in the Solaris 2.5 era. Some aspect of the Solaris kernel
has changed which prevents the same technique working. I no longer have root
access to any Solaris machines to work on this, and am reliant on somebody
developing the patch and testing it. A good starting point would be to see if
xntpd has been modified to work for Solaris 2.8.
@@EPILOGUE
<hr>
Back to
<a href="mailto:rc@rc0.org.uk?subject=chrony">the author</a>'s
<a href="http://www.rc0.org.uk/">main page</a>
</body>
</html>
@@ENDEPILOGUE

140
faqgen.pl
View File

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

862
getdate.c

File diff suppressed because it is too large Load Diff

41
hash.h Normal file
View File

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

View File

@@ -1,12 +1,8 @@
/*
$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.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2002
* Copyright (C) Miroslav Lichvar 2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -25,25 +21,44 @@
=======================================================================
Header file for acquisition module
Routines implementing crypto hashing using internal MD5 implementation.
*/
#ifndef GOT_ACQUIRE_H
#define GOT_ACQUIRE_H
#include "config.h"
#include "sysincl.h"
#include "hash.h"
#include "memory.h"
#include "addressing.h"
#include "md5.c"
typedef struct ACQ_SourceRecord *ACQ_Source;
static MD5_CTX ctx;
extern void ACQ_Initialise(void);
int
HSH_GetHashId(const char *name)
{
/* only MD5 is supported */
if (strcmp(name, "MD5"))
return -1;
extern void ACQ_Finalise(void);
return 0;
}
extern void ACQ_StartAcquisition(int n, IPAddr *ip_addrs, int init_slew_threshold,
void (*after_hook)(void *), void *anything);
unsigned int
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
const unsigned char *in2, unsigned int in2_len,
unsigned char *out, unsigned int out_len)
{
if (out_len < 16)
return 0;
extern void ACQ_AccumulateSample(ACQ_Source acq_source, double offset, double root_distance);
MD5Init(&ctx);
MD5Update(&ctx, in1, in1_len);
if (in2)
MD5Update(&ctx, in2, in2_len);
MD5Final(&ctx);
extern void ACQ_MissedSample(ACQ_Source acq_source);
memcpy(out, ctx.digest, 16);
#endif /* GOT_ACQUIRE_H */
return 16;
}

89
hash_nss.c Normal file
View File

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

116
hash_tomcrypt.c Normal file
View File

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

View File

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

345
keys.c
View File

@@ -1,12 +1,9 @@
/*
$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.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2012-2014
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -29,18 +26,25 @@
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
#include "sysincl.h"
#include "keys.h"
#include "cmdparse.h"
#include "conf.h"
#include "memory.h"
#include "util.h"
#include "local.h"
#include "logging.h"
typedef struct {
unsigned long id;
char *val;
int len;
int hash_id;
int auth_delay;
} Key;
#define MAX_KEYS 256
@@ -49,13 +53,71 @@ static int n_keys;
static Key keys[MAX_KEYS];
static int command_key_valid;
static int command_key_pos;
static int command_key_id;
static int cache_valid;
static unsigned long cache_key_id;
static int cache_key_pos;
/* ================================================== */
static int
generate_key(unsigned long key_id)
{
#ifdef GENERATE_SHA1_KEY
unsigned char key[20];
const char *hashname = "SHA1";
#else
unsigned char key[16];
const char *hashname = "MD5";
#endif
const char *key_file, *rand_dev = "/dev/urandom";
FILE *f;
struct stat st;
int i;
key_file = CNF_GetKeysFile();
if (!key_file)
return 0;
f = fopen(rand_dev, "r");
if (!f || fread(key, sizeof (key), 1, f) != 1) {
if (f)
fclose(f);
LOG_FATAL(LOGF_Keys, "Could not read %s", rand_dev);
return 0;
}
fclose(f);
f = fopen(key_file, "a");
if (!f) {
LOG_FATAL(LOGF_Keys, "Could not open keyfile %s for writing", key_file);
return 0;
}
/* Make sure the keyfile is not world-readable */
if (stat(key_file, &st) || chmod(key_file, st.st_mode & 0770)) {
fclose(f);
LOG_FATAL(LOGF_Keys, "Could not change permissions of keyfile %s", key_file);
return 0;
}
fprintf(f, "\n%lu %s HEX:", key_id, hashname);
for (i = 0; i < sizeof (key); i++)
fprintf(f, "%02hhX", key[i]);
fprintf(f, "\n");
fclose(f);
/* Erase the key from stack */
memset(key, 0, sizeof (key));
LOG(LOGS_INFO, LOGF_Keys, "Generated key %lu", key_id);
return 1;
}
/* ================================================== */
void
KEY_Initialise(void)
{
@@ -63,7 +125,11 @@ KEY_Initialise(void)
command_key_valid = 0;
cache_valid = 0;
KEY_Reload();
return;
if (CNF_GetGenerateCommandKey() && !KEY_KeyKnown(KEY_GetCommandKey())) {
if (generate_key(KEY_GetCommandKey()))
KEY_Reload();
}
}
/* ================================================== */
@@ -71,8 +137,37 @@ KEY_Initialise(void)
void
KEY_Finalise(void)
{
/* Nothing to do */
return;
}
/* ================================================== */
static int
determine_hash_delay(unsigned long key_id)
{
NTP_Packet pkt;
struct timeval before, after;
unsigned long usecs, min_usecs=0;
int i;
for (i = 0; i < 10; i++) {
LCL_ReadRawTime(&before);
KEY_GenerateAuth(key_id, (unsigned char *)&pkt, NTP_NORMAL_PACKET_SIZE,
(unsigned char *)&pkt.auth_data, sizeof (pkt.auth_data));
LCL_ReadRawTime(&after);
usecs = (after.tv_sec - before.tv_sec) * 1000000 + (after.tv_usec - before.tv_usec);
if (i == 0 || usecs < min_usecs) {
min_usecs = usecs;
}
}
/* Add on a bit extra to allow for copying, conversions etc */
min_usecs += min_usecs >> 4;
DEBUG_LOG(LOGF_Keys, "authentication delay for key %lu: %ld useconds", key_id, min_usecs);
return min_usecs;
}
/* ================================================== */
@@ -97,61 +192,84 @@ compare_keys_by_id(const void *a, const void *b)
/* ================================================== */
#define KEYLEN 2047
#define SKEYLEN "2047"
void
KEY_Reload(void)
{
int i, len1;
char *key_file;
int i, line_number;
FILE *in;
unsigned long key_id;
char line[KEYLEN+1], keyval[KEYLEN+1];
char line[2048], *keyval, *key_file;
const char *hashname;
for (i=0; i<n_keys; i++) {
Free(keys[i].val);
}
n_keys = 0;
key_file = CNF_GetKeysFile();
if (key_file) {
in = fopen(key_file, "r");
if (in) {
while (fgets(line, sizeof(line), in)) {
len1 = strlen(line) - 1;
/* Guard against removing last character of the line
* if the last line of the file is missing an end-of-line */
if (line[len1] == '\n') {
line[len1] = '\0';
}
if (sscanf(line, "%lu%" SKEYLEN "s", &key_id, keyval) == 2) {
keys[n_keys].id = key_id;
keys[n_keys].len = strlen(keyval);
keys[n_keys].val = MallocArray(char, 1 + keys[n_keys].len);
strcpy(keys[n_keys].val, keyval);
n_keys++;
}
}
fclose(in);
/* Sort keys into order. Note, if there's a duplicate, it is
arbitrary which one we use later - the user should have been
more careful! */
qsort((void *) keys, n_keys, sizeof(Key), compare_keys_by_id);
}
}
command_key_valid = 0;
cache_valid = 0;
return;
key_file = CNF_GetKeysFile();
line_number = 0;
if (!key_file)
return;
in = fopen(key_file, "r");
if (!in) {
LOG(LOGS_WARN, LOGF_Keys, "Could not open keyfile %s", key_file);
return;
}
while (fgets(line, sizeof (line), in)) {
line_number++;
CPS_NormalizeLine(line);
if (!*line)
continue;
if (!CPS_ParseKey(line, &key_id, &hashname, &keyval)) {
LOG(LOGS_WARN, LOGF_Keys, "Could not parse key at line %d in file %s", line_number, key_file);
continue;
}
keys[n_keys].hash_id = HSH_GetHashId(hashname);
if (keys[n_keys].hash_id < 0) {
LOG(LOGS_WARN, LOGF_Keys, "Unknown hash function in key %lu", key_id);
continue;
}
keys[n_keys].len = UTI_DecodePasswordFromText(keyval);
if (!keys[n_keys].len) {
LOG(LOGS_WARN, LOGF_Keys, "Could not decode password in key %lu", key_id);
continue;
}
keys[n_keys].id = key_id;
keys[n_keys].val = MallocArray(char, keys[n_keys].len);
memcpy(keys[n_keys].val, keyval, keys[n_keys].len);
n_keys++;
}
fclose(in);
/* Sort keys into order. Note, if there's a duplicate, it is
arbitrary which one we use later - the user should have been
more careful! */
qsort((void *) keys, n_keys, sizeof(Key), compare_keys_by_id);
/* Check for duplicates */
for (i = 1; i < n_keys; i++) {
if (keys[i - 1].id == keys[i].id) {
LOG(LOGS_WARN, LOGF_Keys, "Detected duplicate key %lu", keys[i].id);
}
}
/* Erase any passwords from stack */
memset(line, 0, sizeof (line));
for (i=0; i<n_keys; i++) {
keys[i].auth_delay = determine_hash_delay(keys[i].id);
}
}
/* ================================================== */
@@ -174,46 +292,35 @@ lookup_key(unsigned long id)
/* ================================================== */
void
KEY_CommandKey(char **key, int *len)
static int
get_key_pos(unsigned long key_id)
{
unsigned long command_key_id;
int position;
if (!command_key_valid) {
command_key_id = CNF_GetCommandKey();
command_key_pos = lookup_key(command_key_id);
command_key_valid = 1;
if (cache_valid && key_id == cache_key_id)
return cache_key_pos;
position = lookup_key(key_id);
if (position >= 0) {
cache_valid = 1;
cache_key_pos = position;
cache_key_id = key_id;
}
if (command_key_pos >= 0) {
*key = keys[command_key_pos].val;
*len = keys[command_key_pos].len;
} else {
*key = "";
*len = 0;
}
return position;
}
/* ================================================== */
int
KEY_GetKey(unsigned long key_id, char **key, int *len)
unsigned long
KEY_GetCommandKey(void)
{
if (!cache_valid || key_id != cache_key_id) {
cache_valid = 1;
cache_key_pos = lookup_key(key_id);
cache_key_id = key_id;
if (!command_key_valid) {
command_key_id = CNF_GetCommandKey();
}
if (cache_key_pos >= 0) {
*key = keys[cache_key_pos].val;
*len = keys[cache_key_pos].len;
return 1;
} else {
*key = "";
*len = 0;
return 0;
}
return command_key_id;
}
/* ================================================== */
@@ -221,23 +328,59 @@ KEY_GetKey(unsigned long key_id, char **key, int *len)
int
KEY_KeyKnown(unsigned long key_id)
{
int position;
if (cache_valid && (key_id == cache_key_id)) {
return 1;
} else {
position = lookup_key(key_id);
if (position >= 0) {
/* Store key in cache, we will probably be using it in a
minute... */
cache_valid = 1;
cache_key_pos = position;
cache_key_id = key_id;
return 1;
} else {
return 0;
}
}
return get_key_pos(key_id) >= 0;
}
/* ================================================== */
int
KEY_GetAuthDelay(unsigned long key_id)
{
int key_pos;
key_pos = get_key_pos(key_id);
if (key_pos < 0) {
return 0;
}
return keys[key_pos].auth_delay;
}
/* ================================================== */
int
KEY_GenerateAuth(unsigned long key_id, const unsigned char *data, int data_len,
unsigned char *auth, int auth_len)
{
int key_pos;
key_pos = get_key_pos(key_id);
if (key_pos < 0) {
return 0;
}
return UTI_GenerateNTPAuth(keys[key_pos].hash_id,
(unsigned char *)keys[key_pos].val, keys[key_pos].len,
data, data_len, auth, auth_len);
}
/* ================================================== */
int
KEY_CheckAuth(unsigned long key_id, const unsigned char *data, int data_len,
const unsigned char *auth, int auth_len)
{
int key_pos;
key_pos = get_key_pos(key_id);
if (key_pos < 0) {
return 0;
}
return UTI_CheckNTPAuth(keys[key_pos].hash_id,
(unsigned char *)keys[key_pos].val, keys[key_pos].len,
data, data_len, auth, auth_len);
}

12
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.
**********************************************************************
@@ -36,9 +32,15 @@ extern void KEY_Finalise(void);
extern void KEY_Reload(void);
extern void KEY_CommandKey(char **key, int *len);
extern unsigned long KEY_GetCommandKey(void);
extern int KEY_GetKey(unsigned long key_id, char **key, int *len);
extern int KEY_KeyKnown(unsigned long key_id);
extern int KEY_GetAuthDelay(unsigned long key_id);
extern int KEY_GenerateAuth(unsigned long key_id, const unsigned char *data,
int data_len, unsigned char *auth, int auth_len);
extern int KEY_CheckAuth(unsigned long key_id, const unsigned char *data,
int data_len, const unsigned char *auth, int auth_len);
#endif /* GOT_KEYS_H */

292
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, 2014
*
* 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,9 +28,11 @@
They interface with the system specific driver files in sys_*.c
*/
#include <assert.h>
#include <stddef.h>
#include "config.h"
#include "sysincl.h"
#include "conf.h"
#include "local.h"
#include "localp.h"
#include "memory.h"
@@ -45,6 +44,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 +90,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
@@ -100,17 +104,15 @@ static double precision_quantum;
static void
calculate_sys_precision(void)
{
struct timeval tv, old_tv, first_tv;
struct timezone tz;
struct timeval tv, old_tv;
int dusec, best_dusec;
int iters;
gettimeofday(&old_tv, &tz);
first_tv = old_tv;
gettimeofday(&old_tv, NULL);
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,18 +122,19 @@ 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;
/* Get rounded log2 value of the measured precision */
precision_log = 0;
while (best_dusec < 500000) {
while (best_dusec < 707107) {
precision_log--;
best_dusec *= 2;
}
precision_quantum = 1.0 / (double)(1<<(-precision_log));
return;
DEBUG_LOG(LOGF_Local, "Clock precision %.9f (%d)", precision_quantum, precision_log);
}
/* ================================================== */
@@ -153,8 +156,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;
}
/* ================================================== */
@@ -162,7 +168,6 @@ LCL_Initialise(void)
void
LCL_Finalise(void)
{
return;
}
/* ================================================== */
@@ -185,6 +190,14 @@ LCL_GetSysPrecisionAsQuantum(void)
/* ================================================== */
double
LCL_GetMaxClockError(void)
{
return max_clock_error;
}
/* ================================================== */
void
LCL_AddParameterChangeHandler(LCL_ParameterChangeHandler handler, void *anything)
{
@@ -193,7 +206,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);
}
}
@@ -207,14 +220,11 @@ LCL_AddParameterChangeHandler(LCL_ParameterChangeHandler handler, void *anything
new_entry->prev = change_list.prev;
change_list.prev->next = new_entry;
change_list.prev = new_entry;
return;
}
/* ================================================== */
/* Remove a handler */
extern
void LCL_RemoveParameterChangeHandler(LCL_ParameterChangeHandler handler, void *anything)
{
@@ -231,17 +241,35 @@ 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;
ptr->prev->next = ptr->next;
free(ptr);
}
return;
/* ================================================== */
int
LCL_IsFirstParameterChangeHandler(LCL_ParameterChangeHandler handler)
{
return change_list.next->handler == handler;
}
/* ================================================== */
static void
invoke_parameter_change_handlers(struct timeval *raw, struct timeval *cooked,
double dfreq, double doffset,
LCL_ChangeType change_type)
{
ChangeListEntry *ptr;
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
(ptr->handler)(raw, cooked, dfreq, doffset, change_type, ptr->anything);
}
}
/* ================================================== */
@@ -254,7 +282,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);
}
}
@@ -268,8 +296,6 @@ LCL_AddDispersionNotifyHandler(LCL_DispersionNotifyHandler handler, void *anythi
new_entry->prev = dispersion_notify_list.prev;
dispersion_notify_list.prev->next = new_entry;
dispersion_notify_list.prev = new_entry;
return;
}
/* ================================================== */
@@ -292,17 +318,13 @@ 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;
ptr->prev->next = ptr->next;
free(ptr);
return;
}
/* ================================================== */
@@ -312,13 +334,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,39 +345,47 @@ 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);
}
/* ================================================== */
/* This is just a simple passthrough of the system specific routine */
void
LCL_GetOffsetCorrection(struct timeval *raw, double *correction, double *err)
{
/* Call system specific driver to get correction */
(*drv_offset_convert)(raw, correction, err);
}
/* ================================================== */
/* Return current frequency */
double
LCL_ReadAbsoluteFrequency(void)
{
return (*drv_read_freq)();
double freq;
freq = current_freq_ppm;
/* Undo temperature compensation */
if (temp_comp_ppm != 0.0) {
freq = (freq + temp_comp_ppm) / (1.0 - 1.0e-6 * temp_comp_ppm);
}
return freq;
}
/* ================================================== */
@@ -369,25 +395,25 @@ LCL_ReadAbsoluteFrequency(void)
void
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);
}
invoke_parameter_change_handlers(&raw, &cooked, dfreq, 0.0, LCL_ChangeAdjust);
current_freq_ppm = afreq_ppm;
@@ -398,54 +424,45 @@ LCL_SetAbsoluteFrequency(double afreq_ppm)
void
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 += dfreq * (1.0e6 - current_freq_ppm);
/* 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);
}
invoke_parameter_change_handlers(&raw, &cooked, dfreq, 0.0, LCL_ChangeAdjust);
}
/* ================================================== */
void
LCL_AccumulateOffset(double offset)
LCL_AccumulateOffset(double offset, double corr_rate)
{
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);
(*drv_accrue_offset)(offset, corr_rate);
/* 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);
}
invoke_parameter_change_handlers(&raw, &cooked, 0.0, offset, LCL_ChangeAdjust);
}
/* ================================================== */
@@ -453,65 +470,63 @@ LCL_AccumulateOffset(double offset)
void
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);
}
invoke_parameter_change_handlers(&raw, &cooked, 0.0, offset, LCL_ChangeStep);
}
/* ================================================== */
void
LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset)
LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked,
double offset, double dispersion)
{
/* Dispatch to all handlers */
invoke_parameter_change_handlers(raw, cooked, 0.0, offset, LCL_ChangeUnknownStep);
lcl_InvokeDispersionNotifyHandlers(dispersion);
}
/* ================================================== */
void
LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
{
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 += dfreq * (1.0e6 - current_freq_ppm);
#ifdef TRACEON
LOG(LOGS_INFO, LOGF_Local, "old_freq=%.3fppm new_freq=%.3fppm offset=%.6fsec",
DEBUG_LOG(LOGF_Local, "old_freq=%.3fppm new_freq=%.3fppm offset=%.6fsec",
old_freq_ppm, current_freq_ppm, doffset);
#endif
/* Call the system-specific driver for setting the frequency */
(*drv_set_freq)(current_freq_ppm);
(*drv_accrue_offset)(doffset);
current_freq_ppm = (*drv_set_freq)(current_freq_ppm);
dfreq = (current_freq_ppm - old_freq_ppm) / (1.0e6 - old_freq_ppm);
(*drv_accrue_offset)(doffset, corr_rate);
/* 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);
}
invoke_parameter_change_handlers(&raw, &cooked, dfreq, doffset, LCL_ChangeAdjust);
}
/* ================================================== */
@@ -546,34 +561,27 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
current_freq_ppm = (*drv_read_freq)();
#ifdef TRACEON
LOG(LOGS_INFO, LOGF_Local, "Local freq=%.3fppm", current_freq_ppm);
#endif
return;
DEBUG_LOG(LOGF_Local, "Local freq=%.3fppm", current_freq_ppm);
}
/* ================================================== */
/* Look at the current difference between the system time and the NTP
time, and make a step to cancel it if it's larger than the threshold. */
time, and make a step to cancel it. */
int
LCL_MakeStep(double threshold)
LCL_MakeStep(void)
{
struct timeval raw;
double correction;
LCL_ReadRawTime(&raw);
correction = LCL_GetOffsetCorrection(&raw);
if (fabs(correction) <= threshold)
return 0;
LCL_GetOffsetCorrection(&raw, &correction, NULL);
/* Cancel remaining slew and make the step */
LCL_AccumulateOffset(correction);
LCL_AccumulateOffset(correction, 0.0);
LCL_ApplyStepOffset(-correction);
LOG(LOGS_WARN, LOGF_Local, "System clock was stepped by %.3f seconds", correction);
LOG(LOGS_WARN, LOGF_Local, "System clock was stepped by %.6f seconds", correction);
return 1;
}
@@ -586,8 +594,34 @@ LCL_SetLeap(int leap)
if (drv_set_leap) {
(drv_set_leap)(leap);
}
return;
}
/* ================================================== */
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;
}
/* ================================================== */

60
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,23 +64,25 @@ 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)
is_step_change : true if change is being applied as a jump (using
settimeofday rather than adjtime)
change_type : what type of change is being applied
anything : Passthrough argument from call to registration routine */
typedef enum {
LCL_ChangeAdjust,
LCL_ChangeStep,
LCL_ChangeUnknownStep
} LCL_ChangeType;
typedef void (*LCL_ParameterChangeHandler)
(struct timeval *raw, struct timeval *cooked,
double dfreq, double afreq_ppm,
double doffset, int is_step_change,
double dfreq,
double doffset,
LCL_ChangeType change_type,
void *anything
);
@@ -92,6 +92,9 @@ extern void LCL_AddParameterChangeHandler(LCL_ParameterChangeHandler handler, vo
/* Remove a handler */
extern void LCL_RemoveParameterChangeHandler(LCL_ParameterChangeHandler, void *anything);
/* Check if a handler is invoked first when dispatching */
extern int LCL_IsFirstParameterChangeHandler(LCL_ParameterChangeHandler handler);
/* Function type for handlers to be called back when an indeterminate
offset is introduced into the local time. This situation occurs
when the frequency must be adjusted to effect a clock slew and
@@ -144,9 +147,10 @@ extern void LCL_AccumulateDeltaFrequency(double dfreq);
/* Routine to apply an offset (in seconds) to the local clock. The
argument should be positive to move the clock backwards (i.e. the
local clock is currently fast of true time), or negative to move it
forwards (i.e. it is currently slow of true time). */
forwards (i.e. it is currently slow of true time). Provided is also
a suggested correction rate (correction time * offset). */
extern void LCL_AccumulateOffset(double offset);
extern void LCL_AccumulateOffset(double offset, double corr_rate);
/* Routine to apply an immediate offset by doing a sudden step if
possible. (Intended for use after an initial estimate of offset has
@@ -157,9 +161,14 @@ extern void LCL_AccumulateOffset(double offset);
extern void LCL_ApplyStepOffset(double offset);
/* Routine to invoke notify handlers on an unexpected time jump
in system clock */
extern void LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked,
double offset, double dispersion);
/* Perform the combination of modifying the frequency and applying
a slew, in one easy step */
extern void LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset);
extern void LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate);
/* Routine to read the system precision as a log to base 2 value. */
extern int LCL_GetSysPrecisionAsLog(void);
@@ -167,6 +176,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) */
@@ -179,11 +192,18 @@ extern void LCL_Finalise(void);
/* Routine to convert the outstanding system clock error to a step and
apply it, e.g. if the system clock has ended up an hour wrong due
to a timezone problem. */
extern int LCL_MakeStep(double threshold);
extern int LCL_MakeStep(void);
/* Routine to schedule a leap second. Leap second will be inserted
at the end of the day if argument is positive, deleted if negative,
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,12 +36,14 @@ 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. */
typedef void (*lcl_AccrueOffsetDriver)(double offset);
the clock forwards. The suggested correction rate of time to correct the
offset is given in 'corr_rate'. */
typedef void (*lcl_AccrueOffsetDriver)(double offset, double corr_rate);
/* System driver to apply a step offset. A positive argument means step
the clock forwards. */
@@ -54,7 +52,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);

346
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-2014
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -28,24 +25,48 @@
Module to handle logging of diagnostic information
*/
#include "config.h"
#include "sysincl.h"
#include "main.h"
#include "conf.h"
#include "logging.h"
#include "version.h"
#include "mkdirpp.h"
#include "util.h"
/* This is used by DEBUG_LOG macro */
int log_debug_enabled = 0;
/* ================================================== */
/* 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;
static int parent_fd = 0;
#define DEBUG_LEVEL_PRINT_FUNCTION 2
#define DEBUG_LEVEL_PRINT_DEBUG 2
static int debug_level = 0;
#ifdef WINNT
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 */
@@ -57,8 +78,6 @@ LOG_Initialise(void)
#ifdef WINNT
logfile = fopen("./chronyd.err", "a");
#endif
return;
}
/* ================================================== */
@@ -72,179 +91,242 @@ LOG_Finalise(void)
fclose(logfile);
}
#else
if (is_detached) {
if (system_log) {
closelog();
}
#endif
LOG_CycleLogFiles();
initialised = 0;
return;
}
/* ================================================== */
void
LOG_Line_Function(LOG_Severity severity, LOG_Facility facility, const char *format, ...)
static void log_message(int fatal, LOG_Severity severity, const char *message)
{
char buf[2048];
va_list other_args;
va_start(other_args, format);
vsnprintf(buf, sizeof(buf), format, other_args);
va_end(other_args);
#ifdef WINNT
if (logfile) {
fprintf(logfile, "%s\n", buf);
fprintf(logfile, fatal ? "Fatal error : %s\n" : "%s\n", message);
}
#else
if (is_detached) {
if (system_log) {
int priority;
switch (severity) {
case LOGS_DEBUG:
priority = LOG_DEBUG;
break;
case LOGS_INFO:
syslog(LOG_INFO, "%s", buf);
priority = LOG_INFO;
break;
case LOGS_WARN:
syslog(LOG_WARNING, "%s", buf);
priority = LOG_WARNING;
break;
case LOGS_ERR:
default:
syslog(LOG_ERR, "%s", buf);
priority = LOG_ERR;
break;
case LOGS_FATAL:
priority = LOG_CRIT;
break;
default:
assert(0);
}
syslog(priority, fatal ? "Fatal error : %s" : "%s", message);
} else {
fprintf(stderr, "%s\n", buf);
fprintf(stderr, fatal ? "Fatal error : %s\n" : "%s\n", message);
}
#endif
return;
}
/* ================================================== */
void
LOG_Fatal_Function(LOG_Facility facility, const char *format, ...)
void LOG_Message(LOG_Severity severity, LOG_Facility facility,
int line_number, const char *filename,
const char *function_name, const char *format, ...)
{
char buf[2048];
va_list other_args;
time_t t;
struct tm stm;
#ifdef WINNT
#else
if (!system_log) {
/* Don't clutter up syslog with timestamps and internal debugging info */
time(&t);
stm = *gmtime(&t);
strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", &stm);
fprintf(stderr, "%s ", buf);
if (debug_level >= DEBUG_LEVEL_PRINT_FUNCTION)
fprintf(stderr, "%s:%d:(%s) ", filename, line_number, function_name);
}
#endif
va_start(other_args, format);
vsnprintf(buf, sizeof(buf), format, other_args);
va_end(other_args);
#ifdef WINNT
if (logfile) {
fprintf(logfile, "Fatal error : %s\n", buf);
}
#else
if (is_detached) {
syslog(LOG_CRIT, "Fatal error : %s", buf);
} else {
fprintf(stderr, "Fatal error : %s\n", buf);
}
#endif
switch (severity) {
case LOGS_DEBUG:
case LOGS_INFO:
case LOGS_WARN:
case LOGS_ERR:
log_message(0, severity, buf);
break;
case LOGS_FATAL:
log_message(1, severity, buf);
MAI_CleanupAndExit();
return;
}
/* ================================================== */
void
LOG_Position(const char *filename, int line_number, const char *function_name)
{
#ifdef WINNT
#else
time_t t;
struct tm stm;
char buf[64];
if (!is_detached) {
/* Don't clutter up syslog with internal debugging info */
time(&t);
stm = *gmtime(&t);
strftime(buf, sizeof(buf), "%d-%H:%M:%S", &stm);
fprintf(stderr, "%s:%d:(%s)[%s] ", filename, line_number, function_name, buf);
}
#endif
return;
}
/* ================================================== */
void
LOG_GoDaemon(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);
/* With syslog, send the message also to the grandparent
process or write it to stderr if not detached */
if (system_log) {
if (parent_fd > 0) {
if (write(parent_fd, buf, strlen(buf) + 1) < 0)
; /* Not much we can do here */
} else if (parent_fd == 0) {
system_log = 0;
log_message(1, severity, buf);
}
}
is_detached = 1;
openlog("chronyd", LOG_PID, LOG_DAEMON);
LOG(LOGS_INFO, LOGF_Logging, "chronyd version %s starting", PROGRAM_VERSION_STRING);
}
break;
default:
assert(0);
}
}
/* ================================================== */
void
LOG_OpenSystemLog(void)
{
#ifdef WINNT
#else
system_log = 1;
openlog("chronyd", LOG_PID, LOG_DAEMON);
#endif
}
/* ================================================== */
int
LOG_RateLimited(void)
void LOG_SetDebugLevel(int level)
{
time_t now;
now = time(NULL);
if (last_limited + 10 > now && last_limited <= now)
return 1;
last_limited = now;
return 0;
debug_level = level;
if (level >= DEBUG_LEVEL_PRINT_DEBUG) {
if (!DEBUG)
LOG(LOGS_WARN, LOGF_Logging, "Not compiled with full debugging support");
log_debug_enabled = 1;
}
}
/* ================================================== */
/* 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)
void
LOG_SetParentFd(int fd)
{
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 */
parent_fd = fd;
}
/* ================================================== */
void
LOG_CloseParentFd()
{
if (parent_fd > 0)
close(parent_fd);
parent_fd = -1;
}
/* ================================================== */
LOG_FileID
LOG_FileOpen(const char *name, const char *banner)
{
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;
logdir = CNF_GetLogDir();
if (!mkdir_and_parents(logdir)) {
LOG(LOGS_ERR, LOGF_Logging, "Could not create directory %s", logdir);
}
}
/* ================================================== */
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,12 +1,9 @@
/*
$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.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2002
* Copyright (C) Miroslav Lichvar 2013-2014
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -32,11 +29,39 @@
#ifndef GOT_LOGGING_H
#define GOT_LOGGING_H
/* Flag indicating whether debug messages are logged */
extern int log_debug_enabled;
/* Line logging macros. If the compiler is GNU C, we take advantage of
being able to get the function name also. */
#ifdef __GNUC__
#define FUNCTION_NAME __FUNCTION__
#define FORMAT_ATTRIBUTE_PRINTF(str, first) __attribute__ ((format (printf, str, first)))
#else
#define FUNCTION_NAME ""
#define FORMAT_ATTRIBUTE_PRINTF(str, first)
#endif
#define DEBUG_LOG(facility, ...) \
do { \
if (DEBUG && log_debug_enabled) \
LOG_Message(LOGS_DEBUG, facility, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__); \
} while (0)
#define LOG(severity, facility, ...) LOG_Message(severity, facility, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__)
#define LOG_FATAL(facility, ...) \
do { \
LOG_Message(LOGS_FATAL, facility, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__); \
exit(1); \
} while (0)
/* Definition of severity */
typedef enum {
LOGS_INFO,
LOGS_WARN,
LOGS_ERR
LOGS_ERR,
LOGS_FATAL,
LOGS_DEBUG
} LOG_Severity;
/* Definition of facility. Each message is tagged with who generated
@@ -58,14 +83,19 @@ typedef enum {
LOGF_CmdMon,
LOGF_Acquire,
LOGF_Manual,
LOGF_Keys,
LOGF_Logging,
LOGF_Nameserv,
LOGF_Rtc,
LOGF_Regress,
LOGF_Sys,
LOGF_SysGeneric,
LOGF_SysLinux,
LOGF_SysNetBSD,
LOGF_SysSolaris,
LOGF_SysSunOS,
LOGF_SysWinnt,
LOGF_TempComp,
LOGF_RtcLinux,
LOGF_Refclock
} LOG_Facility;
@@ -77,36 +107,37 @@ extern void LOG_Initialise(void);
extern void LOG_Finalise(void);
/* Line logging function */
extern void LOG_Line_Function(LOG_Severity severity, LOG_Facility facility, const char *format, ...);
FORMAT_ATTRIBUTE_PRINTF(6, 7)
extern void LOG_Message(LOG_Severity severity, LOG_Facility facility,
int line_number, const char *filename,
const char *function_name, const char *format, ...);
/* Logging function for fatal errors */
extern void LOG_Fatal_Function(LOG_Facility facility, const char *format, ...);
/* Set debug level:
0, 1 - only non-debug messages are logged
2 - debug messages are logged too, all messages are prefixed with
filename, line, and function name
*/
extern void LOG_SetDebugLevel(int level);
/* Position in code reporting function */
extern void LOG_Position(const char *filename, int line_number, const char *function_name);
/* Log messages to syslog instead of stderr */
extern void LOG_OpenSystemLog(void);
extern void LOG_GoDaemon(void);
/* Send fatal message also to the foreground process */
extern void LOG_SetParentFd(int fd);
/* Return zero once per 10 seconds */
extern int LOG_RateLimited(void);
/* Close the pipe to the foreground process so it can exit */
extern void LOG_CloseParentFd(void);
/* Line logging macro. If the compiler is GNU C, we take advantage of
being able to get the function name also. */
#if defined(__GNUC__)
#define LOG LOG_Position(__FILE__, __LINE__, __FUNCTION__); LOG_Line_Function
#define LOG_FATAL LOG_Position(__FILE__, __LINE__, __FUNCTION__); LOG_Fatal_Function
#else
#define LOG LOG_Position(__FILE__, __LINE__, ""); LOG_Line_Function
#define LOG_FATAL LOG_Position(__FILE__, __LINE__, ""); LOG_Fatal_Function
#endif /* defined (__GNUC__) */
/* File logging functions */
/* Like assert(0) */
typedef int LOG_FileID;
#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
extern LOG_FileID LOG_FileOpen(const char *name, const char *banner);
FORMAT_ATTRIBUTE_PRINTF(2, 3)
extern void LOG_FileWrite(LOG_FileID id, const char *format, ...);
extern void LOG_CreateLogFileDir(void);
extern void LOG_CycleLogFiles(void);
#endif /* GOT_LOGGING_H */

268
main.c
View File

@@ -1,13 +1,10 @@
/*
$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.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) John G. Hasler 2009
* Copyright (C) Miroslav Lichvar 2012-2014
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -29,6 +26,8 @@
The main program
*/
#include "config.h"
#include "sysincl.h"
#include "main.h"
@@ -45,14 +44,13 @@
#include "conf.h"
#include "cmdmon.h"
#include "keys.h"
#include "acquire.h"
#include "manual.h"
#include "version.h"
#include "rtc.h"
#include "refclock.h"
#include "clientlog.h"
#include "broadcast.h"
#include "nameserv.h"
#include "tempcomp.h"
/* ================================================== */
@@ -61,10 +59,12 @@
static int initialised = 0;
/* ================================================== */
static int exit_status = 0;
static int reload = 0;
static REF_Mode ref_mode = REF_ModeNormal;
/* ================================================== */
static void
@@ -80,23 +80,23 @@ delete_pidfile(void)
void
MAI_CleanupAndExit(void)
{
if (!initialised) exit(0);
if (!initialised) exit(exit_status);
if (CNF_GetDumpOnExit()) {
SRC_DumpSources();
}
TMC_Finalise();
MNL_Finalise();
ACQ_Finalise();
KEY_Finalise();
CLG_Finalise();
NSR_Finalise();
NCR_Finalise();
BRD_Finalise();
SRC_Finalise();
SST_Finalise();
REF_Finalise();
KEY_Finalise();
RCL_Finalise();
SRC_Finalise();
RTC_Finalise();
CAM_Finalise();
NIO_Finalise();
@@ -108,7 +108,7 @@ MAI_CleanupAndExit(void)
LOG_Finalise();
exit(0);
exit(exit_status);
}
/* ================================================== */
@@ -116,7 +116,6 @@ MAI_CleanupAndExit(void)
static void
signal_cleanup(int x)
{
LOG(LOGS_WARN, LOGF_Main, "chronyd exiting on signal");
if (!initialised) exit(0);
SCH_QuitProgram();
}
@@ -124,11 +123,10 @@ signal_cleanup(int x)
/* ================================================== */
static void
post_acquire_hook(void *anything)
ntp_source_resolving_end(void)
{
NSR_SetSourceResolvingEndHandler(NULL);
CNF_AddSources();
CNF_AddBroadcasts();
if (reload) {
/* Note, we want reload to come well after the initialisation from
the real time clock - this gives us a fighting chance that the
@@ -136,10 +134,62 @@ post_acquire_hook(void *anything)
semblence of validity about it. */
SRC_ReloadSources();
}
CNF_SetupAccessRestrictions();
RTC_StartMeasurements();
RCL_StartRefclocks();
NSR_StartSources();
NSR_AutoStartSources();
/* Special modes can end only when sources update their reachability.
Give up immediatelly if there are no active sources. */
if (ref_mode != REF_ModeNormal && !SRC_ActiveSources()) {
REF_SetUnsynchronised();
}
}
/* ================================================== */
static void
post_init_ntp_hook(void *anything)
{
if (ref_mode == REF_ModeInitStepSlew) {
/* Remove the initstepslew sources and set normal mode */
NSR_RemoveAllSources();
ref_mode = REF_ModeNormal;
REF_SetMode(ref_mode);
}
/* Close the pipe to the foreground process so it can exit */
LOG_CloseParentFd();
CNF_AddSources();
CNF_AddBroadcasts();
NSR_SetSourceResolvingEndHandler(ntp_source_resolving_end);
NSR_ResolveSources();
}
/* ================================================== */
static void
reference_mode_end(int result)
{
switch (ref_mode) {
case REF_ModeNormal:
case REF_ModeUpdateOnce:
case REF_ModePrintOnce:
exit_status = !result;
SCH_QuitProgram();
break;
case REF_ModeInitStepSlew:
/* Switch to the normal mode, the delay is used to prevent polling
interval shorter than the burst interval if some configured servers
were used also for initstepslew */
SCH_AddTimeoutByDelay(2.0, post_init_ntp_hook, NULL);
break;
default:
assert(0);
}
}
/* ================================================== */
@@ -147,7 +197,14 @@ post_acquire_hook(void *anything)
static void
post_init_rtc_hook(void *anything)
{
CNF_ProcessInitStepSlew(post_acquire_hook, NULL);
if (CNF_GetInitSources() > 0) {
CNF_AddInitSources();
NSR_StartSources();
assert(REF_GetMode() != REF_ModeNormal);
/* Wait for mode end notification */
} else {
(post_init_ntp_hook)(NULL);
}
}
/* ================================================== */
@@ -199,7 +256,7 @@ write_lockfile(void)
out = fopen(pidfile, "w");
if (!out) {
LOG(LOGS_ERR, LOGF_Main, "could not open lockfile %s for writing", pidfile);
LOG_FATAL(LOGF_Main, "could not open lockfile %s for writing", pidfile);
} else {
fprintf(out, "%d\n", getpid());
fclose(out);
@@ -208,15 +265,89 @@ write_lockfile(void)
/* ================================================== */
static void
go_daemon(void)
{
#ifdef WINNT
#else
int pid, fd, pipefd[2];
/* Create pipe which will the daemon use to notify the grandparent
when it's initialised or send an error message */
if (pipe(pipefd)) {
LOG_FATAL(LOGF_Logging, "Could not detach, pipe failed : %s", strerror(errno));
}
/* Does this preserve existing signal handlers? */
pid = fork();
if (pid < 0) {
LOG_FATAL(LOGF_Logging, "Could not detach, fork failed : %s", strerror(errno));
} else if (pid > 0) {
/* In the 'grandparent' */
char message[1024];
int r;
close(pipefd[1]);
r = read(pipefd[0], message, sizeof (message));
if (r) {
if (r > 0) {
/* Print the error message from the child */
fprintf(stderr, "%.1024s\n", message);
}
exit(1);
} else
exit(0);
} else {
close(pipefd[0]);
setsid();
/* Do 2nd fork, as-per recommended practice for launching daemons. */
pid = fork();
if (pid < 0) {
LOG_FATAL(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 */
/* Change current directory to / */
if (chdir("/") < 0) {
LOG_FATAL(LOGF_Logging, "Could not chdir to / : %s", strerror(errno));
}
/* Don't keep stdin/out/err from before. But don't close
the parent pipe yet. */
for (fd=0; fd<1024; fd++) {
if (fd != pipefd[1])
close(fd);
}
LOG_SetParentFd(pipefd[1]);
}
}
#endif
}
/* ================================================== */
int main
(int argc, char **argv)
{
char *conf_file = NULL;
const char *conf_file = DEFAULT_CONF_FILE;
char *user = NULL;
int debug = 0;
int do_init_rtc = 0;
int debug = 0, nofork = 0, address_family = IPADDR_UNSPEC;
int do_init_rtc = 0, restarted = 0;
int other_pid;
int lock_memory = 0, sched_priority = 0;
int system_log = 1;
int config_args = 0;
LOG_Initialise();
@@ -235,6 +366,8 @@ int main
lock_memory = 1;
} else if (!strcmp("-r", *argv)) {
reload = 1;
} else if (!strcmp("-R", *argv)) {
restarted = 1;
} else if (!strcmp("-u", *argv)) {
++argv, --argc;
if (argc == 0) {
@@ -246,59 +379,88 @@ int main
do_init_rtc = 1;
} else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
/* This write to the terminal is OK, it comes before we turn into a daemon */
printf("chronyd (chrony) version %s\n", PROGRAM_VERSION_STRING);
printf("chronyd (chrony) version %s\n", CHRONY_VERSION);
exit(0);
} else if (!strcmp("-n", *argv)) {
nofork = 1;
} else if (!strcmp("-d", *argv)) {
debug = 1;
debug++;
nofork = 1;
system_log = 0;
} else if (!strcmp("-q", *argv)) {
ref_mode = REF_ModeUpdateOnce;
nofork = 1;
system_log = 0;
} else if (!strcmp("-Q", *argv)) {
ref_mode = REF_ModePrintOnce;
nofork = 1;
system_log = 0;
} else if (!strcmp("-4", *argv)) {
DNS_SetAddressFamily(IPADDR_INET4);
address_family = IPADDR_INET4;
} else if (!strcmp("-6", *argv)) {
DNS_SetAddressFamily(IPADDR_INET6);
} else {
address_family = IPADDR_INET6;
} else if (*argv[0] == '-') {
LOG_FATAL(LOGF_Main, "Unrecognized command line option [%s]", *argv);
} else {
/* Process remaining arguments and configuration lines */
config_args = argc;
break;
}
}
#ifndef SYS_WINNT
if (getuid() != 0) {
/* This write to the terminal is OK, it comes before we turn into a daemon */
fprintf(stderr,"Not superuser\n");
exit(1);
}
/* Turn into a daemon */
if (!debug) {
LOG_GoDaemon();
if (!nofork) {
go_daemon();
}
if (system_log) {
LOG_OpenSystemLog();
}
LOG_SetDebugLevel(debug);
LOG(LOGS_INFO, LOGF_Main, "chronyd version %s starting", CHRONY_VERSION);
DNS_SetAddressFamily(address_family);
CNF_SetRestarted(restarted);
/* Parse the config file or the remaining command line arguments */
if (!config_args) {
CNF_ReadFile(conf_file);
} else {
do {
CNF_ParseLine(NULL, config_args - argc + 1, *argv);
} while (++argv, --argc);
}
/* Check whether another chronyd may already be running. Do this after
* forking, so that message logging goes to the right place (i.e. syslog), in
* case this chronyd is being run from a boot script. */
if (maybe_another_chronyd_running(&other_pid)) {
LOG_FATAL(LOGF_Main, "Another chronyd may already be running (pid=%d), check lockfile (%s)",
other_pid, CNF_GetPidFile());
exit(1);
}
/* Write our lockfile to prevent other chronyds running. This has *GOT* to
* be done *AFTER* the daemon-creation fork() */
write_lockfile();
#endif
CNF_ReadFile(conf_file);
if (do_init_rtc) {
RTC_TimePreInit();
}
LCL_Initialise();
SCH_Initialise();
SYS_Initialise();
NIO_Initialise();
CAM_Initialise();
RTC_Initialise();
NIO_Initialise(address_family);
CAM_Initialise(address_family);
RTC_Initialise(do_init_rtc);
SRC_Initialise();
RCL_Initialise();
KEY_Initialise();
/* Command-line switch must have priority */
if (!sched_priority) {
@@ -312,24 +474,36 @@ int main
SYS_LockMemory();
}
if (user) {
if (!user) {
user = CNF_GetUser();
}
if (user && strcmp(user, "root")) {
SYS_DropRoot(user);
}
LOG_CreateLogFileDir();
REF_Initialise();
SST_Initialise();
SRC_Initialise();
BRD_Initialise();
NCR_Initialise();
NSR_Initialise();
CLG_Initialise();
KEY_Initialise();
ACQ_Initialise();
MNL_Initialise();
TMC_Initialise();
/* From now on, it is safe to do finalisation on exit */
initialised = 1;
CNF_SetupAccessRestrictions();
if (ref_mode == REF_ModeNormal && CNF_GetInitSources() > 0) {
ref_mode = REF_ModeInitStepSlew;
}
REF_SetModeEndHandler(reference_mode_end);
REF_SetMode(ref_mode);
if (do_init_rtc) {
RTC_TimeInit(post_init_rtc_hook, NULL);
} else {
@@ -347,6 +521,8 @@ int main
the scheduler. */
SCH_MainLoop();
LOG(LOGS_INFO, LOGF_Main, "chronyd exiting");
MAI_CleanupAndExit();
return 0;

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,52 +1,78 @@
#!/usr/bin/env perl
#!/bin/sh
$tool = "chrony";
LANG=C
export LANG
$version = shift || die "Usage : $0 <version>\n";
$subdir = "${tool}-${version}";
if [ $# -ne 1 ]; then
echo "Usage : $0 <version>"
exit 2
fi
unless (-d ".git") {
die "No .git subdirectory?"
}
version=$1
tag=$version
subdir=chrony-${version}
mandate=$(date +'%B %Y')
unless (-d "RELEASES") {
mkdir "RELEASES", 0755;
}
umask 022
system ("git tag -s $version");
die "git-tag failed" if ($? != 0);
if (-d "RELEASES/$subdir") {
system ("rm -rf RELEASES/$subdir");
}
if [ ! -d .git ]; then
echo "No .git subdirectory?"
exit 3
fi
system ("git archive --format=tar --prefix=RELEASES/${subdir}/ $version | tar xf -");
die "git-tar-tree failed" if ($? != 0);
[ -d RELEASES ] || mkdir RELEASES
chdir "RELEASES";
$here = qx/pwd/;
chomp $here;
chdir $subdir;
rm -rf RELEASES/$subdir
open (OUT, ">version.txt");
print OUT $version."\n";
close OUT;
if [ $version != test ]; then
git tag -s $tag || exit 1
else
tag=HEAD
fi
open (IN, "<${tool}.spec.sample");
open (OUT, ">${tool}.spec");
while (<IN>) {
s/\@\@VERSION\@\@/$version/;
print OUT;
}
close (IN);
close (OUT);
git archive --format=tar --prefix=RELEASES/${subdir}/ $tag | \
tar xf - || exit 1
system("makeinfo --no-headers --number-sections -o chrony.txt chrony.texi");
unlink "make_release";
unlink "${tool}.spec.sample";
unlink ".gitignore";
cd RELEASES/$subdir || exit 1
chdir $here;
system ("tar cvf - $subdir | gzip -9 > ${subdir}.tar.gz");
system ("gpg -b -a -o ${subdir}-tar-gz-asc.txt ${subdir}.tar.gz");
echo $version > version.txt
sed -e "s%@@VERSION@@%${version}%" < chrony.spec.sample > chrony.spec
for m in chrony.1 chronyc.1.in chrony.conf.5.in chronyd.8.in; do
sed -e "s%@VERSION@%${version}%;s%@MAN_DATE@%${mandate}%" \
< $m > ${m}_
mv -f ${m}_ $m
done
./configure && make chrony.txt || exit 1
mv chrony.txt chrony.txt_
make distclean
mv chrony.txt_ chrony.txt
awk '/^[1-9] Installation$/{p=1}
/^[1-9]\.. Support for line editing/{exit}; p' chrony.txt | \
tail -n +4 > INSTALL
if [ $(wc -l < INSTALL) -gt 100 -o $(wc -l < INSTALL) -lt 85 ]; then
echo "INSTALL generated incorrectly?"
exit 3
fi
awk '/^[1-9] Frequently asked questions$/{p=1}
/^Appendix A GNU General Public License$/{exit}; p' chrony.txt | \
tail -n +4 | sed 's/^[1-9]\.\([1-9]\)/\1/' | sed 's/^----/--/' | \
sed 's/^====/==/' > FAQ
if [ $(wc -l < FAQ) -gt 400 -o $(wc -l < FAQ) -lt 200 ]; then
echo "FAQ generated incorrectly?"
exit 3
fi
rm -f config.h config.log faqgen.pl make_release chrony.spec.sample .gitignore
cd ..
tar cv --owner root --group root $subdir | gzip -9 > ${subdir}.tar.gz
[ $version != test ] && \
gpg -b -a -o ${subdir}-tar-gz-asc.txt ${subdir}.tar.gz

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.
**********************************************************************
@@ -34,7 +30,9 @@
*/
#include <stddef.h>
#include "config.h"
#include "sysincl.h"
#include "manual.h"
#include "logging.h"
@@ -61,22 +59,14 @@ typedef struct {
static Sample samples[16];
static int n_samples;
static int replace_margin;
static int error;
/* Eventually these constants need to be user-defined in conf file */
#define REPLACE_MARGIN 300
#define ERROR_MARGIN 0.2
/* ================================================== */
static void
slew_samples(struct timeval *raw,
struct timeval *cooked,
double dfreq,
double afreq,
double doffset,
int is_step_change,
LCL_ChangeType change_type,
void *not_used);
/* ================================================== */
@@ -92,12 +82,7 @@ MNL_Initialise(void)
n_samples = 0;
replace_margin = REPLACE_MARGIN;
error = ERROR_MARGIN;
LCL_AddParameterChangeHandler(slew_samples, NULL);
return;
}
/* ================================================== */
@@ -105,7 +90,6 @@ MNL_Initialise(void)
void
MNL_Finalise(void)
{
return;
}
/* ================================================== */
@@ -148,6 +132,8 @@ estimate_and_set_system(struct timeval *now, int offset_provided, double offset,
}
b1 = freq = 0.0;
found_freq = 0;
agos[0] = 0.0;
offsets[0] = b0;
}
if (offset_provided) {
@@ -158,7 +144,7 @@ estimate_and_set_system(struct timeval *now, int offset_provided, double offset,
if (found_freq) {
LOG(LOGS_INFO, LOGF_Manual,
"Making a frequency change of %.3fppm and a slew of %.6f\n",
"Making a frequency change of %.3f ppm and a slew of %.6f",
1.0e6 * freq, slew_by);
REF_SetManualReference(now,
@@ -188,14 +174,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,20 +215,22 @@ static void
slew_samples(struct timeval *raw,
struct timeval *cooked,
double dfreq,
double afreq,
double doffset,
int is_step_change,
LCL_ChangeType change_type,
void *not_used)
{
double elapsed, delta_time;
double delta_time;
int i;
if (change_type == LCL_ChangeUnknownStep) {
MNL_Reset();
}
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 +290,6 @@ MNL_DeleteSample(int index)
{
int i;
struct timeval now;
double local_clock_err;
if ((index < 0) || (index >= n_samples)) {
return 0;
@@ -319,7 +305,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.
**********************************************************************

6
md5.h
View File

@@ -32,11 +32,7 @@
***********************************************************************
*/
#ifdef HAS_STDINT_H
#include <stdint.h>
#elif defined(HAS_INTTYPES_H)
#include <inttypes.h>
#endif
#include "sysincl.h"
/* typedef a 32-bit type */
typedef uint32_t UINT4;

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.
**********************************************************************
@@ -31,8 +27,6 @@
#ifndef GOT_MEMORY_H
#define GOT_MEMORY_H
#include <stdlib.h>
#define Malloc(x) malloc(x)
#define MallocNew(T) ((T *) malloc(sizeof(T)))
#define MallocArray(T, n) ((T *) malloc((n) * sizeof(T)))

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.
**********************************************************************
@@ -30,6 +26,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "mkdirpp.h"
@@ -86,6 +84,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,15 +0,0 @@
#!/bin/sh
rm -f version.h
echo "#ifndef VERSION_H" > version.h
echo "#define VERSION_H 1" >> version.h
if [ -f version.txt ]; then
ver=`cat version.txt`
echo "#define PROGRAM_VERSION_STRING \"$ver\"" >> version.h
else
echo "#define PROGRAM_VERSION_STRING \"DEVELOPMENT\"" >> version.h
fi
echo "#endif /* VERSION_H */" >> version.h

View File

@@ -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
@@ -30,17 +26,15 @@
*/
#include "config.h"
#include "sysincl.h"
#include "nameserv.h"
#include "util.h"
#include <resolv.h>
/* ================================================== */
#define MAXRETRIES 10
static unsigned int retries = 0;
static int address_family = IPADDR_UNSPEC;
void
@@ -49,31 +43,25 @@ 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
#ifdef HAVE_GETADDRINFO
struct addrinfo hints, *res, *ai;
int result;
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;
#ifdef FORCE_DNSRETRY
return DNS_TryAgain;
#else
return result == EAI_AGAIN ? DNS_TryAgain : DNS_Failure;
#endif
}
for (ai = res; !result && ai != NULL; ai = ai->ai_next) {
@@ -96,32 +84,27 @@ 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;
#ifdef FORCE_DNSRETRY
return DNS_TryAgain;
#else
return DNS_Failure;
#endif
#endif
}
@@ -190,3 +173,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 */

144
nameserv_async.c Normal file
View File

@@ -0,0 +1,144 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2014
*
* 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.
*
**********************************************************************
=======================================================================
Functions to asynchronously convert name to IP address
*/
#include "config.h"
#include "sysincl.h"
#include "nameserv_async.h"
#include "logging.h"
#include "memory.h"
#include "sched.h"
#include "util.h"
#ifdef FEAT_ASYNCDNS
#ifdef USE_PTHREAD_ASYNCDNS
#include <pthread.h>
/* ================================================== */
struct DNS_Async_Instance {
const char *name;
DNS_Status status;
IPAddr addr;
DNS_NameResolveHandler handler;
void *arg;
pthread_t thread;
int pipe[2];
};
static int resolving_threads = 0;
/* ================================================== */
static void *
start_resolving(void *anything)
{
struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything;
inst->status = DNS_Name2IPAddress(inst->name, &inst->addr);
/* Notify the main thread that the result is ready */
if (write(inst->pipe[1], "", 1) < 0)
;
return NULL;
}
/* ================================================== */
static void
end_resolving(void *anything)
{
struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything;
if (pthread_join(inst->thread, NULL)) {
LOG_FATAL(LOGF_Nameserv, "pthread_join() failed");
}
resolving_threads--;
SCH_RemoveInputFileHandler(inst->pipe[0]);
close(inst->pipe[0]);
close(inst->pipe[1]);
(inst->handler)(inst->status, &inst->addr, inst->arg);
Free(inst);
}
/* ================================================== */
void
DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything)
{
struct DNS_Async_Instance *inst;
inst = MallocNew(struct DNS_Async_Instance);
inst->name = name;
inst->handler = handler;
inst->arg = anything;
inst->status = DNS_Failure;
if (pipe(inst->pipe)) {
LOG_FATAL(LOGF_Nameserv, "pipe() failed");
}
resolving_threads++;
assert(resolving_threads <= 1);
if (pthread_create(&inst->thread, NULL, start_resolving, inst)) {
LOG_FATAL(LOGF_Nameserv, "pthread_create() failed");
}
SCH_AddInputFileHandler(inst->pipe[0], end_resolving, inst);
}
/* ================================================== */
#else
#error
#endif
#else
/* This is a blocking implementation used when nothing else is available */
void
DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything)
{
IPAddr addr;
DNS_Status status;
status = DNS_Name2IPAddress(name, &addr);
(handler)(status, &addr, anything);
}
/* ================================================== */
#endif

41
nameserv_async.h Normal file
View File

@@ -0,0 +1,41 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2014
*
* 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 for asynchronous nameserver functions
*/
#ifndef GOT_NAMESERV_ASYNC_H
#define GOT_NAMESERV_ASYNC_H
#include "nameserv.h"
/* Function type for callback to process the result */
typedef void (*DNS_NameResolveHandler)(DNS_Status status, IPAddr *ip_addr, void *anything);
/* Request resolving of a name to IP address. The handler will be
called when the result is available, but it may be also called
directly from this function call. */
extern void DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything);
#endif

36
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.
**********************************************************************
@@ -31,11 +27,9 @@
#ifndef GOT_NTP_H
#define GOT_NTP_H
#ifdef HAS_STDINT_H
#include <stdint.h>
#elif defined(HAS_INTTYPES_H)
#include <inttypes.h>
#endif
#include "sysincl.h"
#include "hash.h"
typedef struct {
uint32_t hi;
@@ -44,7 +38,7 @@ typedef struct {
typedef uint32_t NTP_int32;
#define AUTH_DATA_LEN 16
#define MAX_NTP_AUTH_DATA_LEN MAX_HASH_LENGTH
/* Type definition for leap bits */
typedef enum {
@@ -76,7 +70,7 @@ typedef struct {
NTP_int64 receive_ts;
NTP_int64 transmit_ts;
NTP_int32 auth_keyid;
uint8_t auth_data[AUTH_DATA_LEN];
uint8_t auth_data[MAX_NTP_AUTH_DATA_LEN];
} NTP_Packet;
/* We have to declare a buffer type to hold a datagram read from the
@@ -93,24 +87,6 @@ typedef union {
uint8_t arbitrary[MAX_NTP_MESSAGE_SIZE];
} ReceiveBuffer;
#define NTP_NORMAL_PACKET_SIZE (sizeof(NTP_Packet) - (sizeof(NTP_int32) + AUTH_DATA_LEN))
/* ================================================== */
inline static double
int32_to_double(NTP_int32 x)
{
return (double) ntohl(x) / 65536.0;
}
/* ================================================== */
inline static NTP_int32
double_to_int32(double x)
{
return htonl((NTP_int32)(0.5 + 65536.0 * x));
}
/* ================================================== */
#define NTP_NORMAL_PACKET_SIZE offsetof(NTP_Packet, auth_keyid)
#endif /* GOT_NTP_H */

1598
ntp_core.c

File diff suppressed because it is too large Load Diff

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,25 @@ 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);
/* Start an instance */
extern void NCR_StartInstance(NCR_Instance instance);
/* Reset an instance */
extern void NCR_ResetInstance(NCR_Instance inst);
/* 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_ProcessKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance data, int sock_fd, int length);
/* This routine is called when a new packet arrives off the network,
and we do not recognize its source */
extern void NCR_ProcessNoauthUnknown(NTP_Packet *message, struct timeval *now, 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);
/* 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_ProcessUnknown(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length);
/* Slew receive and transmit times in instance records */
extern void NCR_SlewTimes(NCR_Instance inst, struct timeval *when, double dfreq, double doffset);
@@ -90,6 +84,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 +97,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 */

557
ntp_io.c
View File

@@ -1,14 +1,10 @@
/*
$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.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Timo Teras 2009
* Copyright (C) Miroslav Lichvar 2009
* Copyright (C) Miroslav Lichvar 2009, 2013-2014
*
* 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
@@ -30,6 +26,8 @@
This file deals with the IO aspects of reading and writing NTP packets
*/
#include "config.h"
#include "sysincl.h"
#include "ntp_io.h"
@@ -41,7 +39,7 @@
#include "conf.h"
#include "util.h"
#include <fcntl.h>
#define INVALID_SOCK_FD -1
union sockaddr_in46 {
struct sockaddr_in in4;
@@ -51,84 +49,108 @@ union sockaddr_in46 {
struct sockaddr u;
};
/* The file descriptors for the IPv4 and IPv6 sockets */
static int sock_fd4;
/* The server/peer and client sockets for IPv4 and IPv6 */
static int server_sock_fd4;
static int client_sock_fd4;
#ifdef HAVE_IPV6
static int sock_fd6;
static int server_sock_fd6;
static int client_sock_fd6;
#endif
/* Flag indicating we create a new connected client socket for each
server instead of sharing client_sock_fd4 and client_sock_fd6 */
static int separate_client_sockets;
/* Flag indicating that we have been initialised */
static int initialised=0;
/* ================================================== */
/* Forward prototypes */
static int prepare_socket(int family);
static void read_from_socket(void *anything);
/* ================================================== */
static void
do_size_checks(void)
{
/* Assertions to check the sizes of certain data types
and the positions of certain record fields */
/* Check that certain invariants are true */
assert(sizeof(NTP_int32) == 4);
assert(sizeof(NTP_int64) == 8);
/* Check offsets of all fields in the NTP packet format */
assert(offsetof(NTP_Packet, lvm) == 0);
assert(offsetof(NTP_Packet, stratum) == 1);
assert(offsetof(NTP_Packet, poll) == 2);
assert(offsetof(NTP_Packet, precision) == 3);
assert(offsetof(NTP_Packet, root_delay) == 4);
assert(offsetof(NTP_Packet, root_dispersion) == 8);
assert(offsetof(NTP_Packet, reference_id) == 12);
assert(offsetof(NTP_Packet, reference_ts) == 16);
assert(offsetof(NTP_Packet, originate_ts) == 24);
assert(offsetof(NTP_Packet, receive_ts) == 32);
assert(offsetof(NTP_Packet, transmit_ts) == 40);
}
/* ================================================== */
static int
prepare_socket(int family)
prepare_socket(int family, int port_number, int client_only)
{
union sockaddr_in46 my_addr;
socklen_t my_addr_len;
int sock_fd;
unsigned short port_number;
IPAddr bind_address;
int on_off = 1;
port_number = CNF_GetNTPPort();
/* Open Internet domain UDP socket for NTP message transmissions */
#if 0
sock_fd = socket(family, SOCK_DGRAM, IPPROTO_UDP);
#else
sock_fd = socket(family, SOCK_DGRAM, 0);
#endif
if (sock_fd < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not open %s NTP socket : %s",
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
return -1;
return INVALID_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) {
/* Close on exec */
UTI_FdSetCloexec(sock_fd);
/* Prepare local address */
memset(&my_addr, 0, sizeof (my_addr));
my_addr_len = 0;
switch (family) {
case AF_INET:
if (!client_only)
CNF_GetBindAddress(IPADDR_INET4, &bind_address);
else
CNF_GetBindAcquisitionAddress(IPADDR_INET4, &bind_address);
if (bind_address.family == IPADDR_INET4)
my_addr.in4.sin_addr.s_addr = htonl(bind_address.addr.in4);
else if (port_number)
my_addr.in4.sin_addr.s_addr = htonl(INADDR_ANY);
else
break;
my_addr.in4.sin_family = family;
my_addr.in4.sin_port = htons(port_number);
my_addr_len = sizeof (my_addr.in4);
break;
#ifdef HAVE_IPV6
case AF_INET6:
if (!client_only)
CNF_GetBindAddress(IPADDR_INET6, &bind_address);
else
CNF_GetBindAcquisitionAddress(IPADDR_INET6, &bind_address);
if (bind_address.family == IPADDR_INET6)
memcpy(my_addr.in6.sin6_addr.s6_addr, bind_address.addr.in6,
sizeof (my_addr.in6.sin6_addr.s6_addr));
else if (port_number)
my_addr.in6.sin6_addr = in6addr_any;
else
break;
my_addr.in6.sin6_family = family;
my_addr.in6.sin6_port = htons(port_number);
my_addr_len = sizeof (my_addr.in6);
break;
#endif
default:
assert(0);
}
/* Make the socket capable of re-using an old address if binding to a specific port */
if (port_number &&
setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on_off, sizeof(on_off)) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set reuseaddr socket options");
/* Don't quit - we might survive anyway */
}
/* Make the socket capable of sending broadcast pkts - needed for NTP broadcast mode */
if (setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, (char *)&on_off, sizeof(on_off)) < 0) {
if (!client_only &&
setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, (char *)&on_off, sizeof(on_off)) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set broadcast socket options");
/* Don't quit - we might survive anyway */
}
@@ -141,11 +163,20 @@ prepare_socket(int family)
}
#endif
#ifdef IP_FREEBIND
/* Allow binding to address that doesn't exist yet */
if (my_addr_len > 0 &&
setsockopt(sock_fd, IPPROTO_IP, IP_FREEBIND, (char *)&on_off, sizeof(on_off)) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set free bind socket option");
}
#endif
if (family == AF_INET) {
#ifdef IP_PKTINFO
/* We want the local IP info too */
if (setsockopt(sock_fd, IPPROTO_IP, IP_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not request packet info using socket option");
/* We want the local IP info on server sockets */
if (!client_only &&
setsockopt(sock_fd, IPPROTO_IP, IP_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set packet info socket option");
/* Don't quit - we might survive anyway */
}
#endif
@@ -155,93 +186,165 @@ prepare_socket(int family)
#ifdef IPV6_V6ONLY
/* Receive IPv6 packets only */
if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on_off, sizeof(on_off)) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not request IPV6_V6ONLY socket option");
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set IPV6_V6ONLY socket option");
}
#endif
if (!client_only) {
#ifdef IPV6_RECVPKTINFO
if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set IPv6 packet info socket option");
}
#elif defined(IPV6_PKTINFO)
if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set IPv6 packet info socket option");
}
#endif
}
}
#endif
/* Bind the port */
memset(&my_addr, 0, sizeof (my_addr));
/* Bind the socket if a port or address was specified */
if (my_addr_len > 0 && bind(sock_fd, &my_addr.u, my_addr_len) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not bind %s NTP socket : %s",
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
close(sock_fd);
return INVALID_SOCK_FD;
}
/* Register handler for read events on the socket */
SCH_AddInputFileHandler(sock_fd, read_from_socket, (void *)(long)sock_fd);
return sock_fd;
}
/* ================================================== */
static int
prepare_separate_client_socket(int family)
{
switch (family) {
case AF_INET:
my_addr_len = sizeof (my_addr.in4);
my_addr.in4.sin_family = family;
my_addr.in4.sin_port = htons(port_number);
case IPADDR_INET4:
return prepare_socket(AF_INET, 0, 1);
#ifdef HAVE_IPV6
case IPADDR_INET6:
return prepare_socket(AF_INET6, 0, 1);
#endif
default:
return INVALID_SOCK_FD;
}
}
CNF_GetBindAddress(IPADDR_INET4, &bind_address);
/* ================================================== */
if (bind_address.family == IPADDR_INET4)
my_addr.in4.sin_addr.s_addr = htonl(bind_address.addr.in4);
else
my_addr.in4.sin_addr.s_addr = htonl(INADDR_ANY);
static int
connect_socket(int sock_fd, NTP_Remote_Address *remote_addr)
{
union sockaddr_in46 addr;
socklen_t addr_len;
memset(&addr, 0, sizeof (addr));
switch (remote_addr->ip_addr.family) {
case IPADDR_INET4:
addr_len = sizeof (addr.in4);
addr.in4.sin_family = AF_INET;
addr.in4.sin_addr.s_addr = htonl(remote_addr->ip_addr.addr.in4);
addr.in4.sin_port = htons(remote_addr->port);
break;
#ifdef HAVE_IPV6
case AF_INET6:
my_addr_len = sizeof (my_addr.in6);
my_addr.in6.sin6_family = family;
my_addr.in6.sin6_port = htons(port_number);
CNF_GetBindAddress(IPADDR_INET6, &bind_address);
if (bind_address.family == IPADDR_INET6)
memcpy(my_addr.in6.sin6_addr.s6_addr, bind_address.addr.in6,
sizeof (my_addr.in6.sin6_addr.s6_addr));
else
my_addr.in6.sin6_addr = in6addr_any;
case IPADDR_INET6:
addr_len = sizeof (addr.in6);
addr.in6.sin6_family = AF_INET6;
memcpy(addr.in6.sin6_addr.s6_addr, remote_addr->ip_addr.addr.in6,
sizeof (addr.in6.sin6_addr.s6_addr));
addr.in6.sin6_port = htons(remote_addr->port);
break;
#endif
default:
assert(0);
}
#if 0
LOG(LOGS_INFO, LOGF_NtpIO, "Initialising, socket fd=%d", sock_fd);
#endif
if (bind(sock_fd, &my_addr.u, my_addr_len) < 0) {
LOG_FATAL(LOGF_NtpIO, "Could not bind %s NTP socket : %s",
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
if (connect(sock_fd, &addr.u, addr_len) < 0) {
DEBUG_LOG(LOGF_NtpIO, "Could not connect NTP socket to %s:%d : %s",
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
strerror(errno));
return 0;
}
/* Register handler for read events on the socket */
SCH_AddInputFileHandler(sock_fd, read_from_socket, (void *)(long)sock_fd);
#if 0
if (fcntl(sock_fd, F_SETFL, O_NONBLOCK | O_NDELAY) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not make socket non-blocking");
}
if (ioctl(sock_fd, I_SETSIG, S_INPUT) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not enable signal");
}
#endif
return sock_fd;
return 1;
}
void
NIO_Initialise(void)
/* ================================================== */
static void
close_socket(int sock_fd)
{
if (sock_fd == INVALID_SOCK_FD)
return;
SCH_RemoveInputFileHandler(sock_fd);
close(sock_fd);
}
/* ================================================== */
void
NIO_Initialise(int family)
{
int server_port, client_port;
assert(!initialised);
initialised = 1;
do_size_checks();
server_port = CNF_GetNTPPort();
client_port = CNF_GetAcquisitionPort();
sock_fd4 = prepare_socket(AF_INET);
/* Use separate connected sockets if client port is negative */
separate_client_sockets = client_port < 0;
if (client_port < 0)
client_port = 0;
server_sock_fd4 = INVALID_SOCK_FD;
client_sock_fd4 = INVALID_SOCK_FD;
#ifdef HAVE_IPV6
sock_fd6 = prepare_socket(AF_INET6);
server_sock_fd6 = INVALID_SOCK_FD;
client_sock_fd6 = INVALID_SOCK_FD;
#endif
if (sock_fd4 < 0
#ifdef HAVE_IPV6
&& sock_fd6 < 0
#endif
) {
LOG_FATAL(LOGF_NtpIO, "Could not open any NTP socket");
if (family == IPADDR_UNSPEC || family == IPADDR_INET4) {
if (server_port)
server_sock_fd4 = prepare_socket(AF_INET, server_port, 0);
if (!separate_client_sockets) {
if (client_port != server_port || !server_port)
client_sock_fd4 = prepare_socket(AF_INET, client_port, 1);
else
client_sock_fd4 = server_sock_fd4;
}
}
#ifdef HAVE_IPV6
if (family == IPADDR_UNSPEC || family == IPADDR_INET6) {
if (server_port)
server_sock_fd6 = prepare_socket(AF_INET6, server_port, 0);
if (!separate_client_sockets) {
if (client_port != server_port || !server_port)
client_sock_fd6 = prepare_socket(AF_INET6, client_port, 1);
else
client_sock_fd6 = server_sock_fd6;
}
}
#endif
return;
if ((server_port && server_sock_fd4 == INVALID_SOCK_FD
#ifdef HAVE_IPV6
&& server_sock_fd6 == INVALID_SOCK_FD
#endif
) || (!separate_client_sockets && client_sock_fd4 == INVALID_SOCK_FD
#ifdef HAVE_IPV6
&& client_sock_fd6 == INVALID_SOCK_FD
#endif
)) {
LOG_FATAL(LOGF_NtpIO, "Could not open NTP sockets");
}
}
/* ================================================== */
@@ -249,24 +352,88 @@ NIO_Initialise(void)
void
NIO_Finalise(void)
{
if (sock_fd4 >= 0) {
SCH_RemoveInputFileHandler(sock_fd4);
close(sock_fd4);
}
sock_fd4 = -1;
if (server_sock_fd4 != client_sock_fd4)
close_socket(client_sock_fd4);
close_socket(server_sock_fd4);
server_sock_fd4 = client_sock_fd4 = INVALID_SOCK_FD;
#ifdef HAVE_IPV6
if (sock_fd6 >= 0) {
SCH_RemoveInputFileHandler(sock_fd6);
close(sock_fd6);
}
sock_fd6 = -1;
if (server_sock_fd6 != client_sock_fd6)
close_socket(client_sock_fd6);
close_socket(server_sock_fd6);
server_sock_fd6 = client_sock_fd6 = INVALID_SOCK_FD;
#endif
initialised = 0;
return;
}
/* ================================================== */
int
NIO_GetClientSocket(NTP_Remote_Address *remote_addr)
{
if (separate_client_sockets) {
int sock_fd = prepare_separate_client_socket(remote_addr->ip_addr.family);
if (sock_fd == INVALID_SOCK_FD)
return INVALID_SOCK_FD;
if (!connect_socket(sock_fd, remote_addr)) {
close_socket(sock_fd);
return INVALID_SOCK_FD;
}
return sock_fd;
} else {
switch (remote_addr->ip_addr.family) {
case IPADDR_INET4:
return client_sock_fd4;
#ifdef HAVE_IPV6
case IPADDR_INET6:
return client_sock_fd6;
#endif
default:
return INVALID_SOCK_FD;
}
}
}
/* ================================================== */
int
NIO_GetServerSocket(NTP_Remote_Address *remote_addr)
{
switch (remote_addr->ip_addr.family) {
case IPADDR_INET4:
return server_sock_fd4;
#ifdef HAVE_IPV6
case IPADDR_INET6:
return server_sock_fd6;
#endif
default:
return INVALID_SOCK_FD;
}
}
/* ================================================== */
void
NIO_CloseClientSocket(int sock_fd)
{
if (separate_client_sockets)
close_socket(sock_fd);
}
/* ================================================== */
int
NIO_IsServerSocket(int sock_fd)
{
return sock_fd != INVALID_SOCK_FD &&
(sock_fd == server_sock_fd4
#ifdef HAVE_IPV6
|| sock_fd == server_sock_fd6
#endif
);
}
/* ================================================== */
@@ -281,7 +448,9 @@ 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;
NTP_Local_Address local_addr;
char cmsgbuf[256];
struct msghdr msg;
struct iovec iov;
@@ -289,7 +458,7 @@ read_from_socket(void *anything)
assert(initialised);
SCH_GetFileReadyTime(&now);
SCH_GetLastEventTime(&now, &now_err, NULL);
iov.iov_base = message.arbitrary;
iov.iov_len = sizeof(message);
@@ -312,7 +481,8 @@ read_from_socket(void *anything)
reponse on a subsequent recvfrom). */
if (status > 0) {
memset(&remote_addr, 0, sizeof (remote_addr));
if (msg.msg_namelen > sizeof (where_from))
LOG_FATAL(LOGF_NtpIO, "Truncated source address");
switch (where_from.u.sa_family) {
case AF_INET:
@@ -332,41 +502,52 @@ read_from_socket(void *anything)
assert(0);
}
local_addr.ip_addr.family = IPADDR_UNSPEC;
local_addr.sock_fd = sock_fd;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
#ifdef IP_PKTINFO
if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
struct in_pktinfo ipi;
memcpy(&ipi, CMSG_DATA(cmsg), sizeof(ipi));
remote_addr.local_ip_addr.addr.in4 = ntohl(ipi.ipi_spec_dst.s_addr);
remote_addr.local_ip_addr.family = IPADDR_INET4;
local_addr.ip_addr.addr.in4 = ntohl(ipi.ipi_spec_dst.s_addr);
local_addr.ip_addr.family = IPADDR_INET4;
}
#endif
#if defined(IPV6_PKTINFO) && defined(HAVE_IN6_PKTINFO)
if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
struct in6_pktinfo ipi;
memcpy(&ipi, CMSG_DATA(cmsg), sizeof(ipi));
memcpy(&local_addr.ip_addr.addr.in6, &ipi.ipi6_addr.s6_addr,
sizeof (local_addr.ip_addr.addr.in6));
local_addr.ip_addr.family = IPADDR_INET6;
}
#endif
#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) {
if (status > 0) {
DEBUG_LOG(LOGF_NtpIO, "Received %d bytes from %s:%d to %s fd %d",
status,
UTI_IPToString(&remote_addr.ip_addr), remote_addr.port,
UTI_IPToString(&local_addr.ip_addr), local_addr.sock_fd);
}
NSR_ProcessReceive((NTP_Packet *) &message.ntp_pkt, &now, &remote_addr);
if (status >= NTP_NORMAL_PACKET_SIZE && status <= sizeof(NTP_Packet)) {
} else if (status == sizeof(NTP_Packet)) {
NSR_ProcessAuthenticatedReceive((NTP_Packet *) &message.ntp_pkt, &now, &remote_addr);
NSR_ProcessReceive((NTP_Packet *) &message.ntp_pkt, &now, now_err,
&remote_addr, &local_addr, status);
} else {
@@ -374,57 +555,67 @@ read_from_socket(void *anything)
}
}
return;
}
/* ================================================== */
/* Send a packet to given address */
static void
send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr)
static int
send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr)
{
union sockaddr_in46 remote;
struct msghdr msg;
struct iovec iov;
char cmsgbuf[256];
int cmsglen;
int sock_fd;
socklen_t addrlen;
socklen_t addrlen = 0;
assert(initialised);
if (local_addr->sock_fd == INVALID_SOCK_FD) {
DEBUG_LOG(LOGF_NtpIO, "No socket to send to %s:%d",
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port);
return 0;
}
switch (remote_addr->ip_addr.family) {
case IPADDR_INET4:
/* Don't set address with connected socket */
if (local_addr->sock_fd != server_sock_fd4 && separate_client_sockets)
break;
memset(&remote.in4, 0, sizeof (remote.in4));
addrlen = sizeof (remote.in4);
remote.in4.sin_family = AF_INET;
remote.in4.sin_port = htons(remote_addr->port);
remote.in4.sin_addr.s_addr = htonl(remote_addr->ip_addr.addr.in4);
sock_fd = sock_fd4;
break;
#ifdef HAVE_IPV6
case IPADDR_INET6:
/* Don't set address with connected socket */
if (local_addr->sock_fd != server_sock_fd6 && separate_client_sockets)
break;
memset(&remote.in6, 0, sizeof (remote.in6));
addrlen = sizeof (remote.in6);
remote.in6.sin6_family = AF_INET6;
remote.in6.sin6_port = htons(remote_addr->port);
memcpy(&remote.in6.sin6_addr.s6_addr, &remote_addr->ip_addr.addr.in6,
sizeof (remote.in6.sin6_addr.s6_addr));
sock_fd = sock_fd6;
break;
#endif
default:
return;
return 0;
}
if (sock_fd < 0)
return;
if (addrlen) {
msg.msg_name = &remote.u;
msg.msg_namelen = addrlen;
} else {
msg.msg_name = NULL;
msg.msg_namelen = 0;
}
iov.iov_base = packet;
iov.iov_len = packetlen;
msg.msg_name = &remote.u;
msg.msg_namelen = addrlen;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = cmsgbuf;
@@ -433,7 +624,7 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr)
cmsglen = 0;
#ifdef IP_PKTINFO
if (remote_addr->local_ip_addr.family == IPADDR_INET4) {
if (local_addr->ip_addr.family == IPADDR_INET4) {
struct cmsghdr *cmsg;
struct in_pktinfo *ipi;
@@ -446,13 +637,27 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr)
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
ipi = (struct in_pktinfo *) CMSG_DATA(cmsg);
ipi->ipi_spec_dst.s_addr = htonl(remote_addr->local_ip_addr.addr.in4);
ipi->ipi_spec_dst.s_addr = htonl(local_addr->ip_addr.addr.in4);
}
#endif
#if 0
LOG(LOGS_INFO, LOGF_NtpIO, "sending to %s:%d from %s",
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port, UTI_IPToString(&remote_addr->local_ip_addr));
#if defined(IPV6_PKTINFO) && defined(HAVE_IN6_PKTINFO)
if (local_addr->ip_addr.family == IPADDR_INET6) {
struct cmsghdr *cmsg;
struct in6_pktinfo *ipi;
cmsg = CMSG_FIRSTHDR(&msg);
memset(cmsg, 0, CMSG_SPACE(sizeof(struct in6_pktinfo)));
cmsglen += CMSG_SPACE(sizeof(struct in6_pktinfo));
cmsg->cmsg_level = IPPROTO_IPV6;
cmsg->cmsg_type = IPV6_PKTINFO;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
ipi = (struct in6_pktinfo *) CMSG_DATA(cmsg);
memcpy(&ipi->ipi6_addr.s6_addr, &local_addr->ip_addr.addr.in6,
sizeof(ipi->ipi6_addr.s6_addr));
}
#endif
msg.msg_controllen = cmsglen;
@@ -460,45 +665,35 @@ 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()) {
LOG(LOGS_WARN, LOGF_NtpIO, "Could not send to %s:%d : %s",
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port, strerror(errno));
if (sendmsg(local_addr->sock_fd, &msg, 0) < 0) {
DEBUG_LOG(LOGF_NtpIO, "Could not send to %s:%d from %s fd %d : %s",
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
UTI_IPToString(&local_addr->ip_addr), local_addr->sock_fd,
strerror(errno));
return 0;
}
return;
DEBUG_LOG(LOGF_NtpIO, "Sent to %s:%d from %s fd %d",
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
UTI_IPToString(&local_addr->ip_addr), local_addr->sock_fd);
return 1;
}
/* ================================================== */
/* Send an unauthenticated packet to a given address */
void
NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr)
int
NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr)
{
send_packet((void *) packet, NTP_NORMAL_PACKET_SIZE, remote_addr);
return send_packet((void *) packet, NTP_NORMAL_PACKET_SIZE, remote_addr, local_addr);
}
/* ================================================== */
/* Send an authenticated packet to a given address */
void
NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr)
int
NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int auth_len)
{
send_packet((void *) packet, sizeof(NTP_Packet), remote_addr);
}
/* ================================================== */
/* We ought to use getservbyname, but I can't really see this changing */
#define ECHO_PORT 7
void
NIO_SendEcho(NTP_Remote_Address *remote_addr)
{
unsigned long magic_message = 0xbe7ab1e7UL;
NTP_Remote_Address addr;
addr = *remote_addr;
addr.port = ECHO_PORT;
send_packet((void *) &magic_message, sizeof(unsigned long), &addr);
return send_packet((void *) packet, NTP_NORMAL_PACKET_SIZE + auth_len, remote_addr, local_addr);
}

View File

@@ -1,12 +1,9 @@
/*
$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.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2002
* Copyright (C) Miroslav Lichvar 2014
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -36,18 +33,27 @@
#include "addressing.h"
/* Function to initialise the module. */
extern void NIO_Initialise(void);
extern void NIO_Initialise(int family);
/* Function to finalise the module */
extern void NIO_Finalise(void);
/* Function to obtain a socket for sending client packets */
extern int NIO_GetClientSocket(NTP_Remote_Address *remote_addr);
/* Function to obtain a socket for sending server/peer packets */
extern int NIO_GetServerSocket(NTP_Remote_Address *remote_addr);
/* Function to close a socket returned by NIO_GetClientSocket() */
extern void NIO_CloseClientSocket(int sock_fd);
/* Function to check if socket is a server socket */
extern int NIO_IsServerSocket(int sock_fd);
/* Function to transmit a packet */
extern void NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr);
extern int NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr);
/* Function to transmit an authenticated packet */
extern void NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr);
/* Function to send a datagram to a remote machine's UDP echo port. */
extern void NIO_SendEcho(NTP_Remote_Address *remote_addr);
extern int NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int auth_len);
#endif /* GOT_NTP_IO_H */

View File

@@ -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-2012, 2014
*
* 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
@@ -30,6 +27,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "ntp_sources.h"
@@ -37,6 +36,9 @@
#include "util.h"
#include "logging.h"
#include "local.h"
#include "memory.h"
#include "nameserv_async.h"
#include "sched.h"
/* ================================================== */
@@ -60,15 +62,39 @@ static int n_sources;
/* The largest number of sources we want to have stored in the hash table */
#define MAX_SOURCES 64
/* Flag indicating new sources will be started automatically when added */
static int auto_start_sources = 0;
/* Source with unknown address (which may be resolved later) */
struct UnresolvedSource {
char *name;
int port;
NTP_Source_Type type;
SourceParameters params;
struct UnresolvedSource *next;
};
#define RESOLVE_INTERVAL_UNIT 7
#define MIN_RESOLVE_INTERVAL 2
#define MAX_RESOLVE_INTERVAL 9
static struct UnresolvedSource *unresolved_sources = NULL;
static int resolving_interval = 0;
static SCH_TimeoutID resolving_id;
static struct UnresolvedSource *resolving_source = NULL;
static NSR_SourceResolvingEndHandler resolving_end_handler = NULL;
/* ================================================== */
/* Forward prototypes */
static void resolve_sources(void *arg);
static void
slew_sources(struct timeval *raw,
struct timeval *cooked,
double dfreq,
double afreq,
double doffset,
int is_step_change,
LCL_ChangeType change_type,
void *anything);
/* ================================================== */
@@ -89,8 +115,6 @@ NSR_Initialise(void)
initialised = 1;
LCL_AddParameterChangeHandler(slew_sources, NULL);
return;
}
/* ================================================== */
@@ -99,7 +123,6 @@ void
NSR_Finalise(void)
{
initialised = 0;
return; /* Nothing to do yet */
}
/* ================================================== */
@@ -165,25 +188,18 @@ find_slot(NTP_Remote_Address *remote_addr, int *slot, int *found)
*found = 0;
*slot = hash;
}
return;
}
/* ================================================== */
/* 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;
assert(initialised);
#if 0
LOG(LOGS_INFO, LOGF_NtpSources, "IP=%s port=%d", UTI_IPToString(&remote_addr->ip_addr), remote_addr->port);
#endif
/* Find empty bin & check that we don't have the address already */
find_slot(remote_addr, &slot, &found);
if (found) {
@@ -196,8 +212,10 @@ 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);
if (auto_start_sources)
NCR_StartInstance(records[slot].data);
return NSR_Success;
}
}
@@ -205,35 +223,162 @@ 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
name_resolve_handler(DNS_Status status, IPAddr *ip_addr, void *anything)
{
int slot, found;
struct UnresolvedSource *us, **i, *next;
NTP_Remote_Address address;
assert(initialised);
us = (struct UnresolvedSource *)anything;
#if 0
LOG(LOGS_INFO, LOGF_NtpSources, "IP=%s port=%d", UTI_IPToString(&remote_addr->ip_addr), remote_addr->port);
#endif
assert(us == resolving_source);
/* Find empty bin & check that we don't have the address already */
find_slot(remote_addr, &slot, &found);
if (found) {
return NSR_AlreadyInUse;
} 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;
switch (status) {
case DNS_TryAgain:
break;
case DNS_Success:
DEBUG_LOG(LOGF_NtpSources, "%s resolved to %s", us->name, UTI_IPToString(ip_addr));
address.ip_addr = *ip_addr;
address.port = us->port;
NSR_AddSource(&address, us->type, &us->params);
break;
case DNS_Failure:
LOG(LOGS_WARN, LOGF_NtpSources, "Invalid host %s", us->name);
break;
default:
assert(0);
}
next = us->next;
if (status != DNS_TryAgain) {
/* Remove the source from the list */
for (i = &unresolved_sources; *i; i = &(*i)->next) {
if (*i == us) {
*i = us->next;
Free(us->name);
Free(us);
break;
}
}
}
resolving_source = next;
if (next) {
/* Continue with the next source in the list */
DEBUG_LOG(LOGF_NtpSources, "resolving %s", next->name);
DNS_Name2IPAddressAsync(next->name, name_resolve_handler, next);
} else {
/* This was the last source in the list. If some sources couldn't
be resolved, try again in exponentially increasing interval. */
if (unresolved_sources) {
if (resolving_interval < MIN_RESOLVE_INTERVAL)
resolving_interval = MIN_RESOLVE_INTERVAL;
else if (resolving_interval < MAX_RESOLVE_INTERVAL)
resolving_interval++;
resolving_id = SCH_AddTimeoutByDelay(RESOLVE_INTERVAL_UNIT *
(1 << resolving_interval), resolve_sources, NULL);
} else {
resolving_interval = 0;
}
/* This round of resolving is done */
if (resolving_end_handler)
(resolving_end_handler)();
}
}
/* ================================================== */
static void
resolve_sources(void *arg)
{
struct UnresolvedSource *us;
assert(!resolving_source);
DNS_Reload();
/* Start with the first source in the list, name_resolve_handler
will iterate over the rest */
us = unresolved_sources;
resolving_source = us;
DEBUG_LOG(LOGF_NtpSources, "resolving %s", us->name);
DNS_Name2IPAddressAsync(us->name, name_resolve_handler, us);
}
/* ================================================== */
/* 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;
}
/* ================================================== */
void
NSR_SetSourceResolvingEndHandler(NSR_SourceResolvingEndHandler handler)
{
resolving_end_handler = handler;
}
/* ================================================== */
void
NSR_ResolveSources(void)
{
/* Try to resolve unresolved sources now */
if (unresolved_sources) {
/* Make sure no resolving is currently running */
if (!resolving_source) {
if (resolving_interval) {
SCH_RemoveTimeout(resolving_id);
resolving_interval--;
}
resolve_sources(NULL);
}
} else {
/* No unresolved sources, we are done */
if (resolving_end_handler)
(resolving_end_handler)();
}
}
/* ================================================== */
void NSR_StartSources(void)
{
int i;
for (i = 0; i < N_RECORDS; i++) {
if (!records[i].remote_addr)
continue;
NCR_StartInstance(records[i].data);
}
}
/* ================================================== */
void NSR_AutoStartSources(void)
{
auto_start_sources = 1;
}
/* ================================================== */
@@ -245,60 +390,75 @@ 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;
}
n_sources--;
records[slot].remote_addr = NULL;
NCR_DestroyInstance(records[slot].data);
/* 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;
}
/* ================================================== */
void
NSR_RemoveAllSources(void)
{
int i;
for (i = 0; i < N_RECORDS; i++) {
if (!records[i].remote_addr)
continue;
NCR_DestroyInstance(records[i].data);
records[i].remote_addr = NULL;
}
}
/* ================================================== */
/* This routine is called by ntp_io when a new packet arrives off the network.*/
/* This routine is called by ntp_io when a new packet arrives off the network,
possibly with an authentication tail */
void
NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, NTP_Remote_Address *remote_addr)
NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length)
{
int slot, found;
assert(initialised);
#if 0
LOG(LOGS_INFO, LOGF_NtpSources, "from (%s,%d) at %s",
UTI_IPToString(&remote_addr->ip_addr),
remote_addr->port, UTI_TimevalToString(now));
#endif
find_slot(remote_addr, &slot, &found);
if (found == 2) { /* Must match IP address AND port number */
NCR_ProcessNoauthKnown(message, now, records[slot].data);
NCR_ProcessKnown(message, now, now_err, records[slot].data,
local_addr->sock_fd, length);
} else {
NCR_ProcessNoauthUnknown(message, now, remote_addr);
}
}
/* ================================================== */
/* This routine is called by ntp_io when a new packet with an authentication tail arrives off the network */
void
NSR_ProcessAuthenticatedReceive(NTP_Packet *message, struct timeval *now, NTP_Remote_Address *remote_addr)
{
int slot, found;
assert(initialised);
find_slot(remote_addr, &slot, &found);
if (found == 2) {
NCR_ProcessAuthKnown(message, now, records[slot].data);
} else {
NCR_ProcessAuthUnknown(message, now, remote_addr);
NCR_ProcessUnknown(message, now, now_err, remote_addr, local_addr, length);
}
}
@@ -308,24 +468,21 @@ static void
slew_sources(struct timeval *raw,
struct timeval *cooked,
double dfreq,
double afreq,
double doffset,
int is_step_change,
LCL_ChangeType change_type,
void *anything)
{
int i;
for (i=0; i<N_RECORDS; i++) {
if (records[i].remote_addr) {
#if 0
LOG(LOGS_INFO, LOGF_Sources, "IP=%s dfreq=%f doff=%f",
UTI_IPToString(&records[i].remote_addr->ip_addr), dfreq, doffset);
#endif
NCR_SlewTimes(records[i].data, cooked, dfreq, doffset);
if (change_type == LCL_ChangeUnknownStep) {
NCR_ResetInstance(records[i].data);
} else {
NCR_SlewTimes(records[i].data, cooked, dfreq, doffset);
}
}
}
}
/* ================================================== */
@@ -336,6 +493,8 @@ NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address)
int i;
int any;
NSR_ResolveSources();
any = 0;
for (i=0; i<N_RECORDS; i++) {
if (records[i].remote_addr) {
@@ -347,6 +506,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 +523,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 +636,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 +742,7 @@ void
NSR_GetActivityReport(RPT_ActivityReport *report)
{
int i;
struct UnresolvedSource *us;
report->online = 0;
report->offline = 0;
@@ -511,7 +755,12 @@ NSR_GetActivityReport(RPT_ActivityReport *report)
&report->burst_online, &report->burst_offline);
}
}
return;
report->unresolved = 0;
for (us = unresolved_sources; us; us = us->next) {
report->unresolved++;
}
}

View File

@@ -1,12 +1,9 @@
/*
$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.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2002
* Copyright (C) Miroslav Lichvar 2014
*
* 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
@@ -45,27 +42,43 @@
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);
/* Function type for handlers to be called back when an attempt
* (possibly unsuccessful) to resolve unresolved sources ends */
typedef void (*NSR_SourceResolvingEndHandler)(void);
/* Set the handler, or NULL to disable the notification */
extern void NSR_SetSourceResolvingEndHandler(NSR_SourceResolvingEndHandler handler);
/* Procedure to start resolving unresolved sources */
extern void NSR_ResolveSources(void);
/* Procedure to start all sources */
extern void NSR_StartSources(void);
/* Start new sources automatically */
extern void NSR_AutoStartSources(void);
/* Procedure to remove a source */
extern NSR_Status NSR_RemoveSource(NTP_Remote_Address *remote_addr);
/* This routine is called by ntp_io when a new packet arrives off the network */
extern void NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, NTP_Remote_Address *remote_addr);
/* Procedure to remove all sources */
extern void NSR_RemoveAllSources(void);
/* 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);
/* This routine is called by ntp_io when a new packet arrives off the network */
extern void NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length);
/* Initialisation function */
extern void NSR_Initialise(void);
@@ -91,6 +104,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.
**********************************************************************
@@ -30,6 +26,8 @@
integer endianness within the structures.
*/
#include "config.h"
#include "sysincl.h"
#include "util.h"
@@ -37,8 +35,8 @@
/* ================================================== */
int
PKL_CommandLength(CMD_Request *r)
static int
command_unpadded_length(CMD_Request *r)
{
int type;
type = ntohs(r->command);
@@ -65,6 +63,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 :
@@ -124,19 +124,9 @@ PKL_CommandLength(CMD_Request *r)
case REQ_CYCLELOGS :
return offsetof(CMD_Request, data.cyclelogs.EOR);
case REQ_SUBNETS_ACCESSED :
{
unsigned long ns;
ns = ntohl(r->data.subnets_accessed.n_subnets);
return (offsetof(CMD_Request, data.subnets_accessed.subnets) +
ns * sizeof(REQ_SubnetsAccessed_Subnet));
}
case REQ_CLIENT_ACCESSES:
{
unsigned long nc;
nc = ntohl(r->data.client_accesses.n_clients);
return (offsetof(CMD_Request, data.client_accesses.client_ips) +
nc * sizeof(unsigned long));
}
/* No longer supported */
return 0;
case REQ_CLIENT_ACCESSES_BY_INDEX:
return offsetof(CMD_Request, data.client_accesses_by_index.EOR);
case REQ_MANUAL_LIST:
@@ -147,6 +137,14 @@ 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_RESELECTDISTANCE:
return offsetof(CMD_Request, data.reselect_distance.EOR);
case REQ_MODIFY_MINSTRATUM:
return offsetof(CMD_Request, data.modify_minstratum.EOR);
case REQ_MODIFY_POLLTARGET:
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);
@@ -159,6 +157,149 @@ PKL_CommandLength(CMD_Request *r)
}
/* ================================================== */
int
PKL_CommandLength(CMD_Request *r)
{
int command_length;
command_length = command_unpadded_length(r);
if (!command_length)
return 0;
return command_length + PKL_CommandPaddingLength(r);
}
/* ================================================== */
#define PADDING_LENGTH_(request_length, reply_length) \
((request_length) < (reply_length) ? (reply_length) - (request_length) : 0)
#define PADDING_LENGTH(request_data, reply_data) \
PADDING_LENGTH_(offsetof(CMD_Request, request_data), offsetof(CMD_Reply, reply_data))
int
PKL_CommandPaddingLength(CMD_Request *r)
{
int type;
if (r->version < PROTO_VERSION_PADDING)
return 0;
type = ntohs(r->command);
if (type < 0 || type >= N_REQUEST_TYPES)
return 0;
switch (type) {
case REQ_NULL:
return PADDING_LENGTH(data, data.null.EOR);
case REQ_ONLINE:
return PADDING_LENGTH(data.online.EOR, data.null.EOR);
case REQ_OFFLINE:
return PADDING_LENGTH(data.offline.EOR, data.null.EOR);
case REQ_BURST:
return PADDING_LENGTH(data.burst.EOR, data.null.EOR);
case REQ_MODIFY_MINPOLL:
return PADDING_LENGTH(data.modify_minpoll.EOR, data.null.EOR);
case REQ_MODIFY_MAXPOLL:
return PADDING_LENGTH(data.modify_maxpoll.EOR, data.null.EOR);
case REQ_DUMP:
return PADDING_LENGTH(data.dump.EOR, data.null.EOR);
case REQ_MODIFY_MAXDELAY:
return PADDING_LENGTH(data.modify_maxdelay.EOR, data.null.EOR);
case REQ_MODIFY_MAXDELAYRATIO:
return PADDING_LENGTH(data.modify_maxdelayratio.EOR, data.null.EOR);
case REQ_MODIFY_MAXDELAYDEVRATIO:
return PADDING_LENGTH(data.modify_maxdelaydevratio.EOR, data.null.EOR);
case REQ_MODIFY_MAXUPDATESKEW:
return PADDING_LENGTH(data.modify_maxupdateskew.EOR, data.null.EOR);
case REQ_LOGON:
return PADDING_LENGTH(data.logon.EOR, data.null.EOR);
case REQ_SETTIME:
return PADDING_LENGTH(data.settime.EOR, data.manual_timestamp.EOR);
case REQ_LOCAL:
return PADDING_LENGTH(data.local.EOR, data.null.EOR);
case REQ_MANUAL:
return PADDING_LENGTH(data.manual.EOR, data.null.EOR);
case REQ_N_SOURCES:
return PADDING_LENGTH(data.n_sources.EOR, data.n_sources.EOR);
case REQ_SOURCE_DATA:
return PADDING_LENGTH(data.source_data.EOR, data.source_data.EOR);
case REQ_REKEY:
return PADDING_LENGTH(data.rekey.EOR, data.null.EOR);
case REQ_ALLOW:
return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR);
case REQ_ALLOWALL:
return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR);
case REQ_DENY:
return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR);
case REQ_DENYALL:
return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR);
case REQ_CMDALLOW:
return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR);
case REQ_CMDALLOWALL:
return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR);
case REQ_CMDDENY:
return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR);
case REQ_CMDDENYALL:
return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR);
case REQ_ACCHECK:
return PADDING_LENGTH(data.ac_check.EOR, data.null.EOR);
case REQ_CMDACCHECK:
return PADDING_LENGTH(data.ac_check.EOR, data.null.EOR);
case REQ_ADD_SERVER:
return PADDING_LENGTH(data.ntp_source.EOR, data.null.EOR);
case REQ_ADD_PEER:
return PADDING_LENGTH(data.ntp_source.EOR, data.null.EOR);
case REQ_DEL_SOURCE:
return PADDING_LENGTH(data.del_source.EOR, data.null.EOR);
case REQ_WRITERTC:
return PADDING_LENGTH(data.writertc.EOR, data.null.EOR);
case REQ_DFREQ:
return PADDING_LENGTH(data.dfreq.EOR, data.null.EOR);
case REQ_DOFFSET:
return PADDING_LENGTH(data.doffset.EOR, data.null.EOR);
case REQ_TRACKING:
return PADDING_LENGTH(data.tracking.EOR, data.tracking.EOR);
case REQ_SOURCESTATS:
return PADDING_LENGTH(data.sourcestats.EOR, data.sourcestats.EOR);
case REQ_RTCREPORT:
return PADDING_LENGTH(data.rtcreport.EOR, data.rtc.EOR);
case REQ_TRIMRTC:
return PADDING_LENGTH(data.trimrtc.EOR, data.null.EOR);
case REQ_CYCLELOGS:
return PADDING_LENGTH(data.cyclelogs.EOR, data.null.EOR);
case REQ_SUBNETS_ACCESSED:
case REQ_CLIENT_ACCESSES:
/* No longer supported */
return 0;
case REQ_CLIENT_ACCESSES_BY_INDEX:
return PADDING_LENGTH(data.client_accesses_by_index.EOR, data.client_accesses_by_index.EOR);
case REQ_MANUAL_LIST:
return PADDING_LENGTH(data.manual_list.EOR, data.manual_list.EOR);
case REQ_MANUAL_DELETE:
return PADDING_LENGTH(data.manual_delete.EOR, data.null.EOR);
case REQ_MAKESTEP:
return PADDING_LENGTH(data.make_step.EOR, data.null.EOR);
case REQ_ACTIVITY:
return PADDING_LENGTH(data.activity.EOR, data.activity.EOR);
case REQ_RESELECT:
return PADDING_LENGTH(data.reselect.EOR, data.null.EOR);
case REQ_RESELECTDISTANCE:
return PADDING_LENGTH(data.reselect_distance.EOR, data.null.EOR);
case REQ_MODIFY_MINSTRATUM:
return PADDING_LENGTH(data.modify_minstratum.EOR, data.null.EOR);
case REQ_MODIFY_POLLTARGET:
return PADDING_LENGTH(data.modify_polltarget.EOR, data.null.EOR);
default:
/* If we fall through the switch, it most likely means we've forgotten to implement a new case */
assert(0);
return 0;
}
}
/* ================================================== */
int
@@ -186,29 +327,15 @@ PKL_ReplyLength(CMD_Reply *r)
case RPY_RTC:
return offsetof(CMD_Reply, data.rtc.EOR);
case RPY_SUBNETS_ACCESSED :
{
unsigned long ns = ntohl(r->data.subnets_accessed.n_subnets);
if (r->status == htons(STT_SUCCESS)) {
return (offsetof(CMD_Reply, data.subnets_accessed.subnets) +
ns * sizeof(RPY_SubnetsAccessed_Subnet));
} else {
return offsetof(CMD_Reply, data);
}
}
case RPY_CLIENT_ACCESSES:
{
unsigned long nc = ntohl(r->data.client_accesses.n_clients);
if (r->status == htons(STT_SUCCESS)) {
return (offsetof(CMD_Reply, data.client_accesses.clients) +
nc * sizeof(RPY_ClientAccesses_Client));
} else {
return offsetof(CMD_Reply, data);
}
}
/* No longer supported */
return 0;
case RPY_CLIENT_ACCESSES_BY_INDEX:
{
unsigned long nc = ntohl(r->data.client_accesses_by_index.n_clients);
if (r->status == htons(STT_SUCCESS)) {
if (nc > MAX_CLIENT_ACCESSES)
return 0;
return (offsetof(CMD_Reply, data.client_accesses_by_index.clients) +
nc * sizeof(RPY_ClientAccesses_Client));
} else {
@@ -218,6 +345,8 @@ PKL_ReplyLength(CMD_Reply *r)
case RPY_MANUAL_LIST:
{
unsigned long ns = ntohl(r->data.manual_list.n_samples);
if (ns > MAX_MANUAL_LIST_SAMPLES)
return 0;
if (r->status == htons(STT_SUCCESS)) {
return (offsetof(CMD_Reply, data.manual_list.samples) +
ns * sizeof(RPY_ManualListSample));

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.
**********************************************************************
@@ -37,6 +33,8 @@
extern int PKL_CommandLength(CMD_Request *r);
extern int PKL_CommandPaddingLength(CMD_Request *r);
extern int PKL_ReplyLength(CMD_Reply *r);
#endif /* GOT_PKTLENGTH_H */

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, 2013-2014
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -25,6 +25,8 @@
*/
#include "config.h"
#include "refclock.h"
#include "reference.h"
#include "conf.h"
@@ -33,16 +35,18 @@
#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;
extern RefclockDriver RCL_SOCK_driver;
extern RefclockDriver RCL_PPS_driver;
extern RefclockDriver RCL_PHC_driver;
struct FilterSample {
double offset;
double dispersion;
struct timeval sample_time;
};
@@ -51,7 +55,14 @@ struct MedianFilter {
int index;
int used;
int last;
int avg_var_n;
double avg_var;
double max_var;
struct FilterSample *samples;
int *selected;
double *x_data;
double *y_data;
double *w_data;
};
struct RCL_Instance_Record {
@@ -62,14 +73,15 @@ struct RCL_Instance_Record {
int driver_poll;
int driver_polled;
int poll;
int missed_samples;
int leap_status;
int pps_rate;
int pps_active;
struct MedianFilter filter;
unsigned long ref_id;
unsigned long lock_ref;
uint32_t ref_id;
uint32_t lock_ref;
double offset;
double delay;
double precision;
SCH_TimeoutID timeout_id;
SRC_Instance source;
};
@@ -79,42 +91,40 @@ 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,
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 slew_samples(struct timeval *raw, struct timeval *cooked, double dfreq,
double doffset, LCL_ChangeType change_type, void *anything);
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_init(struct MedianFilter *filter, int length, double max_dispersion);
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);
}
if (n_sources > 0) {
LCL_AddParameterChangeHandler(slew_samples, NULL);
LCL_AddDispersionNotifyHandler(add_dispersion, NULL);
}
logfileid = CNF_GetLogRefclocks() ? LOG_FileOpen("refclocks",
" Date (UTC) Time Refid DP L P Raw offset Cooked offset Disp.")
: -1;
}
void
@@ -132,12 +142,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
@@ -150,14 +158,20 @@ RCL_AddRefclock(RefclockParameters *params)
if (n_sources == MAX_RCL_SOURCES)
return 0;
if (strncmp(params->driver_name, "SHM", 4) == 0) {
if (strcmp(params->driver_name, "SHM") == 0) {
inst->driver = &RCL_SHM_driver;
} else if (strncmp(params->driver_name, "SOCK", 4) == 0) {
inst->precision = 1e-6;
} else if (strcmp(params->driver_name, "SOCK") == 0) {
inst->driver = &RCL_SOCK_driver;
inst->precision = 1e-9;
pps_source = 1;
} else if (strncmp(params->driver_name, "PPS", 4) == 0) {
} else if (strcmp(params->driver_name, "PPS") == 0) {
inst->driver = &RCL_PPS_driver;
inst->precision = 1e-9;
pps_source = 1;
} else if (strcmp(params->driver_name, "PHC") == 0) {
inst->driver = &RCL_PHC_driver;
inst->precision = 1e-9;
} else {
LOG_FATAL(LOGF_Refclock, "unknown refclock driver %s", params->driver_name);
return 0;
@@ -173,13 +187,15 @@ 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->leap_status = LEAP_Normal;
inst->pps_rate = params->pps_rate;
inst->pps_active = 0;
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,32 +215,47 @@ 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);
return 0;
}
filter_init(&inst->filter, params->filter_length);
filter_init(&inst->filter, params->filter_length, params->max_dispersion);
#if 0
LOG(LOGS_INFO, LOGF_Refclock, "refclock added poll=%d dpoll=%d filter=%d",
inst->poll, inst->driver_poll, params->filter_length);
#endif
inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, params->sel_option, NULL);
DEBUG_LOG(LOGF_Refclock, "refclock %s added poll=%d dpoll=%d filter=%d",
params->driver_name, inst->poll, inst->driver_poll, params->filter_length);
n_sources++;
Free(params->driver_name);
return 1;
}
@@ -236,7 +267,8 @@ 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);
SRC_SetActive(inst->source);
inst->timeout_id = SCH_AddTimeoutByDelay(0.0, poll_timeout, (void *)inst);
if (inst->lock_ref) {
@@ -247,16 +279,13 @@ RCL_StartRefclocks(void)
} else
inst->lock_ref = -1;
}
if (n_sources > 0)
LCL_AddParameterChangeHandler(slew_samples, NULL);
}
void
RCL_ReportSource(RPT_SourceReport *report, struct timeval *now)
{
int i;
unsigned long ref_id;
uint32_t ref_id;
assert(report->ip_addr.family == IPADDR_INET4);
ref_id = report->ip_addr.addr.in4;
@@ -315,26 +344,38 @@ RCL_GetDriverOption(RCL_Instance instance, char *name)
}
int
RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset, NTP_Leap leap_status)
RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset, int leap)
{
double correction;
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;
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, dispersion);
filter_add_sample(&instance->filter, &cooked_time, offset - correction + instance->offset);
instance->leap_status = leap_status;
switch (leap) {
case LEAP_Normal:
case LEAP_InsertSecond:
case LEAP_DeleteSecond:
instance->leap_status = leap;
break;
default:
instance->leap_status = LEAP_Unsynchronised;
break;
}
log_sample(instance, &cooked_time, 0, offset, offset - correction + instance->offset);
instance->pps_active = 0;
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 +383,15 @@ 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);
leap = LEAP_Normal;
LCL_GetOffsetCorrection(pulse_time, &correction, &dispersion);
UTI_AddDoubleToTimeval(pulse_time, correction, &cooked_time);
dispersion += instance->precision;
if (!valid_sample_time(instance, pulse_time))
return 0;
@@ -372,15 +410,22 @@ 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)) {
DEBUG_LOG(LOGF_Refclock, "refclock pulse ignored no ref sample");
return 0;
}
ref_dispersion += filter_get_avg_sample_dispersion(&refclocks[instance->lock_ref].filter);
UTI_DiffTimevalsToDouble(&sample_diff, &cooked_time, &ref_sample_time);
if (fabs(sample_diff) >= 2.0 / rate)
if (fabs(sample_diff) >= 2.0 / rate) {
DEBUG_LOG(LOGF_Refclock, "refclock pulse ignored samplediff=%.9f",
sample_diff);
return 0;
}
/* Align the offset to the reference sample */
if ((ref_offset - offset) >= 0.0)
@@ -390,14 +435,22 @@ 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) {
DEBUG_LOG(LOGF_Refclock, "refclock pulse ignored offdiff=%.9f refdisp=%.9f disp=%.9f",
ref_offset - offset, ref_dispersion, dispersion);
return 0;
}
#if 0
LOG(LOGS_INFO, LOGF_Refclock, "refclock pulse second=%.9f offset=%.9f offdiff=%.9f samplediff=%.9f",
leap = refclocks[instance->lock_ref].leap_status;
DEBUG_LOG(LOGF_Refclock, "refclock pulse second=%.9f offset=%.9f offdiff=%.9f samplediff=%.9f",
second, offset, ref_offset - offset, sample_diff);
#endif
} else {
struct timeval ref_time;
int is_synchronised, stratum;
double root_delay, root_dispersion, distance;
uint32_t ref_id;
/* Ignore the pulse if we are not well synchronized */
REF_GetReferenceParams(&cooked_time, &is_synchronised, &leap, &stratum,
@@ -405,37 +458,34 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
distance = fabs(root_delay) / 2 + root_dispersion;
if (!is_synchronised || distance >= 0.5 / rate) {
#if 0
LOG(LOGS_INFO, LOGF_Refclock, "refclock pulse dropped second=%.9f sync=%d dist=%.9f",
DEBUG_LOG(LOGF_Refclock, "refclock pulse ignored second=%.9f sync=%d dist=%.9f",
second, is_synchronised, distance);
#endif
/* Drop also all stored samples */
filter_reset(&instance->filter);
return 0;
}
}
#if 0
LOG(LOGS_INFO, LOGF_Refclock, "refclock pulse second=%.9f offset=%.9f",
second, offset);
#endif
filter_add_sample(&instance->filter, &cooked_time, offset, dispersion);
instance->leap_status = leap;
instance->pps_active = 1;
filter_add_sample(&instance->filter, &cooked_time, offset);
instance->leap_status = LEAP_Normal;
log_sample(instance, &cooked_time, 0, 1, offset + correction - instance->offset, offset, dispersion);
log_sample(instance, &cooked_time, 1, second, offset);
/* for logging purposes */
if (!instance->driver->poll)
instance->driver_polled++;
return 1;
}
void
RCL_CycleLogFile(void)
static double
poll_interval(int poll)
{
if (logfile) {
fclose(logfile);
logfile = NULL;
logwrites = 0;
}
if (poll >= 0)
return 1 << poll;
else
return 1.0 / (1 << -poll);
}
static int
@@ -446,8 +496,11 @@ valid_sample_time(RCL_Instance instance, struct timeval *tv)
LCL_ReadRawTime(&raw_time);
UTI_DiffTimevalsToDouble(&diff, &raw_time, tv);
if (diff < 0.0 || diff > 1 << (instance->poll + 1))
if (diff < 0.0 || diff > poll_interval(instance->poll + 1)) {
DEBUG_LOG(LOGF_Refclock, "refclock sample not valid age=%.6f tv=%s",
diff, UTI_TimevalToString(tv));
return 0;
}
return 1;
}
@@ -458,7 +511,7 @@ pps_stratum(RCL_Instance instance, struct timeval *tv)
int is_synchronised, stratum, i;
double root_delay, root_dispersion;
NTP_Leap leap;
unsigned long ref_id;
uint32_t ref_id;
REF_GetReferenceParams(tv, &is_synchronised, &leap, &stratum,
&ref_id, &ref_time, &root_delay, &root_dispersion);
@@ -470,7 +523,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_active && refclocks[i].lock_ref == -1)
return stratum - 1;
}
@@ -480,7 +534,6 @@ pps_stratum(RCL_Instance instance, struct timeval *tv)
static void
poll_timeout(void *arg)
{
double next;
int poll;
RCL_Instance inst = (RCL_Instance)arg;
@@ -499,75 +552,62 @@ 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_active && 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;
SRC_SelectSource(inst->source);
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);
}
}
if (poll >= 0)
next = 1 << poll;
else
next = 1.0 / (1 << -poll);
inst->timeout_id = SCH_AddTimeoutByDelay(next, poll_timeout, arg);
inst->timeout_id = SCH_AddTimeoutByDelay(poll_interval(poll), poll_timeout, arg);
}
static void
slew_samples(struct timeval *raw, struct timeval *cooked, double dfreq, double afreq,
double doffset, int is_step_change, void *anything)
slew_samples(struct timeval *raw, struct timeval *cooked, double dfreq,
double doffset, LCL_ChangeType change_type, void *anything)
{
int i;
for (i = 0; i < n_sources; i++) {
if (change_type == LCL_ChangeUnknownStep)
filter_reset(&refclocks[i].filter);
else
filter_slew_samples(&refclocks[i].filter, cooked, dfreq, doffset);
}
}
static void
add_dispersion(double dispersion, void *anything)
{
int i;
for (i = 0; i < n_sources; i++)
filter_slew_samples(&refclocks[i].filter, cooked, dfreq, doffset);
filter_add_dispersion(&refclocks[i].filter, dispersion);
}
static void
log_sample(RCL_Instance instance, struct timeval *sample_time, int pulse, double raw_offset, double cooked_offset)
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,12 +615,21 @@ 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
filter_init(struct MedianFilter *filter, int length)
filter_init(struct MedianFilter *filter, int length, double max_dispersion)
{
if (length < 1)
length = 1;
@@ -589,13 +638,25 @@ 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->max_var = max_dispersion * max_dispersion;
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 +666,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 +683,33 @@ 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;
DEBUG_LOG(LOGF_Refclock, "filter sample %d t=%s offset=%.9f dispersion=%.9f",
filter->index, UTI_TimevalToString(sample_time), offset, 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,55 +718,189 @@ 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;
}
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;
}
x /= to - from;
y /= to - from;
for (i = from, d = 0.0; i < to; i++)
d += (filter->samples[i].offset - y) * (filter->samples[i].offset - y);
d = sqrt(d / (to - from));
UTI_AddDoubleToTimeval(&filter->samples[0].sample_time, x, sample_time);
*offset = y;
*dispersion = d;
UTI_DiffTimevalsToDouble(&filter->x_data[i], &s->sample_time, &ls->sample_time);
filter->y_data[i] = s->offset;
filter->w_data[i] = s->dispersion;
}
/* 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;
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;
}
/* avoid having zero dispersion */
if (var < 1e-20) {
var = 1e-20;
d = sqrt(var);
}
/* drop the sample if variance is larger than allowed maximum */
if (filter->max_var > 0.0 && var > filter->max_var) {
DEBUG_LOG(LOGF_Refclock, "filter dispersion too large disp=%.9f max=%.9f",
sqrt(var), sqrt(filter->max_var));
return 0;
}
prev_avg_var = filter->avg_var;
/* update exponential moving average of the variance */
if (filter->avg_var_n > 50) {
filter->avg_var += dof / (dof + 50.0) * (var - filter->avg_var);
} else {
filter->avg_var = (filter->avg_var * filter->avg_var_n + var * dof) /
(dof + filter->avg_var_n);
if (filter->avg_var_n == 0)
prev_avg_var = filter->avg_var;
filter->avg_var_n += dof;
}
/* 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,21 +908,22 @@ 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;
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);
prev_offset = filter->samples[i].offset;
UTI_AdjustTimeval(sample, when, sample, &delta_time, dfreq, doffset);
filter->samples[i].offset -= delta_time;
#if 0
LOG(LOGS_INFO, LOGF_Refclock, "i=%d old_off=%.9f new_off=%.9f",
i, prev_offset, filter->samples[i].offset);
#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

@@ -32,16 +32,19 @@
#include "sources.h"
typedef struct {
char driver_name[4];
char *driver_name;
char *driver_parameter;
int driver_poll;
int poll;
int filter_length;
int pps_rate;
unsigned long ref_id;
unsigned long lock_ref_id;
uint32_t ref_id;
uint32_t lock_ref_id;
double offset;
double delay;
double precision;
double max_dispersion;
SRC_SelectOption sel_option;
} RefclockParameters;
typedef struct RCL_Instance_Record *RCL_Instance;
@@ -56,16 +59,14 @@ extern void RCL_Initialise(void);
extern void RCL_Finalise(void);
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);
extern void *RCL_GetDriverData(RCL_Instance instance);
extern char *RCL_GetDriverParameter(RCL_Instance instance);
extern char *RCL_GetDriverOption(RCL_Instance instance, char *name);
extern int RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset, NTP_Leap leap_status);
extern int RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset, int leap);
extern int RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second);
#endif

193
refclock_phc.c Normal file
View File

@@ -0,0 +1,193 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2013
*
* 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.
*
**********************************************************************
=======================================================================
PTP hardware clock (PHC) refclock driver.
*/
#include "config.h"
#include "refclock.h"
#ifdef FEAT_PHC
#include "sysincl.h"
#include <linux/ptp_clock.h>
#include "refclock.h"
#include "logging.h"
#include "util.h"
/* From linux/include/linux/posix-timers.h */
#define CPUCLOCK_MAX 3
#define CLOCKFD CPUCLOCK_MAX
#define CLOCKFD_MASK (CPUCLOCK_PERTHREAD_MASK|CPUCLOCK_CLOCK_MASK)
#define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD)
#define NUM_READINGS 10
static int no_sys_offset_ioctl = 0;
struct phc_reading {
struct timespec sys_ts1;
struct timespec phc_ts;;
struct timespec sys_ts2;
};
static double diff_ts(struct timespec *ts1, struct timespec *ts2)
{
return (ts1->tv_sec - ts2->tv_sec) + (ts1->tv_nsec - ts2->tv_nsec) / 1e9;
}
static int read_phc_ioctl(struct phc_reading *readings, int phc_fd, int n)
{
#if defined(PTP_SYS_OFFSET) && NUM_READINGS <= PTP_MAX_SAMPLES
struct ptp_sys_offset sys_off;
int i;
/* Silence valgrind */
memset(&sys_off, 0, sizeof (sys_off));
sys_off.n_samples = n;
if (ioctl(phc_fd, PTP_SYS_OFFSET, &sys_off)) {
LOG(LOGS_ERR, LOGF_Refclock, "ioctl(PTP_SYS_OFFSET) failed : %s", strerror(errno));
return 0;
}
for (i = 0; i < n; i++) {
readings[i].sys_ts1.tv_sec = sys_off.ts[i * 2].sec;
readings[i].sys_ts1.tv_nsec = sys_off.ts[i * 2].nsec;
readings[i].phc_ts.tv_sec = sys_off.ts[i * 2 + 1].sec;
readings[i].phc_ts.tv_nsec = sys_off.ts[i * 2 + 1].nsec;
readings[i].sys_ts2.tv_sec = sys_off.ts[i * 2 + 2].sec;
readings[i].sys_ts2.tv_nsec = sys_off.ts[i * 2 + 2].nsec;
}
return 1;
#else
/* Not available */
return 0;
#endif
}
static int read_phc_user(struct phc_reading *readings, int phc_fd, int n)
{
clockid_t phc_id;
int i;
phc_id = FD_TO_CLOCKID(phc_fd);
for (i = 0; i < n; i++) {
if (clock_gettime(CLOCK_REALTIME, &readings[i].sys_ts1) ||
clock_gettime(phc_id, &readings[i].phc_ts) ||
clock_gettime(CLOCK_REALTIME, &readings[i].sys_ts2)) {
LOG(LOGS_ERR, LOGF_Refclock, "clock_gettime() failed : %s", strerror(errno));
return 0;
}
}
return 1;
}
static int phc_initialise(RCL_Instance instance)
{
struct ptp_clock_caps caps;
int phc_fd;
char *path;
path = RCL_GetDriverParameter(instance);
phc_fd = open(path, O_RDONLY);
if (phc_fd < 0) {
LOG_FATAL(LOGF_Refclock, "open() failed on %s", path);
return 0;
}
/* Make sure it is a PHC */
if (ioctl(phc_fd, PTP_CLOCK_GETCAPS, &caps)) {
LOG_FATAL(LOGF_Refclock, "ioctl(PTP_CLOCK_GETCAPS) failed : %s", strerror(errno));
return 0;
}
UTI_FdSetCloexec(phc_fd);
RCL_SetDriverData(instance, (void *)(long)phc_fd);
return 1;
}
static void phc_finalise(RCL_Instance instance)
{
close((long)RCL_GetDriverData(instance));
}
static int phc_poll(RCL_Instance instance)
{
struct phc_reading readings[NUM_READINGS];
struct timeval tv;
double offset = 0.0, delay, best_delay = 0.0;
int i, phc_fd, best;
phc_fd = (long)RCL_GetDriverData(instance);
if (!no_sys_offset_ioctl) {
if (!read_phc_ioctl(readings, phc_fd, NUM_READINGS)) {
no_sys_offset_ioctl = 1;
return 0;
}
} else {
if (!read_phc_user(readings, phc_fd, NUM_READINGS))
return 0;
}
/* Find the fastest reading */
for (i = 0; i < NUM_READINGS; i++) {
delay = diff_ts(&readings[i].sys_ts2, &readings[i].sys_ts1);
if (!i || best_delay > delay) {
best = i;
best_delay = delay;
}
}
offset = diff_ts(&readings[best].phc_ts, &readings[best].sys_ts2) + best_delay / 2.0;
tv.tv_sec = readings[best].sys_ts2.tv_sec;
tv.tv_usec = readings[best].sys_ts2.tv_nsec / 1000;
DEBUG_LOG(LOGF_Refclock, "PHC offset: %+.9f delay: %.9f", offset, best_delay);
return RCL_AddSample(instance, &tv, offset, LEAP_Normal);
}
RefclockDriver RCL_PHC_driver = {
phc_initialise,
phc_finalise,
phc_poll
};
#else
RefclockDriver RCL_PHC_driver = { NULL, NULL, NULL };
#endif

View File

@@ -25,11 +25,17 @@
*/
#include "config.h"
#include "refclock.h"
#if HAVE_PPSAPI
#if defined(HAVE_SYS_TIMEPPS_H)
#include <sys/timepps.h>
#elif defined(HAVE_TIMEPPS_H)
#include <timepps.h>
#endif
#include "logging.h"
#include "memory.h"
@@ -57,6 +63,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 +101,7 @@ static int pps_initialise(RCL_Instance instance) {
return 0;
}
pps = MallocNew(struct pps_instance);
pps->handle = handle;
pps->last_seq = 0;
@@ -125,9 +134,7 @@ static int pps_poll(RCL_Instance instance)
ts.tv_nsec = 0;
if (time_pps_fetch(pps->handle, PPS_TSFMT_TSPEC, &pps_info, &ts) < 0) {
#if 0
LOG(LOGS_INFO, LOGF_Refclock, "time_pps_fetch error");
#endif
LOG(LOGS_ERR, LOGF_Refclock, "time_pps_fetch() failed : %s", strerror(errno));
return 0;
}
@@ -140,6 +147,8 @@ static int pps_poll(RCL_Instance instance)
}
if (seq == pps->last_seq || (ts.tv_sec == 0 && ts.tv_nsec == 0)) {
DEBUG_LOG(LOGF_Refclock, "PPS sample ignored seq=%lu ts=%lu.%09lu",
seq, ts.tv_sec, ts.tv_nsec);
return 0;
}

View File

@@ -25,13 +25,14 @@
*/
#include "config.h"
#include "sysincl.h"
#include "refclock.h"
#include "logging.h"
#include "util.h"
#include <sys/types.h>
#include <sys/shm.h>
#define SHMKEY 0x4e545030
struct shmTime {
@@ -43,7 +44,7 @@ struct shmTime {
* use values
* clear valid
*/
int count;
volatile int count;
time_t clockTimeStampSec;
int clockTimeStampUSec;
time_t receiveTimeStampSec;
@@ -51,8 +52,10 @@ struct shmTime {
int leap;
int precision;
int nsamples;
int valid;
int dummy[10];
volatile int valid;
int clockTimeStampNSec;
int receiveTimeStampNSec;
int dummy[8];
};
static int shm_initialise(RCL_Instance instance) {
@@ -87,7 +90,7 @@ static void shm_finalise(RCL_Instance instance)
static int shm_poll(RCL_Instance instance)
{
struct timeval tv1, tv2;
struct timeval tv;
struct shmTime t, *shm;
double offset;
@@ -97,21 +100,24 @@ static int shm_poll(RCL_Instance instance)
if ((t.mode == 1 && t.count != shm->count) ||
!(t.mode == 0 || t.mode == 1) || !t.valid) {
#if 0
LOG(LOGS_INFO, LOGF_Refclock, "sample ignored mode: %d count: %d valid: %d", t.mode, t.count, t.valid);
#endif
DEBUG_LOG(LOGF_Refclock, "SHM sample ignored mode=%d count=%d valid=%d",
t.mode, t.count, t.valid);
return 0;
}
shm->valid = 0;
tv1.tv_sec = t.receiveTimeStampSec;
tv1.tv_usec = t.receiveTimeStampUSec;
tv2.tv_sec = t.clockTimeStampSec;
tv2.tv_usec = t.clockTimeStampUSec;
tv.tv_sec = t.receiveTimeStampSec;
tv.tv_usec = t.receiveTimeStampUSec;
UTI_DiffTimevalsToDouble(&offset, &tv2, &tv1);
return RCL_AddSample(instance, &tv1, offset, t.leap);
offset = t.clockTimeStampSec - t.receiveTimeStampSec;
if (t.clockTimeStampNSec / 1000 == t.clockTimeStampUSec &&
t.receiveTimeStampNSec / 1000 == t.receiveTimeStampUSec)
offset += (t.clockTimeStampNSec - t.receiveTimeStampNSec) * 1e-9;
else
offset += (t.clockTimeStampUSec - t.receiveTimeStampUSec) * 1e-6;
return RCL_AddSample(instance, &tv, offset, t.leap);
}
RefclockDriver RCL_SHM_driver = {

View File

@@ -25,16 +25,15 @@
*/
#include "config.h"
#include "sysincl.h"
#include "refclock.h"
#include "logging.h"
#include "util.h"
#include "sched.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#define SOCK_MAGIC 0x534f434b
struct sock_sample {
@@ -58,23 +57,20 @@ static void read_sample(void *anything)
s = recv(sockfd, &sample, sizeof (sample), 0);
if (s < 0) {
#if 0
LOG(LOGS_INFO, LOGF_Refclock, "Error reading from SOCK socket : %s", strerror(errno));
#endif
LOG(LOGS_ERR, LOGF_Refclock, "Could not read SOCK sample : %s",
strerror(errno));
return;
}
if (s != sizeof (sample)) {
#if 0
LOG(LOGS_INFO, LOGF_Refclock, "Unexpected length of SOCK sample : %d != %d", s, sizeof (sample));
#endif
LOG(LOGS_WARN, LOGF_Refclock, "Unexpected length of SOCK sample : %d != %ld",
s, (long)sizeof (sample));
return;
}
if (sample.magic != SOCK_MAGIC) {
#if 0
LOG(LOGS_INFO, LOGF_Refclock, "Unexpected magic number in SOCK sample : %x != %x", sample.magic, SOCK_MAGIC);
#endif
LOG(LOGS_WARN, LOGF_Refclock, "Unexpected magic number in SOCK sample : %x != %x",
sample.magic, SOCK_MAGIC);
return;
}
@@ -105,6 +101,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");

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,9 @@
/*
$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.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2002
* Copyright (C) Miroslav Lichvar 2014
*
* 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,6 +41,26 @@ extern void REF_Initialise(void);
/* Fini function */
extern void REF_Finalise(void);
typedef enum {
REF_ModeNormal,
REF_ModeInitStepSlew,
REF_ModeUpdateOnce,
REF_ModePrintOnce,
REF_ModeIgnore,
} REF_Mode;
/* Set reference update mode */
extern void REF_SetMode(REF_Mode mode);
/* Get reference update mode */
extern REF_Mode REF_GetMode(void);
/* Function type for handlers to be called back when mode ends */
typedef void (*REF_ModeEndHandler)(int result);
/* Set the handler for being notified of mode ending */
extern void REF_SetModeEndHandler(REF_ModeEndHandler handler);
/* Function which takes a local cooked time and returns the estimated
time of the reference. It also returns the other parameters
required for forming the outgoing NTP packet.
@@ -75,7 +92,7 @@ extern void REF_GetReferenceParams
int *is_synchronised,
NTP_Leap *leap,
int *stratum,
unsigned long *ref_id,
uint32_t *ref_id,
struct timeval *ref_time,
double *root_delay,
double *root_dispersion
@@ -109,10 +126,12 @@ extern void REF_SetReference
(
int stratum,
NTP_Leap leap,
unsigned long ref_id,
int combined_sources,
uint32_t ref_id,
IPAddr *ref_ip,
struct timeval *ref_time,
double offset,
double offset_sd,
double frequency,
double skew,
double root_delay,
@@ -131,7 +150,7 @@ extern void REF_SetManualReference
extern void
REF_SetUnsynchronised(void);
/* Return the current stratum of this host or zero if the host is not
/* Return the current stratum of this host or 16 if the host is not
synchronised */
extern int REF_GetOurStratum(void);
@@ -144,6 +163,4 @@ extern int REF_IsLocalActive(void);
extern void REF_GetTrackingReport(RPT_TrackingReport *rep);
extern void REF_CycleLogFile(void);
#endif /* GOT_REFERENCE_H */

147
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
@@ -29,11 +26,9 @@
*/
#include <assert.h>
#include <math.h>
#include "config.h"
#include <stdio.h>
#include <string.h>
#include "sysincl.h"
#include "regress.h"
#include "logging.h"
@@ -69,9 +64,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++) {
@@ -106,8 +99,6 @@ RGR_WeightedRegression
*sb0 = sqrt(*s2 / W + aa * aa);
*s2 *= (n / W); /* Giving weighted average of variances */
return;
}
/* ================================================== */
@@ -135,6 +126,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 +165,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,9 +209,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
RGR_FindBestRegression
(double *x, /* independent variable */
@@ -205,6 +217,12 @@ 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 */
int min_samples, /* minimum number of samples to be kept after
changing the starting index to pass the runs
test */
/* And now the results */
@@ -228,13 +246,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 && m >= 0);
assert(n * REGRESS_RUNS_RATIO < sizeof (critical_runs) / sizeof (critical_runs[0]));
if (n < MIN_SAMPLES_FOR_REGRESS) {
return 0;
}
@@ -258,20 +279,28 @@ 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 ||
n - start <= min_samples) {
if (start != resid_start) {
/* Ignore extra samples in returned nruns */
nruns = n_runs_from_residuals(resid - resid_start + start, n - start);
}
break;
} else {
/* Try dropping one sample at a time until the runs test passes. */
@@ -286,7 +315,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 +361,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]) {
@@ -363,7 +390,7 @@ find_ordered_entry_with_flags(double *x, int n, int index, int *flags)
l = u + 1;
r = v;
do {
while (x[l] < piv && l < v) l++;
while (l < v && x[l] < piv) l++;
while (x[r] > piv) r--;
if (r <= l) break;
EXCH(x[l], x[r]);
@@ -378,8 +405,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);
@@ -394,7 +419,7 @@ find_ordered_entry(double *x, int n, int index)
{
int flags[MAX_POINTS];
bzero(flags, n * sizeof(int));
memset(flags, 0, n * sizeof(int));
return find_ordered_entry_with_flags(x, n, index, flags);
}
#endif
@@ -498,6 +523,8 @@ RGR_FindBestRobustRegression
double mx, dx, my, dy;
int nruns = 0;
assert(n < MAX_POINTS);
if (n < 2) {
return 0;
} else if (n == 2) {
@@ -543,11 +570,6 @@ RGR_FindBestRobustRegression
b = X / V;
a = my - b*mx;
#if 0
printf("my=%20.12f mx=%20.12f a=%20.12f b=%20.12f\n", my, mx, a, b);
#endif
s2 = 0.0;
for (i=start; i<n; i++) {
resid = y[i] - a - b * x[i];
@@ -558,7 +580,7 @@ RGR_FindBestRobustRegression
Estimate standard deviation of b and expand range about b based
on that. */
sb = sqrt(s2 * W/V);
if (sb > 0.0) {
if (sb > tol) {
incr = 3.0 * sb;
} else {
incr = 3.0 * tol;
@@ -568,6 +590,11 @@ RGR_FindBestRobustRegression
bhi = b;
do {
/* Make sure incr is significant to blo and bhi */
while (bhi + incr == bhi || blo - incr == blo) {
incr *= 2;
}
blo -= incr;
bhi += incr;
@@ -575,8 +602,8 @@ RGR_FindBestRobustRegression
eval_robust_residual(x + start, y + start, n_points, blo, &a, &rlo);
eval_robust_residual(x + start, y + start, n_points, bhi, &a, &rhi);
} while (rlo * rhi > 0.0); /* fn vals have same sign, i.e. root not
in interval. */
} while (rlo * rhi >= 0.0); /* fn vals have same sign or one is zero,
i.e. root not in interval (rlo, rhi). */
/* OK, so the root for b lies in (blo, bhi). Start bisecting */
do {
@@ -591,9 +618,9 @@ RGR_FindBestRobustRegression
bhi = bmid;
rhi = rmid;
} else {
CROAK("Impossible");
assert(0);
}
} while ((bhi - blo) > tol);
} while ((bhi - blo) > tol && (bmid - blo) * (bhi - bmid) > 0.0);
*b0 = a;
*b1 = bmid;
@@ -610,7 +637,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,18 @@ 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
/* Minimum number of samples for regression */
#define MIN_SAMPLES_FOR_REGRESS 3
/* Return a status indicating whether there were enough points to
carry out the regression */
@@ -72,6 +80,12 @@ 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 */
int min_samples, /* minimum number of samples to be kept after
changing the starting index to pass the 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,8 +37,10 @@ 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, RPT_OUTLIER} state;
enum {RPT_NORMAL, RPT_PREFER, RPT_NOSELECT} sel_option;
int reachability;
unsigned long latest_meas_ago; /* seconds */
double orig_latest_meas; /* seconds */
double latest_meas; /* seconds */
@@ -50,20 +48,24 @@ typedef struct {
} RPT_SourceReport ;
typedef struct {
unsigned long ref_id;
uint32_t ref_id;
IPAddr ip_addr;
unsigned long stratum;
unsigned long leap_status;
struct timeval ref_time;
double current_correction;
double last_offset;
double rms_offset;
double freq_ppm;
double resid_freq_ppm;
double skew_ppm;
double root_delay;
double root_dispersion;
double last_update_interval;
} RPT_TrackingReport;
typedef struct {
unsigned long ref_id;
uint32_t ref_id;
IPAddr ip_addr;
unsigned long n_samples;
unsigned long n_runs;
@@ -117,6 +119,7 @@ typedef struct {
int offline;
int burst_online;
int burst_offline;
int unresolved;
} RPT_ActivityReport;
#endif /* GOT_REPORTS_H */

102
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.
**********************************************************************
@@ -27,9 +23,12 @@
*/
#include "config.h"
#include "sysincl.h"
#include "rtc.h"
#include "local.h"
#include "logging.h"
#include "conf.h"
@@ -44,13 +43,12 @@ static int driver_initialised = 0;
static struct {
int (*init)(void);
void (*fini)(void);
void (*time_pre_init)(void);
int (*time_pre_init)(void);
void (*time_init)(void (*after_hook)(void*), void *anything);
void (*start_measurements)(void);
int (*write_parameters)(void);
int (*get_report)(RPT_RTC_Report *report);
int (*trim)(void);
void (*cycle_logfile)(void);
} driver =
{
#if defined LINUX && defined FEAT_RTC
@@ -61,8 +59,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,47 +68,73 @@ static struct {
NULL,
NULL,
NULL,
NULL,
NULL
#endif
};
/* ================================================== */
/* Set the system clock to the time of last modification of driftfile
if it's in the future */
static void
fallback_time_init(void)
{
struct timeval now;
struct stat buf;
char *drift_file;
drift_file = CNF_GetDriftFile();
if (!drift_file)
return;
if (stat(drift_file, &buf))
return;
LCL_ReadCookedTime(&now, NULL);
if (now.tv_sec < buf.st_mtime) {
LCL_ApplyStepOffset(now.tv_sec - buf.st_mtime);
LOG(LOGS_INFO, LOGF_Rtc,
"System clock set from driftfile %s", drift_file);
}
}
/* ================================================== */
void
RTC_Initialise(void)
RTC_Initialise(int initial_set)
{
char *file_name;
int ok;
/* Do an initial read of the RTC and set the system time to it. This
is analogous to what /sbin/hwclock -s would do on Linux. If that fails
or RTC is not supported, set the clock to the time of the last
modification of driftfile, so we at least get closer to the truth. */
if (initial_set) {
if (!driver.time_pre_init || !driver.time_pre_init()) {
fallback_time_init();
}
}
driver_initialised = 0;
/* This is how we tell whether the user wants to load the RTC
driver, if he is on a machine where it is an option. */
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;
} else {
ok = 0;
driver_initialised = 1;
}
} else {
ok = 0;
LOG(LOGS_ERR, LOGF_Rtc, "RTC not supported on this operating system");
}
if (ok) {
driver_initialised = 1;
} else {
driver_initialised = 0;
LOG(LOGS_ERR, LOGF_Rtc, "Real time clock not supported on this operating system");
}
} else {
driver_initialised = 0;
}
return;
}
/* ================================================== */
@@ -141,23 +164,10 @@ RTC_TimeInit(void (*after_hook)(void *), void *anything)
if (driver_initialised) {
(driver.time_init)(after_hook, anything);
} else {
LOG(LOGS_ERR, LOGF_Rtc, "Can't initialise from real time clock, driver not loaded");
(after_hook)(anything);
}
}
/* ================================================== */
/* Do an initial read of the RTC and set the system time to it. This
is analogous to what /sbin/clock -s -u would do on Linux. */
void
RTC_TimePreInit(void)
{
if (driver.time_pre_init) {
(driver.time_pre_init)();
}
}
/* ================================================== */
/* Start the RTC measurement process */
@@ -210,13 +220,3 @@ RTC_Trim(void)
/* ================================================== */
void
RTC_CycleLogFile(void)
{
if (driver_initialised) {
(driver.cycle_logfile)();
}
}
/* ================================================== */

9
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.
**********************************************************************
@@ -32,9 +28,8 @@
#include "reports.h"
extern void RTC_Initialise(void);
extern void RTC_Initialise(int initial_set);
extern void RTC_Finalise(void);
extern void RTC_TimePreInit(void);
extern void RTC_TimeInit(void (*after_hook)(void *), void *anything);
extern void RTC_StartMeasurements(void);
extern int RTC_GetReport(RPT_RTC_Report *report);
@@ -47,6 +42,4 @@ extern int RTC_WriteParameters(void);
extern int RTC_Trim(void);
extern void RTC_CycleLogFile(void);
#endif /* GOT_RTC_H */

View File

@@ -1,12 +1,9 @@
/*
$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.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2012-2014
*
* 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
@@ -30,50 +27,23 @@
*/
#if defined LINUX
#include "config.h"
#ifdef sparc
#define __KERNEL__
#endif
#include "sysincl.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#include <linux/rtc.h>
#include "logging.h"
#include "sched.h"
#include "local.h"
#include "util.h"
#include "sys_linux.h"
#include "reference.h"
#include "regress.h"
#include "rtc.h"
#include "rtc_linux.h"
#include "io_linux.h"
#include "conf.h"
#include "memory.h"
#include "mkdirpp.h"
struct rtc_time {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};
/* ================================================== */
/* Forward prototypes */
@@ -98,9 +68,7 @@ static int fd = -1;
#define LOWEST_MEASUREMENT_PERIOD 15
#define HIGHEST_MEASUREMENT_PERIOD 480
/* Try to avoid doing regression after _every_ sample we accumulate */
#define N_SAMPLES_PER_REGRESSION 4
#define N_SAMPLES_PER_REGRESSION 1
static int measurement_period = LOWEST_MEASUREMENT_PERIOD;
@@ -156,6 +124,9 @@ static double coef_gain_rate;
RTC data file once we have reacquired its offset after the step */
static double saved_coef_gain_rate;
/* Threshold for automatic RTC trimming in seconds, zero when disabled */
static double autotrim_threshold;
/* Filename supplied by config file where RTC coefficients are
stored. */
static char *coefs_file_name;
@@ -180,11 +151,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 +165,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;
@@ -212,7 +174,6 @@ discard_samples(int new_first)
memmove(system_times, system_times + new_first, n_to_save * sizeof(struct timeval));
n_samples = n_to_save;
return;
}
/* ================================================== */
@@ -240,8 +201,6 @@ accumulate_sample(time_t rtc, struct timeval *sys)
++n_samples_since_regression;
}
++n_samples;
return;
}
/* ================================================== */
@@ -258,14 +217,12 @@ run_regression(int new_sample,
{
double rtc_rel[MAX_SAMPLES]; /* Relative times on RTC axis */
double offsets[MAX_SAMPLES]; /* How much the RTC is fast of the system clock */
int i, n;
int i;
double est_intercept, est_slope;
int best_new_start;
if (n_samples > 0) {
n = n_samples - 1;
for (i=0; i<n_samples; i++) {
rtc_rel[i] = rtc_trim[i] + (double)(rtc_sec[i] - rtc_ref);
offsets[i] = ((double) (rtc_ref - system_times[i].tv_sec) -
@@ -307,27 +264,23 @@ run_regression(int new_sample,
static void
slew_samples
(struct timeval *raw, struct timeval *cooked,
double dfreq, double afreq_ppm,
double doffset, int is_step_change,
double dfreq,
double doffset,
LCL_ChangeType change_type,
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);
if (change_type == LCL_ChangeUnknownStep) {
/* Drop all samples. */
n_samples = 0;
}
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,16 +288,13 @@ 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 += dfreq * (1.0 - coef_gain_rate);
}
#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,
DEBUG_LOG(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
}
/* ================================================== */
@@ -422,14 +372,55 @@ t_from_rtc(struct tm *stm) {
/* ================================================== */
static void
read_hwclock_file(const char *hwclock_file)
{
FILE *in;
char line[256];
int i;
if (!hwclock_file)
return;
in = fopen(hwclock_file, "r");
if (!in) {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not open hwclockfile %s",
hwclock_file);
return;
}
/* Read third line from the file. */
for (i = 0; i < 3; i++) {
if (!fgets(line, sizeof(line), in))
break;
}
fclose(in);
if (i == 3 && !strncmp(line, "LOCAL", 5)) {
rtc_on_utc = 0;
} else if (i == 3 && !strncmp(line, "UTC", 3)) {
rtc_on_utc = 1;
} else {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not read LOCAL/UTC setting from hwclockfile %s",
hwclock_file);
}
}
/* ================================================== */
static void
setup_config(void)
{
if (CNF_GetRTCOnUTC()) {
if (CNF_GetRtcOnUtc()) {
rtc_on_utc = 1;
} else {
rtc_on_utc = 0;
}
read_hwclock_file(CNF_GetHwclockFile());
autotrim_threshold = CNF_GetRtcAutotrim();
}
/* ================================================== */
@@ -440,7 +431,6 @@ static void
read_coefs_from_file(void)
{
FILE *in;
char line[256];
if (!tried_to_load_coefs) {
@@ -448,26 +438,17 @@ read_coefs_from_file(void)
tried_to_load_coefs = 1;
in = fopen(coefs_file_name, "r");
if (in) {
if (fgets(line, sizeof(line), in)) {
if (sscanf(line, "%d%ld%lf%lf",
&valid_coefs_from_file,
&file_ref_time,
&file_ref_offset,
&file_rate_ppm) == 4) {
} else {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not parse coefficients line from RTC file %s",
coefs_file_name);
}
if (coefs_file_name && (in = fopen(coefs_file_name, "r"))) {
if (fscanf(in, "%d%ld%lf%lf",
&valid_coefs_from_file,
&file_ref_time,
&file_ref_offset,
&file_rate_ppm) == 4) {
} else {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not read first line from RTC file %s",
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not read coefficients from RTC file %s",
coefs_file_name);
}
fclose(in);
} else {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not open RTC file %s for reading",
coefs_file_name);
}
}
}
@@ -482,6 +463,7 @@ write_coefs_to_file(int valid,time_t ref_time,double offset,double rate)
struct stat buf;
char *temp_coefs_file_name;
FILE *out;
int r1, r2;
/* Create a temporary file with a '.tmp' extension. */
@@ -503,18 +485,25 @@ write_coefs_to_file(int valid,time_t ref_time,double offset,double rate)
}
/* Gain rate is written out in ppm */
fprintf(out, "%1d %ld %.6f %.3f\n",
valid,ref_time, offset, 1.0e6 * rate);
fclose(out);
r1 = fprintf(out, "%1d %ld %.6f %.3f\n",
valid, ref_time, offset, 1.0e6 * rate);
r2 = fclose(out);
if (r1 < 0 || r2) {
Free(temp_coefs_file_name);
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not write to temporary RTC file %s.tmp",
coefs_file_name);
return RTC_ST_BADFILE;
}
/* Clone the file attributes from the existing file if there is one. */
if (!stat(coefs_file_name,&buf)) {
if (chown(temp_coefs_file_name,buf.st_uid,buf.st_gid)) {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not change ownership of temporary RTC file %s.tmp", coefs_file_name);
if (chown(temp_coefs_file_name,buf.st_uid,buf.st_gid) ||
chmod(temp_coefs_file_name,buf.st_mode & 0777)) {
LOG(LOGS_WARN, LOGF_RtcLinux,
"Could not change ownership or permissions of temporary RTC file %s.tmp",
coefs_file_name);
}
chmod(temp_coefs_file_name,buf.st_mode&0777);
}
/* Rename the temporary file to the correct location (see rename(2) for details). */
@@ -541,63 +530,6 @@ write_coefs_to_file(int valid,time_t ref_time,double offset,double rate)
int
RTC_Linux_Initialise(void)
{
int major, minor, patch;
char *direc;
/* Check whether we can support the real time clock.
Linux 1.2.x - haven't checked yet
Linux 1.3.x - don't know, haven't got a system to look at
Linux 2.0.x - For x<=31, using any variant of the adjtimex() call
sets the kernel into a mode where the RTC was updated every 11
minutes. The only way to escape this is to use settimeofday().
Since we need to have sole control over the RTC to be able to
measure its drift rate, and there is no 'notify' callback to warn
you that the kernel is going to do this, I can't see a way to
support this.
Linux 2.0.x - For x>=32 the adjtimex()/RTC behaviour was
modified, so that as long as the STA_UNSYNC flag is set the RTC
is left alone. This is the mode we exploit here, so that the RTC
continues to go its own sweet way, unless we make updates to it
from this module.
Linux 2.1.x - don't know, haven't got a system to look at.
Linux 2.2.x, 2.3.x and 2.4.x are believed to be OK for all
patch levels
*/
SYS_Linux_GetKernelVersion(&major, &minor, &patch);
/* Obviously this test can get more elaborate when we know about
more system types. */
if (major != 2) {
return 0;
} else {
switch (minor) {
case 0:
if (patch <= 31) {
return 0;
}
break;
case 1:
return 0;
break;
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
break; /* OK for all patch levels */
}
}
/* Setup details depending on configuration options */
setup_config();
@@ -608,10 +540,14 @@ RTC_Linux_Initialise(void)
fd = open (CNF_GetRtcDevice(), O_RDWR);
if (fd < 0) {
LOG(LOGS_ERR, LOGF_RtcLinux, "Could not open %s, %s", CNF_GetRtcDevice(), strerror(errno));
LOG(LOGS_ERR, LOGF_RtcLinux, "Could not open RTC device %s : %s",
CNF_GetRtcDevice(), strerror(errno));
return 0;
}
/* Close on exec */
UTI_FdSetCloexec(fd);
n_samples = 0;
n_samples_since_regression = 0;
n_runs = 0;
@@ -627,18 +563,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 +588,6 @@ RTC_Linux_Finalise(void)
(void) RTC_Linux_WriteParameters();
}
if (logfile) {
fclose(logfile);
}
Free(logfilename);
}
/* ================================================== */
@@ -717,6 +639,9 @@ set_rtc(time_t new_rtc_time)
rtc_raw.tm_mday = rtc_tm.tm_mday;
rtc_raw.tm_mon = rtc_tm.tm_mon;
rtc_raw.tm_year = rtc_tm.tm_year;
rtc_raw.tm_wday = rtc_tm.tm_wday;
rtc_raw.tm_yday = rtc_tm.tm_yday;
rtc_raw.tm_isdst = rtc_tm.tm_isdst;
status = ioctl(fd, RTC_SET_TIME, &rtc_raw);
if (status < 0) {
@@ -763,7 +688,7 @@ handle_initial_trim(void)
sys_error_now = rtc_error_now - coef_seconds_fast;
LOG(LOGS_INFO, LOGF_RtcLinux, "System trim from RTC = %f", sys_error_now);
LCL_AccumulateOffset(sys_error_now);
LCL_AccumulateOffset(sys_error_now, 0.0);
} else {
LOG(LOGS_WARN, LOGF_RtcLinux, "No valid file coefficients, cannot trim system time");
}
@@ -773,8 +698,6 @@ handle_initial_trim(void)
(after_init_hook)(after_init_hook_arg);
operating_mode = OM_NORMAL;
return;
}
/* ================================================== */
@@ -786,6 +709,7 @@ handle_relock_after_trim(void)
time_t ref;
double fast, slope;
valid = 0;
run_regression(1, &valid, &ref, &fast, &slope);
if (valid) {
@@ -794,6 +718,7 @@ handle_relock_after_trim(void)
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not do regression after trim");
}
coefs_valid = 0;
n_samples = 0;
n_samples_since_regression = 0;
operating_mode = OM_NORMAL;
@@ -802,8 +727,25 @@ handle_relock_after_trim(void)
/* ================================================== */
/* Day number of 1 Jan 1970 */
#define MJD_1970 40587
static void
maybe_autotrim(void)
{
/* Trim only when in normal mode, the coefficients are fresh, the current
offset is above the threshold and the system clock is synchronized */
if (operating_mode != OM_NORMAL || !coefs_valid || n_samples_since_regression)
return;
if (autotrim_threshold <= 0.0 || fabs(coef_seconds_fast) < autotrim_threshold)
return;
if (REF_GetOurStratum() >= 16)
return;
RTC_Linux_Trim();
}
/* ================================================== */
static void
process_reading(time_t rtc_time, struct timeval *system_time)
@@ -815,9 +757,10 @@ process_reading(time_t rtc_time, struct timeval *system_time)
switch (operating_mode) {
case OM_NORMAL:
if (n_samples_since_regression >= /* 4 */ 1 ) {
if (n_samples_since_regression >= N_SAMPLES_PER_REGRESSION) {
run_regression(1, &coefs_valid, &coef_ref_time, &coef_seconds_fast, &coef_gain_rate);
n_samples_since_regression = 0;
maybe_autotrim();
}
break;
@@ -832,38 +775,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);
}
}
@@ -887,15 +811,10 @@ read_from_device(void *any)
/* This looks like a bad error : the file descriptor was indicating it was
* ready to read but we couldn't read anything. Give up. */
LOG(LOGS_ERR, LOGF_RtcLinux, "Could not read flags %s : %s", CNF_GetRtcDevice(), strerror(errno));
error = 1;
SCH_RemoveInputFileHandler(fd);
switch_interrupts(0); /* Likely to raise error too, but just to be sure... */
close(fd);
fd = -1;
if (logfile) {
fclose(logfile);
logfile = NULL;
}
return;
}
@@ -905,13 +824,13 @@ read_from_device(void *any)
return;
}
if ((data & RTC_UIE) == RTC_UIE) {
if ((data & RTC_UF) == RTC_UF) {
/* Update interrupt detected */
/* Read RTC time, sandwiched between two polls of the system clock
so we can bound any error. */
SCH_GetFileReadyTime(&sys_time);
SCH_GetLastEventTime(&sys_time, NULL, NULL);
status = ioctl(fd, RTC_RD_TIME, &rtc_raw);
if (status < 0) {
@@ -990,7 +909,7 @@ turn_off_interrupt:
break;
default:
CROAK("Impossible");
assert(0);
break;
}
@@ -1043,20 +962,19 @@ RTC_Linux_WriteParameters(void)
/* ================================================== */
/* Try to set the system clock from the RTC, in the same manner as
/sbin/clock -s -u would do. We're not as picky about OS version
/sbin/hwclock -s would do. We're not as picky about OS version
etc in this case, since we have fewer requirements regarding the
RTC behaviour than we do for the rest of the module. */
void
int
RTC_Linux_TimePreInit(void)
{
int fd, status;
struct rtc_time rtc_raw;
struct rtc_time rtc_raw, rtc_raw_retry;
struct tm rtc_tm;
time_t rtc_t, estimated_correct_rtc_t;
long interval;
double accumulated_error = 0.0;
struct timeval new_sys_time;
time_t rtc_t;
double accumulated_error, sys_offset;
struct timeval new_sys_time, old_sys_time;
coefs_file_name = CNF_GetRtcFile();
@@ -1066,10 +984,23 @@ RTC_Linux_TimePreInit(void)
fd = open(CNF_GetRtcDevice(), O_RDONLY);
if (fd < 0) {
return; /* Can't open it, and won't be able to later */
return 0; /* Can't open it, and won't be able to later */
}
status = ioctl(fd, RTC_RD_TIME, &rtc_raw);
/* Retry reading the rtc until both read attempts give the same sec value.
This way the race condition is prevented that the RTC has updated itself
during the first read operation. */
do {
status = ioctl(fd, RTC_RD_TIME, &rtc_raw);
if (status >= 0) {
status = ioctl(fd, RTC_RD_TIME, &rtc_raw_retry);
}
} while (status >= 0 && rtc_raw.tm_sec != rtc_raw_retry.tm_sec);
/* Read system clock */
LCL_ReadCookedTime(&old_sys_time, NULL);
close(fd);
if (status >= 0) {
/* Convert to seconds since 1970 */
@@ -1087,30 +1018,35 @@ RTC_Linux_TimePreInit(void)
/* Work out approximatation to correct time (to about the
nearest second) */
if (valid_coefs_from_file) {
interval = rtc_t - file_ref_time;
accumulated_error = file_ref_offset + (double)(interval) * 1.0e-6 * file_rate_ppm;
/* Correct time */
LOG(LOGS_INFO, LOGF_RtcLinux, "Set system time, error in RTC = %f",
accumulated_error);
estimated_correct_rtc_t = rtc_t - (long)(0.5 + accumulated_error);
accumulated_error = file_ref_offset +
(rtc_t - file_ref_time) * 1.0e-6 * file_rate_ppm;
} else {
estimated_correct_rtc_t = rtc_t - (long)(0.5 + accumulated_error);
accumulated_error = 0.0;
}
new_sys_time.tv_sec = estimated_correct_rtc_t;
new_sys_time.tv_usec = 0;
/* Correct time */
/* Tough luck if this fails */
if (settimeofday(&new_sys_time, NULL) < 0) {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not settimeofday");
new_sys_time.tv_sec = rtc_t;
/* Average error in the RTC reading */
new_sys_time.tv_usec = 500000;
UTI_AddDoubleToTimeval(&new_sys_time, -accumulated_error, &new_sys_time);
UTI_DiffTimevalsToDouble(&sys_offset, &old_sys_time, &new_sys_time);
/* Set system time only if the step is larger than 1 second */
if (fabs(sys_offset) >= 1.0) {
LOG(LOGS_INFO, LOGF_RtcLinux, "Set system time, error in RTC = %f",
accumulated_error);
LCL_ApplyStepOffset(sys_offset);
}
} else {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not convert RTC reading to seconds since 1/1/1970");
return 0;
}
}
close(fd);
return 1;
}
/* ================================================== */
@@ -1139,7 +1075,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 +1093,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);
@@ -1167,6 +1102,11 @@ RTC_Linux_Trim(void)
n_samples = 0;
operating_mode = OM_AFTERTRIM;
/* Estimate the offset in case writertc is called or chronyd
is terminated during rapid sampling */
coef_seconds_fast = -now.tv_usec / 1e6 + 0.5;
coef_ref_time = now.tv_sec;
/* And start rapid sampling, interrupts on now */
if (timeout_running) {
SCH_RemoveTimeout(timeout_id);
@@ -1178,19 +1118,3 @@ RTC_Linux_Trim(void)
return 1;
}
/* ================================================== */
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.
**********************************************************************
@@ -32,11 +28,9 @@
#include "reports.h"
#if defined LINUX
extern int RTC_Linux_Initialise(void);
extern void RTC_Linux_Finalise(void);
extern void RTC_Linux_TimePreInit(void);
extern int RTC_Linux_TimePreInit(void);
extern void RTC_Linux_TimeInit(void (*after_hook)(void *), void *anything);
extern void RTC_Linux_StartMeasurements(void);
@@ -48,6 +42,4 @@ extern int RTC_Linux_Trim(void);
extern void RTC_Linux_CycleLogFile(void);
#endif /* defined LINUX */
#endif /* _GOT_RTC_LINUX_H */

320
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, 2013-2014
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -29,6 +26,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "sched.h"
@@ -58,21 +57,22 @@ static unsigned int n_read_fds;
/* One more than the highest file descriptor that is registered */
static unsigned int one_highest_fd;
/* This assumes that fd_set is implemented as a fixed size array of
bits, possibly embedded inside a record. It might therefore
somewhat non-portable. */
#define FD_SET_SIZE (sizeof(fd_set) * 8)
#ifndef FD_SETSIZE
/* If FD_SETSIZE is not defined, assume that fd_set is implemented
as a fixed size array of bits, possibly embedded inside a record */
#define FD_SETSIZE (sizeof(fd_set) * 8)
#endif
typedef struct {
SCH_FileHandler handler;
SCH_ArbitraryArgument arg;
} FileHandlerEntry;
static FileHandlerEntry file_handlers[FD_SET_SIZE];
static FileHandlerEntry file_handlers[FD_SETSIZE];
/* Last timestamp when a file descriptor became readable */
static struct timeval last_fdready;
/* Timestamp when last select() returned */
static struct timeval last_select_ts, last_select_ts_raw;
static double last_select_ts_err;
/* ================================================== */
@@ -109,6 +109,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,9 +122,8 @@ static void
handle_slew(struct timeval *raw,
struct timeval *cooked,
double dfreq,
double afreq,
double doffset,
int is_step_change,
LCL_ChangeType change_type,
void *anything);
/* ================================================== */
@@ -129,7 +131,6 @@ handle_slew(struct timeval *raw,
void
SCH_Initialise(void)
{
FD_ZERO(&read_fds);
n_read_fds = 0;
@@ -143,9 +144,12 @@ SCH_Initialise(void)
LCL_AddParameterChangeHandler(handle_slew, NULL);
initialised = 1;
LCL_ReadRawTime(&last_select_ts_raw);
last_select_ts = last_select_ts_raw;
return;
srandom(last_select_ts.tv_sec << 16 ^ last_select_ts.tv_usec);
initialised = 1;
}
@@ -154,7 +158,6 @@ SCH_Initialise(void)
void
SCH_Finalise(void) {
initialised = 0;
return; /* Nothing to do for now */
}
/* ================================================== */
@@ -164,16 +167,15 @@ SCH_AddInputFileHandler
(int fd, SCH_FileHandler handler, SCH_ArbitraryArgument arg)
{
if (!initialised) {
CROAK("Should be initialised");
}
assert(initialised);
if (fd >= FD_SETSIZE)
LOG_FATAL(LOGF_Scheduler, "Too many file descriptors");
/* Don't want to allow the same fd to register a handler more than
once without deleting a previous association - this suggests
a bug somewhere else in the program. */
if (FD_ISSET(fd, &read_fds)) {
CROAK("File handler already registered");
}
assert(!FD_ISSET(fd, &read_fds));
++n_read_fds;
@@ -185,8 +187,6 @@ SCH_AddInputFileHandler
if ((fd + 1) > one_highest_fd) {
one_highest_fd = fd + 1;
}
return;
}
@@ -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;
@@ -221,17 +217,20 @@ SCH_RemoveInputFileHandler(int fd)
}
one_highest_fd = fd_to_check;
return;
}
/* ================================================== */
void
SCH_GetFileReadyTime(struct timeval *tv)
SCH_GetLastEventTime(struct timeval *cooked, double *err, struct timeval *raw)
{
*tv = last_fdready;
if (cooked) {
*cooked = last_select_ts;
if (err)
*err = last_select_ts_err;
}
if (raw)
*raw = last_select_ts_raw;
}
/* ================================================== */
@@ -265,7 +264,6 @@ release_tqe(TimerQueueEntry *node)
{
node->next = tqe_free_list;
tqe_free_list = node;
return;
}
/* ================================================== */
@@ -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,8 @@ SCH_AddTimeoutByDelay(double delay, SCH_TimeoutHandler handler, SCH_ArbitraryArg
{
struct timeval now, then;
if (!initialised) {
CROAK("Should be initialised");
}
assert(initialised);
assert(delay >= 0.0);
LCL_ReadRawTime(&now);
UTI_AddDoubleToTimeval(&now, delay, &then);
@@ -332,23 +327,35 @@ 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(min_delay >= 0.0);
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 +365,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 +404,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,48 +422,57 @@ SCH_RemoveTimeout(SCH_TimeoutID id)
/* Release memory back to the operating system */
release_tqe(ptr);
ok = 1;
break;
}
}
assert(ok);
}
/* ================================================== */
/* The current time (now) has to be passed in from the
caller to avoid race conditions */
/* Try to dispatch any timeouts that have already gone by, and
keep going until all are done. (The earlier ones may take so
long to do that the later ones come around by the time they are
completed). */
static int
static void
dispatch_timeouts(struct timeval *now) {
TimerQueueEntry *ptr;
int n_done = 0;
SCH_TimeoutHandler handler;
SCH_ArbitraryArgument arg;
int n_done = 0, n_entries_on_start = n_timer_queue_entries;
while (1) {
LCL_ReadRawTime(now);
if (!(n_timer_queue_entries > 0 &&
UTI_CompareTimevals(now, &(timer_queue.next->tv)) >= 0)) {
break;
}
if ((n_timer_queue_entries > 0) &&
(UTI_CompareTimevals(now, &(timer_queue.next->tv)) >= 0)) {
ptr = timer_queue.next;
last_class_dispatch[ptr->class] = *now;
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);
/* If more timeouts were handled than there were in the timer queue on
start and there are now, assume some code is scheduling timeouts with
negative delays and abort. Make the actual limit higher in case the
machine is temporarily overloaded and dispatching the handlers takes
more time than was delay of a scheduled timeout. */
if (n_done > n_timer_queue_entries * 4 &&
n_done > n_entries_on_start * 4) {
LOG_FATAL(LOGF_Scheduler, "Possible infinite loop in scheduling");
}
}
return n_done;
}
/* ================================================== */
@@ -495,25 +505,85 @@ static void
handle_slew(struct timeval *raw,
struct timeval *cooked,
double dfreq,
double afreq,
double doffset,
int is_step_change,
LCL_ChangeType change_type,
void *anything)
{
TimerQueueEntry *ptr;
struct timeval T1;
double delta;
int i;
if (is_step_change) {
/* We're not interested in anything else - it won't affect the
functionality of timer event dispatching. If a step change
occurs, just shift all the timeouts by the offset */
if (change_type != LCL_ChangeAdjust) {
/* Make sure this handler is invoked first in order to not shift new timers
added from other handlers */
assert(LCL_IsFirstParameterChangeHandler(handle_slew));
/* If a step change occurs, just shift all raw time stamps by the offset */
for (ptr = timer_queue.next; ptr != &timer_queue; ptr = ptr->next) {
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]);
}
UTI_AddDoubleToTimeval(&last_select_ts_raw, -doffset, &last_select_ts_raw);
}
UTI_AdjustTimeval(&last_select_ts, cooked, &last_select_ts, &delta, dfreq, doffset);
}
/* ================================================== */
#define JUMP_DETECT_THRESHOLD 10
static int
check_current_time(struct timeval *prev_raw, struct timeval *raw, int timeout,
struct timeval *orig_select_tv,
struct timeval *rem_select_tv)
{
struct timeval elapsed_min, elapsed_max;
double step, elapsed;
/* Get an estimate of the time spent waiting in the select() call. On some
systems (e.g. Linux) the timeout timeval is modified to return the
remaining time, use that information. */
if (timeout) {
elapsed_max = elapsed_min = *orig_select_tv;
} else if (rem_select_tv && rem_select_tv->tv_sec >= 0 &&
rem_select_tv->tv_sec <= orig_select_tv->tv_sec &&
(rem_select_tv->tv_sec != orig_select_tv->tv_sec ||
rem_select_tv->tv_usec != orig_select_tv->tv_usec)) {
UTI_DiffTimevals(&elapsed_min, orig_select_tv, rem_select_tv);
elapsed_max = elapsed_min;
} else {
if (rem_select_tv)
elapsed_max = *orig_select_tv;
else
UTI_DiffTimevals(&elapsed_max, raw, prev_raw);
elapsed_min.tv_sec = 0;
elapsed_min.tv_usec = 0;
}
if (last_select_ts_raw.tv_sec + elapsed_min.tv_sec >
raw->tv_sec + JUMP_DETECT_THRESHOLD) {
LOG(LOGS_WARN, LOGF_Scheduler, "Backward time jump detected!");
} else if (prev_raw->tv_sec + elapsed_max.tv_sec + JUMP_DETECT_THRESHOLD <
raw->tv_sec) {
LOG(LOGS_WARN, LOGF_Scheduler, "Forward time jump detected!");
} else {
return 1;
}
UTI_DiffTimevalsToDouble(&step, &last_select_ts_raw, raw);
UTI_TimevalToDouble(&elapsed_min, &elapsed);
step += elapsed;
/* Cooked time may no longer be valid after dispatching the handlers */
LCL_NotifyExternalTimeStep(raw, raw, step, fabs(step));
return 0;
}
/* ================================================== */
@@ -522,34 +592,29 @@ void
SCH_MainLoop(void)
{
fd_set rd;
int status;
struct timeval tv, *ptv;
struct timeval now;
int status, errsv;
struct timeval tv, saved_tv, *ptv;
struct timeval now, saved_now, cooked;
double err;
if (!initialised) {
CROAK("Should be initialised");
}
assert(initialised);
while (!need_to_exit) {
/* Copy current set of read file descriptors */
memcpy((void *) &rd, (void *) &read_fds, sizeof(fd_set));
/* Dispatch timeouts and fill now with current raw time */
dispatch_timeouts(&now);
saved_now = now;
/* Try to dispatch any timeouts that have already gone by, and
keep going until all are done. (The earlier ones may take so
long to do that the later ones come around by the time they are
completed). */
/* The timeout handlers may request quit */
if (need_to_exit)
break;
do {
LCL_ReadRawTime(&now);
} while (dispatch_timeouts(&now) > 0);
/* Check whether there is a timeout and set it up */
if (n_timer_queue_entries > 0) {
UTI_DiffTimevals(&tv, &(timer_queue.next->tv), &now);
ptv = &tv;
assert(tv.tv_sec > 0 || tv.tv_usec > 0);
saved_tv = tv;
} else {
ptv = NULL;
@@ -557,32 +622,42 @@ SCH_MainLoop(void)
/* if there are no file descriptors being waited on and no
timeout set, this is clearly ridiculous, so stop the run */
if (!ptv && (n_read_fds == 0)) {
LOG_FATAL(LOGF_Scheduler, "No descriptors or timeout to wait for");
if (!ptv && !n_read_fds) {
LOG_FATAL(LOGF_Scheduler, "Nothing to do");
}
/* Copy current set of read file descriptors */
memcpy((void *) &rd, (void *) &read_fds, sizeof(fd_set));
status = select(one_highest_fd, &rd, NULL, NULL, ptv);
errsv = errno;
LCL_ReadRawTime(&now);
LCL_CookTime(&now, &cooked, &err);
/* Check if the time didn't jump unexpectedly */
if (!check_current_time(&saved_now, &now, status == 0, &saved_tv, ptv)) {
/* Cook the time again after handling the step */
LCL_CookTime(&now, &cooked, &err);
}
last_select_ts_raw = now;
last_select_ts = cooked;
last_select_ts_err = err;
if (status < 0) {
if (!need_to_exit)
CROAK("Status < 0 after select");
if (!need_to_exit && errsv != EINTR) {
LOG_FATAL(LOGF_Scheduler, "select() failed : %s", strerror(errsv));
}
} else if (status > 0) {
/* A file descriptor is ready to read */
LCL_ReadCookedTime(&last_fdready, &err);
dispatch_filehandlers(status, &rd);
} else {
if (status != 0) {
CROAK("Unexpected value from select");
}
/* 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
@@ -590,9 +665,6 @@ SCH_MainLoop(void)
}
}
return;
}
/* ================================================== */
@@ -600,9 +672,7 @@ SCH_MainLoop(void)
void
SCH_QuitProgram(void)
{
if (!initialised) {
CROAK("Should be initialised");
}
assert(initialised);
need_to_exit = 1;
}

24
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);
@@ -60,9 +58,8 @@ extern void SCH_AddInputFileHandler
);
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);
/* Get the time stamp taken after a file descriptor became ready or a timeout expired */
extern void SCH_GetLastEventTime(struct timeval *cooked, double *err, struct timeval *raw);
/* 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 +69,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);

751
sources.c

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,9 @@
/*
$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.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2002
* Copyright (C) Miroslav Lichvar 2014
*
* 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,6 +35,9 @@
#include "ntp.h"
#include "reports.h"
/* Size of the source reachability register */
#define SOURCE_REACH_BITS 8
/* This datatype is used to hold information about sources. The
instance must be passed when calling many of the interface
functions */
@@ -55,10 +55,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(uint32_t ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr);
/* Function to get rid of a source when it is being unconfigured.
This may cause the current reference source to be reselected, if this
@@ -111,23 +118,40 @@ extern void SRC_GetFrequencyRange(SRC_Instance instance, double *lo, double *hi)
extern void SRC_AccumulateSample(SRC_Instance instance, struct timeval *sample_time, double offset, double peer_delay, double peer_dispersion, double root_delay, double root_dispersion, int stratum, NTP_Leap leap_status);
/* This routine sets the source as receiving reachability updates */
extern void SRC_SetActive(SRC_Instance inst);
/* This routine sets the source as not receiving reachability updates */
extern void SRC_UnsetActive(SRC_Instance inst);
/* 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) */
extern void SRC_SelectSource(unsigned long match_addr);
for the local time. Updates are only made to the local reference
if a new source is selected or updated_inst is the selected
reference source. (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(SRC_Instance updated_inst);
/* Force reselecting the best source */
extern void SRC_ReselectSource(void);
/* Set reselect distance */
extern void SRC_SetReselectDistance(double distance);
/* Predict the offset of the local clock relative to a given source at
a given local cooked time. Positive indicates local clock is FAST
@@ -138,12 +162,18 @@ 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);
extern int SRC_IsSyncPeer(SRC_Instance inst);
extern int SRC_IsReachable(SRC_Instance inst);
extern int SRC_ReadNumberOfSources(void);
extern int SRC_ActiveSources(void);
extern int SRC_ReportSource(int index, RPT_SourceReport *report, struct timeval *now);
extern int SRC_ReportSourcestats(int index, RPT_SourcestatsReport *report, struct timeval *now);
@@ -158,5 +188,7 @@ typedef enum {
extern SRC_Skew_Direction SRC_LastSkewChange(SRC_Instance inst);
extern int SRC_Samples(SRC_Instance inst);
#endif /* GOT_SOURCES_H */

File diff suppressed because it is too large Load Diff

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.
**********************************************************************
@@ -42,11 +38,14 @@ extern void SST_Initialise(void);
extern void SST_Finalise(void);
/* This function creates a new instance of the statistics handler */
extern SST_Stats SST_CreateInstance(unsigned long refid, IPAddr *addr);
extern SST_Stats SST_CreateInstance(uint32_t refid, IPAddr *addr);
/* This function deletes an instance of the statistics handler. */
extern void SST_DeleteInstance(SST_Stats inst);
/* This function resets an instance */
extern void SST_ResetInstance(SST_Stats inst);
/* This function accumulates a single sample into the statistics handler
sample_time is the epoch at which the sample is to be considered to
@@ -71,11 +70,6 @@ extern void SST_AccumulateSample(SST_Stats inst, struct timeval *sample_time, do
down to that number of samples. */
extern void SST_DoNewRegression(SST_Stats inst);
/* 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 */
extern void SST_DoUpdateRegression(SST_Stats inst);
/* Return the assumed worst case range of values that this source's
frequency lies within. Frequency is defined as the amount of time
the local clock gains relative to the source per unit local clock
@@ -86,26 +80,17 @@ extern void SST_GetFrequencyRange(SST_Stats inst, double *lo, double *hi);
extern void
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 *offset_lo_limit,
double *offset_hi_limit,
double *root_distance,
double *variance, int *select_ok);
/* Get data needed when setting up tracking on this source */
extern void
SST_GetTrackingData(SST_Stats inst, struct timeval *now,
SST_GetTrackingData(SST_Stats inst, struct timeval *ref_time,
double *average_offset, double *offset_sd,
double *accrued_dispersion,
double *frequency, double *skew);
/* Get parameters for using this source as the reference */
extern void
SST_GetReferenceData(SST_Stats inst, struct timeval *now,
int *stratum, double *offset,
double *root_delay, double *root_dispersion,
double *frequency, double *skew);
double *frequency, double *skew,
double *root_delay, double *root_dispersion);
/* This routine is called when the local machine clock parameters are
changed. It adjusts all existing samples that we are holding for
@@ -125,6 +110,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 +122,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 +143,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 0.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.
**********************************************************************
@@ -29,6 +24,8 @@
Replacement strerror function for systems that don't have it
*/
#include "config.h"
#ifdef SUNOS
#include <errno.h>

14
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.
**********************************************************************
@@ -29,6 +25,8 @@
in the various operating-system specific modules
*/
#include "config.h"
#include "sys.h"
#include "logging.h"
@@ -93,8 +91,6 @@ SYS_Finalise(void)
#if defined(__NetBSD__)
SYS_NetBSD_Finalise();
#endif
return;
}
/* ================================================== */
@@ -106,8 +102,6 @@ void SYS_DropRoot(char *user)
#else
LOG_FATAL(LOGF_Sys, "dropping root privileges not supported");
#endif
return;
}
/* ================================================== */
@@ -119,8 +113,6 @@ void SYS_SetScheduler(int SchedPriority)
#else
LOG_FATAL(LOGF_Sys, "scheduler priority setting not supported");
#endif
return;
}
/* ================================================== */
@@ -132,8 +124,6 @@ void SYS_LockMemory(void)
#else
LOG_FATAL(LOGF_Sys, "memory locking not supported");
#endif
return;
}
/* ================================================== */

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.
**********************************************************************

314
sys_generic.c Normal file
View File

@@ -0,0 +1,314 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2014
*
* 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.
*
**********************************************************************
=======================================================================
Generic driver functions to complete system-specific drivers
*/
#include "config.h"
#include "sysincl.h"
#include "sys_generic.h"
#include "conf.h"
#include "local.h"
#include "localp.h"
#include "logging.h"
#include "sched.h"
#include "util.h"
/* ================================================== */
/* System clock frequency drivers */
static lcl_ReadFrequencyDriver drv_read_freq;
static lcl_SetFrequencyDriver drv_set_freq;
/* Current frequency as requested by the local module (in ppm) */
static double base_freq;
/* Maximum frequency that can be set by drv_set_freq (in ppm) */
static double max_freq;
/* Maximum expected delay in the actual frequency change (e.g. kernel ticks)
in local time */
static double max_freq_change_delay;
/* Maximum allowed frequency offset relative to the base frequency */
static double max_corr_freq;
/* Amount of outstanding offset to process */
static double offset_register;
/* Minimum offset to correct */
#define MIN_OFFSET_CORRECTION 1.0e-9
/* Current frequency offset between base_freq and the real clock frequency
as set by drv_set_freq (not in ppm) */
static double slew_freq;
/* Time (raw) of last update of slewing frequency and offset */
static struct timeval slew_start;
/* Limits for the slew timeout */
#define MIN_SLEW_TIMEOUT 1.0
#define MAX_SLEW_TIMEOUT 1.0e4
/* Scheduler timeout ID and flag if the timer is currently running */
static SCH_TimeoutID slew_timeout_id;
static int slew_timer_running;
/* Suggested offset correction rate (correction time * offset) */
static double correction_rate;
/* Maximum expected offset correction error caused by delayed change in the
real frequency of the clock */
static double slew_error;
/* ================================================== */
static void handle_end_of_slew(void *anything);
static void update_slew(void);
/* ================================================== */
/* Adjust slew_start on clock step */
static void
handle_step(struct timeval *raw, struct timeval *cooked, double dfreq,
double doffset, LCL_ChangeType change_type, void *anything)
{
if (change_type == LCL_ChangeUnknownStep) {
/* Reset offset and slewing */
slew_start = *raw;
offset_register = 0.0;
update_slew();
} else if (change_type == LCL_ChangeStep) {
UTI_AddDoubleToTimeval(&slew_start, -doffset, &slew_start);
}
}
/* ================================================== */
/* End currently running slew and start a new one */
static void
update_slew(void)
{
struct timeval now, end_of_slew;
double old_slew_freq, total_freq, corr_freq, duration;
/* Remove currently running timeout */
if (slew_timer_running)
SCH_RemoveTimeout(slew_timeout_id);
LCL_ReadRawTime(&now);
/* Adjust the offset register by achieved slew */
UTI_DiffTimevalsToDouble(&duration, &now, &slew_start);
offset_register -= slew_freq * duration;
/* Estimate how long should the next slew take */
if (fabs(offset_register) < MIN_OFFSET_CORRECTION) {
duration = MAX_SLEW_TIMEOUT;
} else {
duration = correction_rate / fabs(offset_register);
if (duration < MIN_SLEW_TIMEOUT)
duration = MIN_SLEW_TIMEOUT;
}
/* Get frequency offset needed to slew the offset in the duration
and clamp it to the allowed maximum */
corr_freq = offset_register / duration;
if (corr_freq < -max_corr_freq)
corr_freq = -max_corr_freq;
else if (corr_freq > max_corr_freq)
corr_freq = max_corr_freq;
/* Get the new real frequency and clamp it */
total_freq = base_freq + corr_freq * (1.0e6 - base_freq);
if (total_freq > max_freq)
total_freq = max_freq;
else if (total_freq < -max_freq)
total_freq = -max_freq;
/* Set the new frequency (the actual frequency returned by the call may be
slightly different from the requested frequency due to rounding) */
total_freq = (*drv_set_freq)(total_freq);
/* Compute the new slewing frequency, it's relative to the real frequency to
make the calculation in offset_convert() cheaper */
old_slew_freq = slew_freq;
slew_freq = (total_freq - base_freq) / (1.0e6 - total_freq);
/* Compute the dispersion introduced by changing frequency and add it
to all statistics held at higher levels in the system */
slew_error = fabs((old_slew_freq - slew_freq) * max_freq_change_delay);
if (slew_error >= MIN_OFFSET_CORRECTION)
lcl_InvokeDispersionNotifyHandlers(slew_error);
/* Compute the duration of the slew and clamp it. If the slewing frequency
is zero or has wrong sign (e.g. due to rounding in the frequency driver or
when base_freq is larger than max_freq), use maximum timeout and try again
on the next update. */
if (fabs(offset_register) < MIN_OFFSET_CORRECTION ||
offset_register * slew_freq <= 0.0) {
duration = MAX_SLEW_TIMEOUT;
} else {
duration = offset_register / slew_freq;
if (duration < MIN_SLEW_TIMEOUT)
duration = MIN_SLEW_TIMEOUT;
else if (duration > MAX_SLEW_TIMEOUT)
duration = MAX_SLEW_TIMEOUT;
}
/* Restart timer for the next update */
UTI_AddDoubleToTimeval(&now, duration, &end_of_slew);
slew_timeout_id = SCH_AddTimeout(&end_of_slew, handle_end_of_slew, NULL);
slew_start = now;
slew_timer_running = 1;
DEBUG_LOG(LOGF_SysGeneric, "slew offset=%e corr_rate=%e base_freq=%f total_freq=%f slew_freq=%e duration=%f slew_error=%e",
offset_register, correction_rate, base_freq, total_freq, slew_freq,
duration, slew_error);
}
/* ================================================== */
static void
handle_end_of_slew(void *anything)
{
slew_timer_running = 0;
update_slew();
}
/* ================================================== */
static double
read_frequency(void)
{
return base_freq;
}
/* ================================================== */
static double
set_frequency(double freq_ppm)
{
base_freq = freq_ppm;
update_slew();
return base_freq;
}
/* ================================================== */
static void
accrue_offset(double offset, double corr_rate)
{
offset_register += offset;
correction_rate = corr_rate;
update_slew();
}
/* ================================================== */
/* Determine the correction to generate the cooked time for given raw time */
static void
offset_convert(struct timeval *raw,
double *corr, double *err)
{
double duration;
UTI_DiffTimevalsToDouble(&duration, raw, &slew_start);
*corr = slew_freq * duration - offset_register;
if (err)
*err = fabs(duration) <= max_freq_change_delay ? slew_error : 0.0;
}
/* ================================================== */
/* Positive means currently fast of true time, i.e. jump backwards */
static void
apply_step_offset(double offset)
{
struct timeval old_time, new_time;
double err;
LCL_ReadRawTime(&old_time);
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
if (settimeofday(&new_time, NULL) < 0) {
LOG_FATAL(LOGF_SysGeneric, "settimeofday() failed");
}
LCL_ReadRawTime(&old_time);
UTI_DiffTimevalsToDouble(&err, &old_time, &new_time);
lcl_InvokeDispersionNotifyHandlers(fabs(err));
}
/* ================================================== */
void
SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_set_freq_delay,
lcl_ReadFrequencyDriver sys_read_freq,
lcl_SetFrequencyDriver sys_set_freq,
lcl_ApplyStepOffsetDriver sys_apply_step_offset,
lcl_SetLeapDriver sys_set_leap)
{
max_freq = max_set_freq_ppm;
max_freq_change_delay = max_set_freq_delay * (1.0 + max_freq / 1.0e6);
drv_read_freq = sys_read_freq;
drv_set_freq = sys_set_freq;
base_freq = (*drv_read_freq)();
slew_freq = 0.0;
offset_register = 0.0;
max_corr_freq = CNF_GetMaxSlewRate() / 1.0e6;
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, sys_apply_step_offset ?
sys_apply_step_offset : apply_step_offset,
offset_convert, sys_set_leap);
LCL_AddParameterChangeHandler(handle_step, NULL);
}
/* ================================================== */
void
SYS_Generic_Finalise(void)
{
/* Must *NOT* leave a slew running - clock could drift way off
if the daemon is not restarted */
if (slew_timer_running) {
SCH_RemoveTimeout(slew_timeout_id);
slew_timer_running = 0;
}
(*drv_set_freq)(base_freq);
}
/* ================================================== */

42
sys_generic.h Normal file
View File

@@ -0,0 +1,42 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2014
*
* 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 generic driver
*/
#ifndef GOT_SYS_GENERIC_H
#define GOT_SYS_GENERIC_H
#include "localp.h"
/* Register a completed driver that implements offset functions on top of
provided frequency functions */
extern void SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_set_freq_delay,
lcl_ReadFrequencyDriver sys_read_freq,
lcl_SetFrequencyDriver sys_set_freq,
lcl_ApplyStepOffsetDriver sys_apply_step_offset,
lcl_SetLeapDriver sys_set_leap);
extern void SYS_Generic_Finalise(void);
#endif /* GOT_SYS_GENERIC_H */

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-2012, 2014
*
* 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 +27,10 @@
*/
#ifdef LINUX
#include "config.h"
#include "sysincl.h"
#include <sys/time.h>
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include <ctype.h>
#include <assert.h>
#include <sys/utsname.h>
#if defined(HAVE_SCHED_SETSCHEDULER)
@@ -60,77 +52,38 @@ int LockAll = 0;
#include <grp.h>
#endif
#include "localp.h"
#include "sys_generic.h"
#include "sys_linux.h"
#include "sched.h"
#include "util.h"
#include "conf.h"
#include "logging.h"
#include "wrap_adjtimex.h"
static long current_tick;
/* This is the value of tick, in seconds, including the current vernier
frequency term */
static double current_total_tick;
/* This is the uncompensated system tick value */
static int nominal_tick;
/* This is the scaling required to go between absolute ppm and the
scaled ppm used as an argument to adjtimex. Because chronyd is to an extent
'closed loop' maybe it doesn't matter if this is wrongly determined, UNLESS
the system's ppm error is close to a multiple of HZ, in which case the
relationship between changing the frequency and changing the value of 'tick'
will be wrong. This would (I imagine) cause the system to thrash between
two states.
However..., if this effect was not corrected, and the system is left offline
for a long period, a substantial error would build up. e.g. with HZ==100,
the correction required is 128/128.125, giving a drift of about 84 seconds
per day). */
static double freq_scale;
/* Current tick value */
static int current_delta_tick;
/* The HZ value from the kernel header file (may be over-ridden from config
file, e.g. if chronyd binary is moved to a box whose kernel was built with a
different HZ value). */
/* The maximum amount by which 'tick' can be biased away from 'nominal_tick'
(sys_adjtimex() in the kernel bounds this to 10%) */
static int max_tick_bias;
/* The kernel USER_HZ constant */
static int hz;
static double dhz; /* And dbl prec version of same for arithmetic */
/* Flag indicating whether adjtimex() can step the clock */
static int have_setoffset;
/* The assumed rate at which the effective frequency and tick values are
updated in the kernel */
static int tick_update_hz;
/* ================================================== */
/* The operating system kernel version */
static int version_major;
static int version_minor;
static int version_patchlevel;
/* Flag indicating whether adjtimex() returns the remaining time adjustment
or not. If not we have to read the outstanding adjustment by setting it to
zero, examining the return value and setting the outstanding adjustment back
again. If 1, txc.modes equal to zero is used to read the time. If 2,
txc.modes is set to ADJ_OFFSET_SS_READ. */
static int have_readonly_adjtime;
/* ================================================== */
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;
@@ -139,367 +92,58 @@ our_lround(double x) {
return y;
}
/* ================================================== */
/* Amount of outstanding offset to process */
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 fast slew (one done by altering tick) is being
run at the moment */
static int fast_slewing;
/* The amount by which the fast slew was supposed to slew the clock */
static double fast_slew_wanted;
/* The value programmed into the kernel's 'tick' variable whilst
slewing a large offset */
static long slewing_tick;
/* The timeval (raw) at which a fast slew was started. We need to
know this for two reasons. First, if we want to change the
frequency midway through, we will want to abort the slew and return
the unprocessed portion to the offset register to start again
later. Second, when the end of the slew expires, we need to know
precisely how long we have been slewing for, so that we can negate
the excess and slew it back the other way. */
static struct timeval slew_start_tv;
/* This is the ID returned to use by the scheduler's timeout handler.
We need this if we subsequently wish to abort a slew, because we will have to
dequeue the timeout */
static SCH_TimeoutID slew_timeout_id;
/* The adjustment that we apply to 'tick', in seconds, whilst applying
a fast slew */
static double delta_total_tick;
/* Max amount of time that we wish to slew by using adjtime (or its
equivalent). If more than this is outstanding, we alter the value
of tick instead, for a set period. Set this according to the
amount of time that a dial-up clock might need to be shifted
assuming it is resync'ed about once per day. (TBC) */
#define MAX_ADJUST_WITH_ADJTIME (0.2)
/* The amount by which we alter 'tick' when doing a large slew */
static int slew_delta_tick;
/* The maximum amount by which 'tick' can be biased away from 'nominal_tick'
(sys_adjtimex() in the kernel bounds this to 10%) */
static int max_tick_bias;
/* ================================================== */
/* This routine stops a fast slew, determines how long the slew has
been running for, and consequently how much adjustment has actually
been applied. It can be used both when a slew finishes naturally
due to a timeout, and when a slew is being aborted. */
static void
stop_fast_slew(void)
{
struct timeval T1, T1d, T1a;
struct timezone tz;
double end_window;
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");
}
/* Now set the thing off */
if (gettimeofday(&T1, &tz) < 0) {
CROAK("gettimeofday() failed in stop_fast_slew");
}
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");
}
fast_slewing = 0;
UTI_AverageDiffTimevals(&T1, &T1d, &T1a, &end_window);
UTI_DiffTimevalsToDouble(&slew_duration, &T1a, &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
at higher levels in the system. */
introduced_dispersion = end_window * delta_total_tick;
lcl_InvokeDispersionNotifyHandlers(introduced_dispersion);
fast_slew_done = delta_total_tick * slew_duration /
(current_total_tick + delta_total_tick);
offset_register += (fast_slew_wanted + fast_slew_done);
}
/* ================================================== */
/* This routine is called to start a clock offset adjustment */
static void
initiate_slew(void)
{
double dseconds;
long tick_adjust;
long offset;
struct timeval T0, T0d, T0a;
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");
}
if (offset_register == 0.0) {
return;
}
/* Cancel any standard adjtime that is running */
if (slow_slewing) {
offset = 0;
if (TMX_ApplyOffset(&offset) < 0) {
CROAK("adjtimex() failed in accrue_offset");
}
offset_register -= (double) offset / 1.0e6;
slow_slewing = 0;
}
if (fabs(offset_register) < MAX_ADJUST_WITH_ADJTIME) {
/* Use adjtime to do the shift */
offset = our_lround(1.0e6 * -offset_register);
offset_register += offset * 1e-6;
if (offset != 0) {
if (TMX_ApplyOffset(&offset) < 0) {
CROAK("adjtimex() failed in initiate_slew");
}
slow_slewing = 1;
}
} else {
/* If the system clock has a high drift rate, the combination of
current_tick + slew_delta_tick could be outside the range that adjtimex
will accept. To prevent this, the tick adjustment that is used to slew
an error off the clock is clamped according to what tick_adjust is.
*/
long min_allowed_tick, max_allowed_tick;
min_allowed_tick = nominal_tick - max_tick_bias;
max_allowed_tick = nominal_tick + max_tick_bias;
if (offset_register > 0) {
slewing_tick = current_tick - slew_delta_tick;
if (slewing_tick <= min_allowed_tick) {
slewing_tick = min_allowed_tick + 1;
}
} else {
slewing_tick = current_tick + slew_delta_tick;
if (slewing_tick >= max_allowed_tick) {
slewing_tick = max_allowed_tick - 1;
}
}
tick_adjust = slewing_tick - current_tick;
delta_total_tick = (double) tick_adjust / 1.0e6;
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 (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");
}
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
at higher levels in the system. */
introduced_dispersion = start_window * delta_total_tick;
lcl_InvokeDispersionNotifyHandlers(introduced_dispersion);
fast_slewing = 1;
slew_start_tv = T0a;
/* 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);
slew_timeout_id = SCH_AddTimeout(&end_of_slew, handle_end_of_slew, NULL);
fast_slew_wanted = offset_register;
offset_register = 0.0;
}
return;
}
/* ================================================== */
/* This is the callback routine invoked by the scheduler at the end of
a slew. */
static void
handle_end_of_slew(void *anything)
{
stop_fast_slew();
initiate_slew(); /* To do any fine trimming required */
}
/* ================================================== */
/* This routine is used to abort a slew that is in progress, if any */
static void
abort_slew(void)
{
if (fast_slewing) {
stop_fast_slew();
SCH_RemoveTimeout(slew_timeout_id);
}
}
/* ================================================== */
/* This routine accrues an offset into the offset register, and starts
a slew if required.
The offset argument is measured in seconds. Positive means the
clock needs to be slewed backwards (i.e. is currently fast of true
time) */
static void
accrue_offset(double offset)
{
/* Add the new offset to the register */
offset_register += offset;
if (!fast_slewing) {
initiate_slew();
} /* Otherwise, when the fast slew completes, any other stuff
in the offset register will be applied */
}
/* ================================================== */
/* Positive means currently fast of true time, i.e. jump backwards */
static void
apply_step_offset(double offset)
{
struct timeval old_time, new_time;
struct timezone tz;
if (fast_slewing) {
abort_slew();
if (TMX_ApplyStepOffset(-offset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
if (gettimeofday(&old_time, &tz) < 0) {
CROAK("gettimeofday in apply_step_offset");
}
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
if (settimeofday(&new_time, &tz) < 0) {
CROAK("settimeofday in apply_step_offset");
}
initiate_slew();
}
/* ================================================== */
/* This call sets the Linux kernel frequency to a given value in parts
per million relative to the nominal running frequency. Nominal is taken to
be tick=10000, freq=0 (for a HZ==100 system, other values otherwise). The
convention is that this is called with a positive argument if the local
be tick=10000, freq=0 (for a USER_HZ==100 system, other values otherwise).
The 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;
double required_freq; /* what we use */
double scaled_freq; /* what adjtimex & the kernel use */
double required_freq;
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;
} else {
neg = 0;
}
required_delta_tick = our_round(freq_ppm / dhz);
required_freq = freq_ppm - dhz * (double) required_delta_tick;
if (neg) {
/* Uncompensated local clock runs slow */
required_tick = nominal_tick + required_delta_tick;
scaled_freq = freq_scale * required_freq;
} else {
/* Uncompensated local clock runs fast */
required_tick = nominal_tick - required_delta_tick;
scaled_freq = -freq_scale * required_freq;
/* Older kernels (pre-2.6.18) don't apply the frequency offset exactly as
set by adjtimex() and a scaling constant (that depends on the internal
kernel HZ constant) would be needed to compensate for the error. Because
chronyd is closed loop it doesn't matter much if we don't scale the
required frequency, but we want to prevent thrashing between two states
when the system's frequency error is close to a multiple of USER_HZ. With
USER_HZ <= 250, the maximum frequency adjustment of 500 ppm overlaps at
least two ticks and we can stick to the current tick if it's next to the
required tick. */
if (hz <= 250 && (required_delta_tick + 1 == current_delta_tick ||
required_delta_tick - 1 == current_delta_tick)) {
required_delta_tick = current_delta_tick;
}
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);
required_freq = -(freq_ppm - dhz * required_delta_tick);
required_tick = nominal_tick - required_delta_tick;
if (TMX_SetFrequency(&required_freq, required_tick) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex failed for set_frequency, freq_ppm=%10.4e required_freq=%10.4e required_tick=%ld",
freq_ppm, required_freq, required_tick);
}
current_tick = required_tick;
current_total_tick = ((double)current_tick + required_freq/dhz) / 1.0e6 ;
initiate_slew(); /* Restart any slews that need to be restarted */
return;
current_delta_tick = required_delta_tick;
return dhz * current_delta_tick - required_freq;
}
/* ================================================== */
@@ -508,102 +152,16 @@ set_frequency(double freq_ppm) {
static double
read_frequency(void)
{
double tick_term;
double unscaled_freq;
double freq_term;
long tick;
double freq;
if (TMX_GetFrequency(&unscaled_freq) < 0) {
CROAK("adjtimex failed in read_frequency");
if (TMX_GetFrequency(&freq, &tick) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
/* Use current_tick here rather than txc.tick, otherwise we're
thrown off course when doing a fast slew (in which case, txc.tick
is nowhere near the nominal value) */
tick_term = dhz * (double)(nominal_tick - current_tick);
freq_term = unscaled_freq / freq_scale;
current_delta_tick = nominal_tick - tick;
#if 0
LOG(LOGS_INFO, LOGF_SysLinux, "txc.tick=%ld txc.freq=%ld tick_term=%f freq_term=%f",
txc.tick, txc.freq, tick_term, freq_term);
#endif
return tick_term - freq_term;
}
/* ================================================== */
/* Given a raw time, determine the correction in seconds to generate
the 'cooked' time. The correction has to be added to the
raw time */
static void
get_offset_correction(struct timeval *raw,
double *corr)
{
/* 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 */
double adjtime_left;
double fast_slew_duration;
double fast_slew_achieved;
double fast_slew_remaining;
long offset, 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;
}
break;
case 0:
toffset = 0;
if (TMX_ApplyOffset(&toffset) < 0) {
CROAK("adjtimex() failed in get_offset_correction");
}
offset = toffset;
if (TMX_ApplyOffset(&toffset) < 0) {
CROAK("adjtimex() failed in get_offset_correction");
}
break;
case 1:
if (TMX_GetOffsetLeftOld(&offset) < 0) {
CROAK("adjtimex() failed in get_offset_correction");
}
break;
default:
assert(0);
}
if (offset == 0) {
/* adjtime slew has finished */
slow_slewing = 0;
}
}
adjtime_left = (double)offset / 1.0e6;
if (fast_slewing) {
UTI_DiffTimevalsToDouble(&fast_slew_duration, raw, &slew_start_tv);
fast_slew_achieved = delta_total_tick * fast_slew_duration /
(current_total_tick + delta_total_tick);
fast_slew_remaining = fast_slew_wanted + fast_slew_achieved;
} else {
fast_slew_remaining = 0.0;
}
*corr = - (offset_register + fast_slew_remaining) + adjtime_left;
return;
return dhz * current_delta_tick - freq;
}
/* ================================================== */
@@ -617,16 +175,14 @@ set_leap(int leap)
LOG(LOGS_INFO, LOGF_SysLinux, "System clock status set to %s leap second",
leap ? (leap > 0 ? "insert" : "delete") : "not insert/delete");
return;
}
/* ================================================== */
/* Estimate the value of HZ given the value of txc.tick that chronyd finds when
/* Estimate the value of USER_HZ given the value of txc.tick that chronyd finds when
* it starts. The only credible values are 100 (Linux/x86) or powers of 2.
* Also, the bounds checking inside the kernel's adjtimex system call enforces
* a +/- 10% movement of tick away from the nominal value 1e6/HZ. */
* a +/- 10% movement of tick away from the nominal value 1e6/USER_HZ. */
static void
guess_hz_and_shift_hz(int tick, int *hz, int *shift_hz)
@@ -656,7 +212,43 @@ guess_hz_and_shift_hz(int tick, int *hz, int *shift_hz)
/* oh dear. doomed. */
*hz = 0;
*shift_hz = 0;
return;
}
/* ================================================== */
static int
get_hz_and_shift_hz(int *hz, int *shift_hz)
{
#ifdef _SC_CLK_TCK
if ((*hz = sysconf(_SC_CLK_TCK)) < 1) {
return 0;
}
if (*hz == 100) {
*shift_hz = 7;
return 1;
}
for (*shift_hz = 1; (*hz >> *shift_hz) > 1; (*shift_hz)++)
;
return 1;
#else
return 0;
#endif
}
/* ================================================== */
static int
kernelvercmp(int major1, int minor1, int patch1,
int major2, int minor2, int patch2)
{
if (major1 != major2)
return major1 - major2;
if (minor1 != minor2)
return minor1 - minor2;
return patch1 - patch2;
}
/* ================================================== */
@@ -668,170 +260,59 @@ get_version_specific_details(void)
{
int major, minor, patch;
int shift_hz;
double dshift_hz;
double basic_freq_scale; /* what to use if HZ!=100 */
int config_hz, set_config_hz; /* values of HZ from conf file */
int set_config_freq_scale;
double config_freq_scale;
double calculated_freq_scale;
struct tmx_params tmx_params;
struct utsname uts;
TMX_ReadCurrentParams(&tmx_params);
guess_hz_and_shift_hz(tmx_params.tick, &hz, &shift_hz);
if (!get_hz_and_shift_hz(&hz, &shift_hz)) {
TMX_ReadCurrentParams(&tmx_params);
if (!shift_hz) {
LOG_FATAL(LOGF_SysLinux, "Can't determine hz (txc.tick=%ld txc.freq=%ld (%.8f) txc.offset=%ld)",
tmx_params.tick, tmx_params.freq, tmx_params.dfreq, tmx_params.offset);
} else {
LOG(LOGS_INFO, LOGF_SysLinux, "Initial txc.tick=%ld txc.freq=%ld (%.8f) txc.offset=%ld => hz=%d shift_hz=%d",
tmx_params.tick, tmx_params.freq, tmx_params.dfreq, tmx_params.offset, hz, shift_hz);
guess_hz_and_shift_hz(tmx_params.tick, &hz, &shift_hz);
if (!shift_hz) {
LOG_FATAL(LOGF_SysLinux, "Can't determine hz (txc.tick=%ld txc.freq=%ld (%.8f) txc.offset=%ld)",
tmx_params.tick, tmx_params.freq, tmx_params.dfreq, tmx_params.offset);
}
}
CNF_GetLinuxHz(&set_config_hz, &config_hz);
if (set_config_hz) hz = config_hz;
/* (If true, presumably freq_scale will be overridden anyway, making shift_hz
redundant too.) */
dhz = (double) hz;
dshift_hz = (double)(1UL << shift_hz);
basic_freq_scale = dshift_hz / dhz;
nominal_tick = (1000000L + (hz/2))/hz; /* Mirror declaration in kernel */
slew_delta_tick = nominal_tick / 12;
max_tick_bias = nominal_tick / 10;
LOG(LOGS_INFO, LOGF_SysLinux, "set_config_hz=%d hz=%d shift_hz=%d basic_freq_scale=%.8f nominal_tick=%d slew_delta_tick=%d max_tick_bias=%d",
set_config_hz, hz, shift_hz, basic_freq_scale, nominal_tick, slew_delta_tick, max_tick_bias);
/* The basic_freq_scale comes from:
* the kernel increments the usec counter HZ times per second (if the timer
interrupt period were perfect)
* the following code in the kernel
time_adj (+/-)= ltemp >>
(SHIFT_USEC + SHIFT_HZ - SHIFT_SCALE);
causes the adjtimex 'freq' value to be divided down by 1<<SHIFT_HZ.
The net effect is that we have to scale up the value we want by the
reciprocal of all this, i.e. multiply by (1<<SHIFT_HZ)/HZ.
If HZ==100, this code in the kernel comes into play too:
#if HZ == 100
* Compensate for (HZ==100) != (1 << SHIFT_HZ).
* Add 25% and 3.125% to get 128.125; => only 0.125% error (p. 14)
*
if (time_adj < 0)
time_adj -= (-time_adj >> 2) + (-time_adj >> 5);
else
time_adj += (time_adj >> 2) + (time_adj >> 5);
#endif
Special case that later.
*/
/* We can't reliably detect the internal kernel HZ, it may not even be fixed
(CONFIG_NO_HZ aka tickless), assume the lowest commonly used fixed rate */
tick_update_hz = 100;
if (uname(&uts) < 0) {
LOG_FATAL(LOGF_SysLinux, "Cannot uname(2) to get kernel version, sorry.");
}
if (sscanf(uts.release, "%d.%d.%d", &major, &minor, &patch) != 3) {
patch = 0;
if (sscanf(uts.release, "%d.%d.%d", &major, &minor, &patch) < 2) {
LOG_FATAL(LOGF_SysLinux, "Cannot read information from uname, sorry");
}
LOG(LOGS_INFO, LOGF_SysLinux, "Linux kernel major=%d minor=%d patch=%d", major, minor, patch);
DEBUG_LOG(LOGF_SysLinux, "Linux kernel major=%d minor=%d patch=%d", major, minor, patch);
version_major = major;
version_minor = minor;
version_patchlevel = patch;
switch (major) {
case 1:
/* Does Linux v1.x even support HZ!=100? */
switch (minor) {
case 2:
if (patch == 13) {
freq_scale = (hz==100) ? (128.0 / 100.0) : basic_freq_scale ; /* I _think_! */
have_readonly_adjtime = 1;
} else {
LOG_FATAL(LOGF_SysLinux, "Kernel version not supported yet, sorry.");
}
break;
case 3:
/* I guess the change from the 1.2.x scaling to the 2.0.x
scaling must have happened during 1.3 development. I
haven't a clue where though, until someone looks it
up. */
LOG_FATAL(LOGF_SysLinux, "Kernel version not supported yet, sorry.");
break;
default:
LOG_FATAL(LOGF_SysLinux, "Kernel version not supported yet, sorry.");
break;
}
break;
case 2:
switch (minor) {
case 0:
if (patch < 32) {
freq_scale = (hz==100) ? (128.0 / 125.0) : basic_freq_scale;
have_readonly_adjtime = 1;
} else if (patch >= 32) {
freq_scale = (hz==100) ? (128.0 / 128.125) : basic_freq_scale;
/* The functionality in kernel/time.c in the kernel source
was modified with regard to what comes back in the
txc.offset field on return from adjtimex. If txc.modes
was ADJ_OFFSET_SINGLESHOT on entry, the outstanding
adjustment is returned, however the running offset will
be modified to the passed value. */
have_readonly_adjtime = 0;
}
break;
case 1:
/* I know that earlier 2.1 kernels were like 2.0.31, hence
the settings below. However, the 2.0.32 behaviour may
have been added late in the 2.1 series, however I have no
idea at which patch level. Leave it like this until
someone supplies some info. */
freq_scale = (hz==100) ? (128.0 / 125.0) : basic_freq_scale;
have_readonly_adjtime = 0; /* For safety ! */
break;
case 2:
case 3:
case 4:
case 5:
case 6:
if (minor < 6 || patch < 27) {
/* These seem to be like 2.0.32 */
freq_scale = (hz==100) ? (128.0 / 128.125) : basic_freq_scale;
have_readonly_adjtime = 0;
break;
}
/* Let's be optimistic that these will be the same until proven
otherwise :-) */
case 7:
case 8:
/* These don't need scaling */
freq_scale = 1.0;
have_readonly_adjtime = 2;
break;
default:
LOG_FATAL(LOGF_SysLinux, "Kernel version not supported yet, sorry.");
}
break;
default:
LOG_FATAL(LOGF_SysLinux, "Kernel's major version not supported yet, sorry");
break;
if (kernelvercmp(major, minor, patch, 2, 2, 0) < 0) {
LOG_FATAL(LOGF_SysLinux, "Kernel version not supported, sorry.");
}
/* Override freq_scale if it appears in conf file */
CNF_GetLinuxFreqScale(&set_config_freq_scale, &config_freq_scale);
calculated_freq_scale = freq_scale;
if (set_config_freq_scale) freq_scale = config_freq_scale;
LOG(LOGS_INFO, LOGF_SysLinux, "calculated_freq_scale=%.8f freq_scale=%.8f",
calculated_freq_scale, freq_scale);
if (kernelvercmp(major, minor, patch, 2, 6, 27) >= 0 &&
kernelvercmp(major, minor, patch, 2, 6, 33) < 0) {
/* Tickless kernels before 2.6.33 accumulated ticks only in
half-second intervals */
tick_update_hz = 2;
}
/* ADJ_SETOFFSET support */
if (kernelvercmp(major, minor, patch, 2, 6, 39) < 0) {
have_setoffset = 0;
} else {
have_setoffset = 1;
}
DEBUG_LOG(LOGF_SysLinux, "hz=%d nominal_tick=%d max_tick_bias=%d",
hz, nominal_tick, max_tick_bias);
}
/* ================================================== */
@@ -840,17 +321,24 @@ get_version_specific_details(void)
void
SYS_Linux_Initialise(void)
{
offset_register = 0.0;
fast_slewing = 0;
get_version_specific_details();
current_tick = nominal_tick;
current_total_tick = 1.0 / dhz;
if (TMX_ResetOffset() < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, apply_step_offset,
get_offset_correction, set_leap);
if (have_setoffset && TMX_TestStepOffset() < 0) {
LOG(LOGS_INFO, LOGF_SysLinux, "adjtimex() doesn't support ADJ_SETOFFSET");
have_setoffset = 0;
}
TMX_SetSync(CNF_GetRtcSync());
SYS_Generic_CompleteFreqDriver(1.0e6 * max_tick_bias / nominal_tick,
1.0 / tick_update_hz,
read_frequency, set_frequency,
have_setoffset ? apply_step_offset : NULL,
set_leap);
}
/* ================================================== */
@@ -859,19 +347,7 @@ SYS_Linux_Initialise(void)
void
SYS_Linux_Finalise(void)
{
/* Must *NOT* leave a fast slew running - clock would drift way off
if the daemon is not restarted */
abort_slew();
}
/* ================================================== */
void
SYS_Linux_GetKernelVersion(int *major, int *minor, int *patchlevel)
{
*major = version_major;
*minor = version_minor;
*patchlevel = version_patchlevel;
SYS_Generic_Finalise();
}
/* ================================================== */
@@ -916,7 +392,7 @@ SYS_Linux_DropRoot(char *user)
cap_free(cap);
LOG(LOGS_INFO, LOGF_SysLinux, "Privileges dropped to user %s", user);
DEBUG_LOG(LOGF_SysLinux, "Privileges dropped to user %s", user);
}
#endif
@@ -945,7 +421,8 @@ void SYS_Linux_SetScheduler(int SchedPriority)
LOG(LOGS_ERR, LOGF_SysLinux, "sched_setscheduler() failed");
}
else {
LOG(LOGS_INFO, LOGF_SysLinux, "Enabled SCHED_FIFO with priority %d", sched.sched_priority);
DEBUG_LOG(LOGF_SysLinux, "Enabled SCHED_FIFO with priority %d",
sched.sched_priority);
}
}
}
@@ -969,15 +446,9 @@ void SYS_Linux_MemLockAll(int LockAll)
LOG(LOGS_ERR, LOGF_SysLinux, "mlockall() failed");
}
else {
LOG(LOGS_INFO, LOGF_SysLinux, "Successfully locked into RAM");
DEBUG_LOG(LOGF_SysLinux, "Successfully locked into RAM");
}
}
}
}
#endif /* HAVE_MLOCKALL */
#endif /* LINUX */
/* vim:ts=8
* */

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.
**********************************************************************
@@ -35,8 +31,6 @@ extern void SYS_Linux_Initialise(void);
extern void SYS_Linux_Finalise(void);
extern void SYS_Linux_GetKernelVersion(int *major, int *minor, int *patchlevel);
extern void SYS_Linux_DropRoot(char *user);
extern void SYS_Linux_MemLockAll(int LockAll);

Some files were not shown because too many files have changed in this diff Show More