mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-03 18:35:06 -05:00
Compare commits
58 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a7cf6a5ce | ||
|
|
c2f83bd8a4 | ||
|
|
1f0e6296c6 | ||
|
|
ab1f01bacd | ||
|
|
b9b896d8e7 | ||
|
|
6be54f366c | ||
|
|
802cdb3230 | ||
|
|
7e27880cb6 | ||
|
|
d3ad85aa43 | ||
|
|
59192fc695 | ||
|
|
9095b80c5b | ||
|
|
ed5b78bf09 | ||
|
|
d6aafa3f64 | ||
|
|
8de04a808d | ||
|
|
2a299233b3 | ||
|
|
64f83c8861 | ||
|
|
1009fe3d9c | ||
|
|
ba341fe81a | ||
|
|
36e8cb6530 | ||
|
|
273da62aec | ||
|
|
41788184a7 | ||
|
|
fb9c2c7dc8 | ||
|
|
43116be122 | ||
|
|
ee038d5de5 | ||
|
|
ea7fae5277 | ||
|
|
70b108ab69 | ||
|
|
08b152d6a2 | ||
|
|
83c6213c67 | ||
|
|
4253075a97 | ||
|
|
0abdc2a350 | ||
|
|
31669f343a | ||
|
|
438b881ab4 | ||
|
|
27863146a3 | ||
|
|
cd4b73612b | ||
|
|
3c217a9e37 | ||
|
|
cde3a003ea | ||
|
|
2c35f56612 | ||
|
|
4295db25d7 | ||
|
|
3c06e57f24 | ||
|
|
e949cf5967 | ||
|
|
4eeaf34295 | ||
|
|
2212a90698 | ||
|
|
dc52b61dad | ||
|
|
bbf4c3186b | ||
|
|
f72016a78e | ||
|
|
29b587a9c5 | ||
|
|
cec4f2b140 | ||
|
|
05278c3b4c | ||
|
|
1769b8ea0f | ||
|
|
5686bd87d7 | ||
|
|
1cda2db45d | ||
|
|
fdf9640349 | ||
|
|
8f2d5d99f1 | ||
|
|
61272e7ce8 | ||
|
|
88b76f49cc | ||
|
|
ad942e352d | ||
|
|
39c2bcd462 | ||
|
|
ae10664b24 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -2,6 +2,8 @@
|
||||
.vimrc
|
||||
*.o
|
||||
*.swp
|
||||
*.dSYM
|
||||
*.DS_Store
|
||||
RELEASES
|
||||
Makefile
|
||||
chrony.conf.5
|
||||
|
||||
10
Makefile.in
10
Makefile.in
@@ -73,12 +73,14 @@ $(HASH_OBJ) : $(patsubst %.o,%.c,$(HASH_OBJ))
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) @HASH_COMPILE@ -c $<
|
||||
|
||||
distclean : clean
|
||||
-rm -f .DS_Store
|
||||
-rm -f Makefile
|
||||
-rm -f chrony.conf.5 chrony.texi chronyc.1 chronyd.8
|
||||
|
||||
clean :
|
||||
-rm -f *.o *.s chronyc chronyd core *~ chrony.info chrony.html chrony.txt
|
||||
-rm -rf .deps
|
||||
-rm -rf *.dSYM
|
||||
|
||||
getdate.c :
|
||||
bison -o getdate.c getdate.y
|
||||
@@ -112,8 +114,6 @@ install: chronyd chronyc chrony.txt
|
||||
chmod 644 $(DESTDIR)$(DOCDIR)/COPYING
|
||||
cp README $(DESTDIR)$(DOCDIR)/README
|
||||
chmod 644 $(DESTDIR)$(DOCDIR)/README
|
||||
cp chrony.1 $(DESTDIR)$(MANDIR)/man1
|
||||
chmod 644 $(DESTDIR)$(MANDIR)/man1/chrony.1
|
||||
cp chronyc.1 $(DESTDIR)$(MANDIR)/man1
|
||||
chmod 644 $(DESTDIR)$(MANDIR)/man1/chronyc.1
|
||||
cp chronyd.8 $(DESTDIR)$(MANDIR)/man8
|
||||
@@ -152,6 +152,12 @@ chrony.html : chrony.texi
|
||||
chrony.info : chrony.texi
|
||||
makeinfo chrony.texi
|
||||
|
||||
Makefile : Makefile.in configure
|
||||
@echo
|
||||
@echo Makefile needs to be regenerated, run ./configure
|
||||
@echo
|
||||
@exit 1
|
||||
|
||||
.deps:
|
||||
@mkdir .deps
|
||||
|
||||
|
||||
33
NEWS
33
NEWS
@@ -1,3 +1,31 @@
|
||||
New in version 2.1.1
|
||||
====================
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix clock stepping by integer number of seconds on Linux
|
||||
|
||||
New in version 2.1
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add support for Mac OS X
|
||||
* Try to replace unreachable and falseticker servers/peers specified
|
||||
by name like pool sources
|
||||
* Add leaponly option to smoothtime directive to allow synchronised
|
||||
leap smear between multiple servers
|
||||
* Use specific reference ID when smoothing served time
|
||||
* Add smoothing command to report time smoothing status
|
||||
* Add smoothtime command to activate or reset time smoothing
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix crash in source selection with preferred sources
|
||||
* Fix resetting of time smoothing
|
||||
* Include packet precision in peer dispersion
|
||||
* Fix crash in chronyc on invalid command syntax
|
||||
|
||||
New in version 2.0
|
||||
==================
|
||||
|
||||
@@ -15,7 +43,7 @@ Enhancements
|
||||
* Improve source selection
|
||||
* Handle offline sources as unreachable
|
||||
* Open NTP server port only when necessary (client access is allowed by
|
||||
allow directive/command, peer or broadcast is configured)
|
||||
allow directive/command or peer/broadcast is configured)
|
||||
* Change default bindcmdaddress to loopback address
|
||||
* Change default maxdelay to 3 seconds
|
||||
* Change default stratumweight to 0.001
|
||||
@@ -30,6 +58,7 @@ Bug fixes
|
||||
---------
|
||||
* Add sanity checks for time and frequency offset
|
||||
* Don't report synchronised status during leap second
|
||||
* Don't combine reference clocks with close NTP sources
|
||||
* Fix accepting requests from configured sources
|
||||
* Fix initial fallback drift setting
|
||||
|
||||
@@ -39,7 +68,7 @@ New in version 1.31.1
|
||||
Security fixes
|
||||
--------------
|
||||
* Protect authenticated symmetric NTP associations against DoS attacks
|
||||
(CVE-2015-1799)
|
||||
(CVE-2015-1853)
|
||||
* Fix access configuration with subnet size indivisible by 4 (CVE-2015-1821)
|
||||
* Fix initialization of reply slots for authenticated commands (CVE-2015-1822)
|
||||
|
||||
|
||||
84
README
84
README
@@ -3,67 +3,35 @@ This is the README for chrony.
|
||||
What is chrony?
|
||||
===============
|
||||
|
||||
Chrony is a pair of programs for maintaining the accuracy of computer
|
||||
clocks.
|
||||
chrony is a versatile implementation of the Network Time Protocol (NTP).
|
||||
It can synchronize the system clock with NTP servers, reference clocks
|
||||
(e.g. GPS receiver), and manual input using wristwatch and keyboard.
|
||||
It can also operate as an NTPv4 (RFC 5905) server and peer to provide
|
||||
a time service to other computers in the network.
|
||||
|
||||
chronyd is a (background) daemon program that can be started at boot
|
||||
time. This does most of the work.
|
||||
It is designed to perform well in a wide range of conditions, including
|
||||
intermittent network connections, heavily congested networks, changing
|
||||
temperatures (ordinary computer clocks are sensitive to temperature),
|
||||
and systems that do not run continuosly, or run on a virtual machine.
|
||||
|
||||
chronyc is a command-line interface program which can be used to
|
||||
monitor chronyd's performance and to change various operating
|
||||
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
|
||||
accordingly. It also works out the rate at which the system clock
|
||||
gains or loses time and uses this information to keep it accurate
|
||||
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.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 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
|
||||
reboots.
|
||||
|
||||
Typical accuracies available between 2 machines are
|
||||
|
||||
On an ethernet LAN : 100-200 microseconds, often much better
|
||||
On a V32bis dial-up modem connection : 10's of milliseconds (from one
|
||||
session to the next)
|
||||
|
||||
With a good reference clock the accuracy can reach one microsecond.
|
||||
|
||||
chronyd can also operate as an NTPv4 (RFC 5905) server, peer and broadcast
|
||||
server.
|
||||
Typical accuracy between two machines on a LAN is in tens, or a few
|
||||
hundreds, of microseconds; over the Internet, accuracy is typically
|
||||
within a few milliseconds. With a good hardware reference clock
|
||||
sub-microsecond accuracy is possible.
|
||||
|
||||
Two programs are included in chrony, chronyd is a daemon that can be
|
||||
started at boot time and chronyc is a command-line interface program
|
||||
which can be used to monitor chronyd's performance and to change various
|
||||
operating parameters whilst it is running.
|
||||
|
||||
What will chrony run on?
|
||||
========================
|
||||
|
||||
Chrony can be successfully built and run on
|
||||
|
||||
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)
|
||||
|
||||
3. SunOS 4.1.4 (Sparc 2 and Sparc 20)
|
||||
|
||||
4. BSD/386 v1.1 has been reported to work using the SunOS 4.1 driver.
|
||||
|
||||
5. NetBSD.
|
||||
|
||||
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.
|
||||
The software is known to work on Linux, FreeBSD, NetBSD, Mac OS X and
|
||||
Solaris. Closely related systems may work too. Any other system will
|
||||
likely 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.
|
||||
|
||||
How do I set it up?
|
||||
===================
|
||||
@@ -116,6 +84,11 @@ chrony-dev-request@chrony.tuxfamily.org
|
||||
|
||||
as applicable.
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
chrony is distributed under the GNU General Public License version 2.
|
||||
|
||||
|
||||
Author
|
||||
======
|
||||
@@ -155,6 +128,9 @@ Stephan I. Boettcher <stephan@nevis1.columbia.edu>
|
||||
Erik Bryer <ebryer@spots.ab.ca>
|
||||
Entries in contrib directory
|
||||
|
||||
Bryan Christianson <bryan@whatroute.net>
|
||||
Support for Mac OS X
|
||||
|
||||
Juliusz Chroboczek <jch@pps.jussieu.fr>
|
||||
Fix install rule in Makefile if chronyd file is in use.
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997,1998,1999,2000,2001,2002,2005
|
||||
* Copyright (C) Miroslav Lichvar 2009
|
||||
* Copyright (C) Miroslav Lichvar 2009, 2015
|
||||
*
|
||||
* 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
|
||||
|
||||
12
array.c
12
array.c
@@ -44,6 +44,8 @@ ARR_CreateInstance(unsigned int elem_size)
|
||||
{
|
||||
ARR_Instance array;
|
||||
|
||||
assert(elem_size > 0);
|
||||
|
||||
array = MallocNew(struct ARR_Instance_Record);
|
||||
|
||||
array->data = NULL;
|
||||
@@ -64,6 +66,9 @@ ARR_DestroyInstance(ARR_Instance array)
|
||||
static void
|
||||
realloc_array(ARR_Instance array, unsigned int min_size)
|
||||
{
|
||||
size_t data_size;
|
||||
|
||||
assert(min_size <= 2 * min_size);
|
||||
if (array->allocated >= min_size && array->allocated <= 2 * min_size)
|
||||
return;
|
||||
|
||||
@@ -74,7 +79,10 @@ realloc_array(ARR_Instance array, unsigned int min_size)
|
||||
array->allocated = min_size;
|
||||
}
|
||||
|
||||
array->data = Realloc(array->data, array->elem_size * array->allocated);
|
||||
data_size = (size_t)array->elem_size * array->allocated;
|
||||
assert(data_size / array->elem_size == array->allocated);
|
||||
|
||||
array->data = Realloc(array->data, data_size);
|
||||
}
|
||||
|
||||
void *
|
||||
@@ -89,7 +97,7 @@ void *
|
||||
ARR_GetElement(ARR_Instance array, unsigned int index)
|
||||
{
|
||||
assert(index < array->used);
|
||||
return (void *)((char *)array->data + index * array->elem_size);
|
||||
return (void *)((char *)array->data + (size_t)index * array->elem_size);
|
||||
}
|
||||
|
||||
void *
|
||||
|
||||
92
candm.h
92
candm.h
@@ -89,7 +89,9 @@
|
||||
#define REQ_RESELECT 48
|
||||
#define REQ_RESELECTDISTANCE 49
|
||||
#define REQ_MODIFY_MAKESTEP 50
|
||||
#define N_REQUEST_TYPES 51
|
||||
#define REQ_SMOOTHING 51
|
||||
#define REQ_SMOOTHTIME 52
|
||||
#define N_REQUEST_TYPES 53
|
||||
|
||||
/* Special utoken value used to log on with first exchange being the
|
||||
password. (This time value has long since gone by) */
|
||||
@@ -116,6 +118,10 @@ typedef struct {
|
||||
pktlength.c, to get the number of bytes that ought to be
|
||||
transmitted for each packet type. */
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Null;
|
||||
|
||||
typedef struct {
|
||||
IPAddr mask;
|
||||
IPAddr address;
|
||||
@@ -215,19 +221,11 @@ typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Manual;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_N_Sources;
|
||||
|
||||
typedef struct {
|
||||
int32_t index;
|
||||
int32_t EOR;
|
||||
} REQ_Source_Data;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Rekey;
|
||||
|
||||
typedef struct {
|
||||
IPAddr ip;
|
||||
int32_t subnet_bits;
|
||||
@@ -264,10 +262,6 @@ typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Del_Source;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_WriteRtc;
|
||||
|
||||
typedef struct {
|
||||
Float dfreq;
|
||||
int32_t EOR;
|
||||
@@ -279,27 +273,11 @@ typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Doffset;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Tracking;
|
||||
|
||||
typedef struct {
|
||||
uint32_t index;
|
||||
int32_t EOR;
|
||||
} REQ_Sourcestats;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_RTCReport;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_TrimRTC;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_CycleLogs;
|
||||
|
||||
/* This is based on the response size rather than the
|
||||
request size */
|
||||
#define MAX_CLIENT_ACCESSES 8
|
||||
@@ -310,32 +288,24 @@ typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_ClientAccessesByIndex;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_ManualList;
|
||||
|
||||
typedef struct {
|
||||
int32_t index;
|
||||
int32_t EOR;
|
||||
} REQ_ManualDelete;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_MakeStep;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Activity;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Reselect;
|
||||
|
||||
typedef struct {
|
||||
Float distance;
|
||||
int32_t EOR;
|
||||
} REQ_ReselectDistance;
|
||||
|
||||
#define REQ_SMOOTHTIME_RESET 0
|
||||
#define REQ_SMOOTHTIME_ACTIVATE 1
|
||||
|
||||
typedef struct {
|
||||
int32_t option;
|
||||
int32_t EOR;
|
||||
} REQ_SmoothTime;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#define PKT_TYPE_CMD_REQUEST 1
|
||||
@@ -365,7 +335,7 @@ typedef struct {
|
||||
|
||||
Version 6 : added padding to requests to prevent amplification attack,
|
||||
changed maximum number of samples in manual list to 16, new commands: modify
|
||||
makestep
|
||||
makestep, smoothing report, smoothtime command
|
||||
*/
|
||||
|
||||
#define PROTO_VERSION_NUMBER 6
|
||||
@@ -398,6 +368,7 @@ typedef struct {
|
||||
uint32_t token; /* Command token (to prevent replay attack) */
|
||||
|
||||
union {
|
||||
REQ_Null null;
|
||||
REQ_Online online;
|
||||
REQ_Offline offline;
|
||||
REQ_Burst burst;
|
||||
@@ -415,28 +386,18 @@ typedef struct {
|
||||
REQ_Settime settime;
|
||||
REQ_Local local;
|
||||
REQ_Manual manual;
|
||||
REQ_N_Sources n_sources;
|
||||
REQ_Source_Data source_data;
|
||||
REQ_Rekey rekey;
|
||||
REQ_Allow_Deny allow_deny;
|
||||
REQ_Ac_Check ac_check;
|
||||
REQ_NTP_Source ntp_source;
|
||||
REQ_Del_Source del_source;
|
||||
REQ_WriteRtc writertc;
|
||||
REQ_Dfreq dfreq;
|
||||
REQ_Doffset doffset;
|
||||
REQ_Tracking tracking;
|
||||
REQ_Sourcestats sourcestats;
|
||||
REQ_RTCReport rtcreport;
|
||||
REQ_TrimRTC trimrtc;
|
||||
REQ_CycleLogs cyclelogs;
|
||||
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;
|
||||
REQ_SmoothTime smoothtime;
|
||||
} data; /* Command specific parameters */
|
||||
|
||||
/* The following fields only set the maximum size of the packet.
|
||||
@@ -472,7 +433,8 @@ typedef struct {
|
||||
#define RPY_CLIENT_ACCESSES_BY_INDEX 10
|
||||
#define RPY_MANUAL_LIST 11
|
||||
#define RPY_ACTIVITY 12
|
||||
#define N_REPLY_TYPES 13
|
||||
#define RPY_SMOOTHING 13
|
||||
#define N_REPLY_TYPES 14
|
||||
|
||||
/* Status codes */
|
||||
#define STT_SUCCESS 0
|
||||
@@ -627,6 +589,19 @@ typedef struct {
|
||||
int32_t EOR;
|
||||
} RPY_Activity;
|
||||
|
||||
#define RPY_SMT_FLAG_ACTIVE 0x1
|
||||
#define RPY_SMT_FLAG_LEAPONLY 0x2
|
||||
|
||||
typedef struct {
|
||||
uint32_t flags;
|
||||
Float offset;
|
||||
Float freq_ppm;
|
||||
Float wander_ppm;
|
||||
Float last_update_ago;
|
||||
Float remaining_time;
|
||||
int32_t EOR;
|
||||
} RPY_Smoothing;
|
||||
|
||||
typedef struct {
|
||||
uint8_t version;
|
||||
uint8_t pkt_type;
|
||||
@@ -653,6 +628,7 @@ typedef struct {
|
||||
RPY_ClientAccessesByIndex client_accesses_by_index;
|
||||
RPY_ManualList manual_list;
|
||||
RPY_Activity activity;
|
||||
RPY_Smoothing smoothing;
|
||||
} data; /* Reply specific parameters */
|
||||
|
||||
/* authentication of the packet, there is no hole after the actual data
|
||||
|
||||
72
chrony.1
72
chrony.1
@@ -1,72 +0,0 @@
|
||||
.TH CHRONY 1 "@MAN_DATE@" "chrony @VERSION@" "User's Manual"
|
||||
.SH NAME
|
||||
chrony \- programs for keeping computer clocks accurate
|
||||
|
||||
.SH SYNOPSIS
|
||||
\fBchronyc\fR [\fIOPTIONS\fR]
|
||||
|
||||
\fBchronyd\fR [\fIOPTIONS\fR]
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBchrony\fR is a pair of programs for keeping computer clocks accurate.
|
||||
\fIchronyd\fR is a background (daemon) program and \fIchronyc\fR is a
|
||||
command-line interface to it. Time reference sources for chronyd can be
|
||||
NTP servers, human (via keyboard and \fIchronyc\fR), or 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 while no external
|
||||
reference is present. Its use of NTP servers can be switched on and off
|
||||
(through \fIchronyc\fR) to support computers with dial-up/intermittent access
|
||||
to the Internet, and it can also act as an 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
|
||||
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
|
||||
accordingly. It also works out the rate at which the system clock
|
||||
gains or loses time and uses this information to keep it accurate
|
||||
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.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 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
|
||||
reboots.
|
||||
|
||||
Typical accuracies available between 2 machines are
|
||||
|
||||
On an ethernet LAN : 100-200 microseconds, often much better
|
||||
On a V32bis dial-up modem connection : 10's of milliseconds (from one
|
||||
session to the next)
|
||||
|
||||
With a good reference clock the accuracy can reach one microsecond.
|
||||
|
||||
\fIchronyd\fR can also operate as an NTPv4 (RFC 5905) server, peer and
|
||||
broadcast server.
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.BR chronyc(1),
|
||||
.BR chrony.conf(5),
|
||||
.BR chronyd(8)
|
||||
|
||||
.I http://chrony.tuxfamily.org/
|
||||
|
||||
.SH AUTHOR
|
||||
Richard Curnow <rc@rc0.org.uk>
|
||||
|
||||
This man-page was written by Jan Schaumann <jschauma@netmeister.org> as part
|
||||
of "The Missing Man Pages Project". Please see
|
||||
\fIhttp://www.netmeister.org/misc/m2p2/index.html\fR for details.
|
||||
|
||||
The complete chrony documentation is supplied in texinfo format.
|
||||
|
||||
@@ -40,9 +40,8 @@ useful configuration file would look something like
|
||||
|
||||
When using a pool of NTP servers (one name is used for multiple servers which
|
||||
may change over time), it's better to specify them with the `pool' directive
|
||||
instead of multiple `server' directives in order to allow \fIchronyd\fR to
|
||||
replace unreachable or bad servers automatically. The configuration file could
|
||||
in this case look like
|
||||
instead of multiple `server' directives. The configuration file could in this
|
||||
case look like
|
||||
|
||||
.EX
|
||||
pool pool.ntp.org iburst
|
||||
@@ -52,7 +51,6 @@ in this case look like
|
||||
.EE
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.BR chrony(1),
|
||||
.BR chronyc(1),
|
||||
.BR chronyd(8)
|
||||
|
||||
|
||||
620
chrony.texi.in
620
chrony.texi.in
@@ -24,7 +24,7 @@
|
||||
@page
|
||||
@vskip 0pt plus 1filll
|
||||
Copyright @copyright{} 1997-1999 Richard P. Curnow
|
||||
Copyright @copyright{} 2009-2014 Miroslav Lichvar
|
||||
Copyright @copyright{} 2009-2015 Miroslav Lichvar
|
||||
@end titlepage
|
||||
@c }}}
|
||||
@c {{{ Top node
|
||||
@@ -35,7 +35,6 @@ Copyright @copyright{} 2009-2014 Miroslav Lichvar
|
||||
* Installation:: How to compile and install the software
|
||||
* Typical scenarios:: How to configure the software for some common cases
|
||||
* Usage reference:: Reference manual
|
||||
* FAQ:: Answers to some common questions about chrony
|
||||
* GPL:: The GNU General Public License
|
||||
@end menu
|
||||
@c }}}
|
||||
@@ -56,34 +55,30 @@ Copyright @copyright{} 2009-2014 Miroslav Lichvar
|
||||
@c {{{ S:Overview
|
||||
@node Overview
|
||||
@section Overview
|
||||
Chrony is a software package for maintaining the accuracy of computer
|
||||
system clocks. It consists of a pair of programs :
|
||||
chrony is a versatile implementation of the Network Time Protocol (NTP).
|
||||
It can synchronize the system clock with NTP servers, reference clocks
|
||||
(e.g. GPS receiver), and manual input using wristwatch and keyboard.
|
||||
It can also operate as an NTPv4 (RFC 5905) server and peer to provide
|
||||
a time service to other computers in the network.
|
||||
|
||||
@itemize @bullet
|
||||
@item @code{chronyd}. This is a daemon which runs in background on the
|
||||
system. It obtains measurements (e.g. via the network) of the system's
|
||||
offset relative to other systems, and adjusts the system time
|
||||
accordingly. For isolated systems, the user can periodically enter the
|
||||
correct time by hand (using @code{chronyc}). In either case,
|
||||
@code{chronyd} determines the rate at which the computer gains or loses
|
||||
time, and compensates for this.
|
||||
It is designed to perform well in a wide range of conditions, including
|
||||
intermittent network connections, heavily congested networks, changing
|
||||
temperatures (ordinary computer clocks are sensitive to temperature),
|
||||
and systems that do not run continuosly, or run on a virtual machine.
|
||||
|
||||
@code{chronyd} can also act as an NTP server, and provide a time-of-day service
|
||||
to other computers. A typical set-up is to run @code{chronyd} on a gateway
|
||||
computer that has a dial-up link to the Internet, and use it to serve time to
|
||||
computers on a private LAN sitting behind the gateway. The IP addresses that
|
||||
can act as clients of @code{chronyd} can be tightly controlled. The default is
|
||||
no client access.
|
||||
Typical accuracy between two machines on a LAN is in tens, or a few
|
||||
hundreds, of microseconds; over the Internet, accuracy is typically
|
||||
within a few milliseconds. With a good hardware reference clock
|
||||
sub-microsecond accuracy is possible.
|
||||
|
||||
@item @code{chronyc}. This is a command-line driven control and
|
||||
monitoring program. An administrator can use this to fine-tune various
|
||||
parameters within the daemon, add or delete servers etc whilst the
|
||||
daemon is running.
|
||||
Two programs are included in chrony, @code{chronyd} is a daemon that can
|
||||
be started at boot time and @code{chronyc} is a command-line interface
|
||||
program which can be used to monitor @code{chronyd}'s performance and to
|
||||
change various operating parameters whilst it is running.
|
||||
|
||||
The IP addresses from which @code{chronyc} clients may connect can be tightly
|
||||
controlled. The default is just the computer that @code{chronyd} itself is
|
||||
running on.
|
||||
@end itemize
|
||||
@c }}}
|
||||
@c {{{ S:Acknowledgments
|
||||
@node Acknowledgements
|
||||
@@ -123,24 +118,10 @@ different operating systems may provide different function calls to
|
||||
achieve this, and even where the same function is used it may have
|
||||
different quirks in its behaviour.
|
||||
|
||||
The software is known to work in the following environments:
|
||||
@itemize @bullet
|
||||
@item Linux 2.2 and newer
|
||||
|
||||
@item NetBSD
|
||||
@item BSD/386
|
||||
|
||||
@item Solaris 2.3/2.5/2.5.1/2.6/2.7/2.8 on Sparc (Sparc 20, Ultrasparc) and
|
||||
i386
|
||||
|
||||
@item SunOS 4.1.4 on Sparc 2 and Sparc20.
|
||||
@end itemize
|
||||
|
||||
Closely related systems may work too, but they have not been tested.
|
||||
|
||||
Porting the software to other system (particularly to those supporting
|
||||
an @code{adjtime} system call) should not be difficult, however it
|
||||
requires access to such systems to test out the driver.
|
||||
The software is known to work on Linux, FreeBSD, NetBSD, Mac OS X and Solaris.
|
||||
Closely related systems may work too. Porting the software to other systems
|
||||
(particularly to those supporting an @code{adjtime} system call) should not be
|
||||
difficult, however it requires access to such systems to test out the driver.
|
||||
@c }}}
|
||||
@c {{{ S:Other programs
|
||||
@node Other time synchronisation packages
|
||||
@@ -305,8 +286,7 @@ Particular areas that need addressing are :
|
||||
@item Porting to other Unices
|
||||
|
||||
This involves creating equivalents of sys_solaris.c, sys_linux.c etc for the
|
||||
new system. Note, the Linux driver has been reported as working on a range of
|
||||
different architectures (Alpha, Sparc, MIPS as well as x86 of course).
|
||||
new system.
|
||||
|
||||
@item Porting to Windows NT
|
||||
|
||||
@@ -600,9 +580,8 @@ rtcsync
|
||||
|
||||
When using a pool of NTP servers (one name is used for multiple servers which
|
||||
may change over time), it's better to specify them with the @code{pool}
|
||||
directive instead of multiple @code{server} directives in order to allow
|
||||
@code{chronyd} to replace unreachable or bad servers automatically. The
|
||||
configuration file could in this case look like
|
||||
directive instead of multiple @code{server} directives. The configuration file
|
||||
could in this case look like
|
||||
|
||||
@example
|
||||
pool pool.ntp.org iburst
|
||||
@@ -1012,9 +991,8 @@ configuration file. This option is useful if you want to stop and
|
||||
restart @code{chronyd} briefly for any reason, e.g. to install a new
|
||||
version. However, it only makes sense on systems where the kernel can
|
||||
maintain clock compensation whilst not under @code{chronyd's} control.
|
||||
The only version where this happens so far is Linux. On systems where
|
||||
this is not the case, e.g. Solaris and SunOS the option should not be
|
||||
used.
|
||||
The only version where this happens so far is Linux. On other systems
|
||||
this option should not be used.
|
||||
@item -R
|
||||
When this option is used, the @code{initstepslew} directive and the
|
||||
@code{makestep} directive used with a positive limit will be ignored.
|
||||
@@ -1812,33 +1790,37 @@ start with the @code{generatecommandkey} directive.
|
||||
@c {{{ leapsecmode
|
||||
@node leapsecmode directive
|
||||
@subsection leapsecmode
|
||||
This directive selects how @code{chronyd} handles leap seconds. The Unix time
|
||||
doesn't include leap seconds. When a leap second is applied to UTC, the system
|
||||
clock is off by one second and it needs to be corrected.
|
||||
A leap second is an adjustment that is occasionally applied to UTC to keep it
|
||||
close to the mean solar time. When a leap second is inserted, the last day of
|
||||
June or December has an extra second 23:59:60.
|
||||
|
||||
There are four options:
|
||||
For computer clocks that is a problem. The Unix time is defined as number of
|
||||
seconds since 00:00:00 UTC on 1 January 1970 without leap seconds. The system
|
||||
clock cannot have time 23:59:60, every minute has 60 seconds and every day has
|
||||
86400 seconds by definition. The inserted leap second is skipped and the clock
|
||||
is suddenly ahead of UTC by one second. The @code{leapsecmode} directive
|
||||
selects how that error is corrected. There are four options:
|
||||
|
||||
@table @code
|
||||
@item system
|
||||
The kernel steps the system clock backwards by one second at 0:00:00 UTC
|
||||
(before correction) when leap second is inserted or steps forward by one second
|
||||
at 23:59:59 UTC when leap second is deleted. This is the default mode when the
|
||||
system driver supports leap seconds (currently Linux only).
|
||||
When inserting a leap second, the kernel steps the system clock backwards by
|
||||
one second when the clock gets to 00:00:00 UTC. When deleting a leap second,
|
||||
it steps forward by one second when the clock gets to 23:59:59 UTC. This is
|
||||
the default mode when the system driver supports leap seconds (currently Linux
|
||||
only).
|
||||
@item step
|
||||
This is similar to the system mode, except the clock is stepped by
|
||||
@code{chronyd} instead of the kernel. This is the default mode when the system
|
||||
driver doesn't support leap seconds.
|
||||
This is similar to the @code{system} mode, except the clock is stepped by
|
||||
@code{chronyd} instead of the kernel. It can be useful to avoid bugs in the
|
||||
kernel code that would be executed in the @code{system} mode. This is the
|
||||
default mode when the system driver doesn't support leap seconds.
|
||||
@item slew
|
||||
The clock is corrected by slew starting at 0:00:00 UTC when leap second is
|
||||
inserted or 23:59:59 UTC when leap second is deleted. This may be preferred
|
||||
over the system or step mode when applications running on the system are
|
||||
sensitive to jumps in the system time and it's acceptable that the clock will
|
||||
be off for a longer time. On Linux with the default @code{maxslewrate} the
|
||||
correction takes 12 seconds. Note that unless the @code{smoothtime} directive
|
||||
is used (@pxref{smoothtime directive}), there will still be a jump in the time
|
||||
that @code{chronyd} serves to NTP clients. With the @code{smoothtime}
|
||||
directive, the leap second status will not be passed to NTP clients and the
|
||||
leap second will be "smeared" instead.
|
||||
The clock is corrected by slewing started at 00:00:00 UTC when a leap second is
|
||||
inserted or 23:59:59 UTC when a leap second is deleted. This may be preferred
|
||||
over the @code{system} and @code{step} modes when applications running on the
|
||||
system are sensitive to jumps in the system time and it's acceptable that the
|
||||
clock will be off for a longer time. On Linux with the default
|
||||
@code{maxslewrate} value (@pxref{maxslewrate directive}) the correction takes
|
||||
12 seconds.
|
||||
@item ignore
|
||||
No correction is applied to the clock for the leap second. The clock will be
|
||||
corrected later in normal operation when new measurements are made and the
|
||||
@@ -1851,19 +1833,40 @@ An example of the command is
|
||||
leapsecmode slew
|
||||
@end example
|
||||
|
||||
An example enabling the leap smear for NTP clients with the @code{smoothtime}
|
||||
directive could be
|
||||
When serving time to NTP clients that can't be configured to correct their
|
||||
clocks for a leap second by slewing or they would correct them at slightly
|
||||
different rates when it's necessary to keep them close together, the
|
||||
@code{slew} mode can be combined with the @code{smoothtime} directive
|
||||
(@pxref{smoothtime directive}) to enable a server leap smear.
|
||||
|
||||
When smearing a leap second, the leap status is suppressed on the server and
|
||||
the served time is corrected slowly be slewing instead of stepping. The clients
|
||||
don't need any special configuration as they don't know there is any leap
|
||||
second and they follow the server time which eventually brings them back to
|
||||
UTC. Care must be taken to ensure they use for synchronization only NTP
|
||||
servers which smear the leap second in exactly the same way.
|
||||
|
||||
This feature needs to be used carefully, because the server is intentionally
|
||||
not serving its best estimate of the true time.
|
||||
|
||||
A recommended configuration to enable a server leap smear is:
|
||||
|
||||
@example
|
||||
leapsecmode slew
|
||||
smoothtime 400 0.001
|
||||
maxslewrate 1000
|
||||
smoothtime 400 0.001 leaponly
|
||||
@end example
|
||||
|
||||
With this configuration the NTP clients would not know there was any leap
|
||||
second. The server time they follow would be slowly corrected in about 16
|
||||
hours after the leap second was applied to UTC. This configuration should not
|
||||
be used if the clients poll also other NTP servers, because they could reject
|
||||
this server as a falseticker or could fail to select a source completely.
|
||||
The first directive is necessary to disable the clock step which would reset
|
||||
the smoothing process. The second directive limits the slewing rate of the
|
||||
local clock to 1000 ppm, which improves the stability of the smoothing process
|
||||
when the local correction starts and ends. The third directive enables the
|
||||
server time smoothing process. It will start when the clock gets to 00:00:00
|
||||
UTC and it will take 17 hours 34 minutes to finish. The frequency offset will
|
||||
be changing by 0.001 ppm per second and will reach maximum of 31.623 ppm. The
|
||||
@code{leaponly} option makes the duration of the leap smear constant and allows
|
||||
the clients to safely synchronise with multiple identically configured leap
|
||||
smearing servers.
|
||||
@c }}}
|
||||
@c {{{ leapsectz
|
||||
@node leapsectz directive
|
||||
@@ -2543,6 +2546,21 @@ be reported using the @code{clients} command in @code{chronyc}.
|
||||
The syntax of this directive is identical to that for the @code{server}
|
||||
directive (@pxref{server directive}), except that it is used to specify
|
||||
an NTP peer rather than an NTP server.
|
||||
|
||||
Please note that NTP peers that are not configured with a key to enable
|
||||
authentication are vulnerable to a denial-of-service attack. An attacker
|
||||
knowing that NTP hosts A and B are peering with each other can send a packet
|
||||
with random timestamps to host A with source address of B which will set the
|
||||
NTP state variables on A to the values sent by the attacker. Host A will then
|
||||
send on its next poll to B a packet with originate timestamp that doesn't match
|
||||
the transmit timestamp of B and the packet will be dropped. If the attacker
|
||||
does this periodically for both hosts, they won't be able to synchronize to
|
||||
each other.
|
||||
|
||||
This attack can be prevented by enabling authentication with the key option, or
|
||||
using the @code{server} directive on both sides to specify the other host as a
|
||||
server instead of peer, the only drawback is that it will double the network
|
||||
traffic between the two hosts.
|
||||
@c }}}
|
||||
@c {{{ pidfile
|
||||
@node pidfile directive
|
||||
@@ -3047,19 +3065,34 @@ it and keep their clocks close together even when large offset or frequency
|
||||
corrections are applied to the server's clock, for example after being offline
|
||||
for a longer time.
|
||||
|
||||
If a large offset has been accumulated, it may take a very long time to smooth
|
||||
it out. This directive should be used only when the clients are not configured
|
||||
to poll also another NTP server, because they could reject this server as a
|
||||
falseticker or fail to select a source completely.
|
||||
BE WARNED - the server is intentionally not serving its best estimate of the
|
||||
true time. If a large offset has been accumulated, it may take a very long
|
||||
time to smooth it out. This directive should be used only when the clients are
|
||||
not configured to poll also another NTP server, because they could reject this
|
||||
server as a falseticker or fail to select a source completely.
|
||||
|
||||
The smoothing process is independent from any slewing applied to the local
|
||||
system clock, but the accumulated offset and frequency for smoothing will be
|
||||
reset when the clock is corrected by step, e.g. by the @code{makestep}
|
||||
directive or command.
|
||||
The smoothing process is implemented with a quadratic spline function with two
|
||||
or three pieces. It's independent from any slewing applied to the local system
|
||||
clock, but the accumulated offset and frequency will be reset when the clock is
|
||||
corrected by stepping, e.g. by the @code{makestep} directive or command. The
|
||||
process can be reset without stepping the clock by the @code{smoothtime reset}
|
||||
command (@pxref{smoothtime command}).
|
||||
|
||||
The directive takes two arguments, the maximum frequency offset of the smoothed
|
||||
time to the tracked NTP time (in ppm) and the maximum rate at which the
|
||||
frequency offset is allowed to change (in ppm per second).
|
||||
The first two arguments of the directive are the maximum frequency offset of
|
||||
the smoothed time to the tracked NTP time (in ppm) and the maximum rate at
|
||||
which the frequency offset is allowed to change (in ppm per second).
|
||||
@code{leaponly} is an optional third argument which enables a mode where only
|
||||
leap seconds are smoothed out and normal offset/frequency changes are ignored.
|
||||
The @code{leaponly} option is useful in a combination with the
|
||||
@code{leapsecmode slew} option (@pxref{leapsecmode directive}) to allow clients
|
||||
use multiple time smoothing servers safely.
|
||||
|
||||
The smoothing process is activated automatically when 1/10000 of the estimated
|
||||
skew of the local clock falls below the maximum rate of frequency change. It
|
||||
can be also activated manually by the @code{smoothtime activate} command,
|
||||
which is particularly useful when the clock is synchronized only with manual
|
||||
input and the skew is always larger than the threshold. The @code{smoothing}
|
||||
command (@pxref{smoothing command}) can be used to monitor the process.
|
||||
|
||||
An example suitable for clients using @code{ntpd} and 1024 second polling
|
||||
interval could be
|
||||
@@ -3288,6 +3321,7 @@ password:
|
||||
@item @code{password}
|
||||
@item @code{quit}
|
||||
@item @code{rtcdata}
|
||||
@item @code{smoothing}
|
||||
@item @code{sources}
|
||||
@item @code{sourcestats}
|
||||
@item @code{tracking}
|
||||
@@ -3348,6 +3382,8 @@ interface.
|
||||
* retries command:: Set maximum number of retries
|
||||
* rtcdata command:: Display RTC parameters
|
||||
* settime command:: Provide a manual input of the current time
|
||||
* smoothing command:: Display current time smoothing state
|
||||
* smoothtime command:: Reset/activate server time smoothing
|
||||
* sources command:: Display information about the current set of sources
|
||||
* sourcestats command:: Display the rate & offset estimation performance of sources
|
||||
* timeout command:: Set initial response timeout
|
||||
@@ -3471,10 +3507,11 @@ directive in the configuration file.
|
||||
@c {{{ authhash
|
||||
@node authhash command
|
||||
@subsubsection authhash
|
||||
This command sets the hash function used for authenticating user commands.
|
||||
For successful authentication the hash function has to be the same as the one
|
||||
set for the command key in the keys file on the server. It needs to be set
|
||||
before the @code{password} command is used. The default hash function is MD5.
|
||||
This command selects the hash function used for authenticating user commands.
|
||||
For successful authentication the hash function has to be the same as the
|
||||
function specified for the command key in the keys file on the server
|
||||
(@pxref{keyfile directive}). It needs to be selected before the
|
||||
@code{password} command is used. The default hash function is MD5.
|
||||
|
||||
An example is
|
||||
|
||||
@@ -4165,14 +4202,15 @@ password
|
||||
@end example
|
||||
|
||||
The computer will respond with a @samp{Password:} prompt, at which you
|
||||
should enter the password and press return. (Note that the no-echo mode
|
||||
is limited to 8 characters on SunOS 4.1 due to limitations in the system
|
||||
library. Other systems do not have this restriction.)
|
||||
should enter the password and press return.
|
||||
|
||||
The password can be encoded as a string of characters not containing a space
|
||||
with optional @code{ASCII:} prefix or as a hexadecimal number with @code{HEX:}
|
||||
prefix. It has to match @code{chronyd's} currently defined command key
|
||||
(@pxref{commandkey directive}).
|
||||
(@pxref{commandkey directive}). If the command key was specified with a
|
||||
different hash function than MD5, it's necessary to select the hash function
|
||||
with the @code{authhash} command (@pxref{authhash command}) before entering the
|
||||
password.
|
||||
|
||||
The password command is run automatically on start if @code{chronyc} was
|
||||
started with the `-a' option.
|
||||
@@ -4326,6 +4364,66 @@ settime Nov 21, 1997 16:30:05
|
||||
|
||||
For a full description of @code{getdate}, get hold of the getdate
|
||||
documentation (bundled, for example, with the source for GNU tar).
|
||||
@c }}}
|
||||
@c {{{ smoothing
|
||||
@node smoothing command
|
||||
@subsubsection smoothing
|
||||
The @code{smoothing} command displays the current state of the NTP server time
|
||||
smoothing. An example of the output is shown below.
|
||||
|
||||
@example
|
||||
Active : Yes
|
||||
Offset : +1.000268817 seconds
|
||||
Frequency : -0.142859 ppm
|
||||
Wander : -0.010000 ppm per second
|
||||
Last update : 17.8 seconds ago
|
||||
Remaining time : 19988.4 seconds
|
||||
@end example
|
||||
|
||||
The fields are explained as follows.
|
||||
|
||||
@table @code
|
||||
@item Active
|
||||
This shows if the server time smoothing is currently active. Possible values
|
||||
are @code{Yes} and @code{No}. If the @code{leaponly} option is included in the
|
||||
@code{smoothtime} directive, @code{(leap second only)} will be shown on the
|
||||
line.
|
||||
|
||||
@item Offset
|
||||
This is the current offset applied to the time sent to NTP clients. Positive
|
||||
value means the clients are getting time that's ahead of true time.
|
||||
|
||||
@item Frequency
|
||||
The current frequency offset of the served time. Negative value means the time
|
||||
observed by clients is running slower than true time.
|
||||
|
||||
@item Wander
|
||||
The current frequency wander of the served time. Negative value means the time
|
||||
observed by clients is slowing down.
|
||||
|
||||
@item Last update
|
||||
This field shows how long ago was the time smoothing process updated, e.g.
|
||||
@code{chronyd} accumulated a new measurement.
|
||||
|
||||
@item Remaining time
|
||||
The time it would take for the smoothing process to get to zero offset and
|
||||
frequency if there were no more updates.
|
||||
@end table
|
||||
@c }}}
|
||||
@c {{{ smoothtime
|
||||
@node smoothtime command
|
||||
@subsubsection smoothtime
|
||||
The @code{smoothtime} command can be used to reset or activate the server time
|
||||
smoothing process if it is configured with the @code{smoothtime} directive
|
||||
(@pxref{smoothtime directive}).
|
||||
|
||||
The syntax is as follows
|
||||
|
||||
@example
|
||||
smoothtime reset
|
||||
smoothtime activate
|
||||
@end example
|
||||
|
||||
@c }}}
|
||||
@c {{{ sources
|
||||
@node sources command
|
||||
@@ -4551,7 +4649,7 @@ true time (which it reports to NTP clients when it is operating in
|
||||
server mode). The value reported on this line is the difference due to
|
||||
this effect.
|
||||
|
||||
On systems such as Solaris and SunOS, @code{chronyd} has no means to
|
||||
On systems other than Linux, @code{chronyd} doesn't
|
||||
adjust the fundamental rate of the system clock, so keeps the system
|
||||
time correct by periodically making offsets to it as though an error had
|
||||
been measured. The build up of these offsets will be observed in this
|
||||
@@ -4696,332 +4794,6 @@ command is issued.
|
||||
@c }}}
|
||||
@c }}}
|
||||
@c }}}
|
||||
@c {{{ Ch:FAQ
|
||||
@node FAQ
|
||||
@chapter Frequently asked questions
|
||||
|
||||
@c {{{ Chapter top
|
||||
@menu
|
||||
* Administrative issues::
|
||||
* Chrony compared to other programs::
|
||||
* Configuration issues::
|
||||
* Computer is not synchronising::
|
||||
* Issues with chronyc::
|
||||
* Real-time clock issues::
|
||||
* Microsoft Windows::
|
||||
* NTP-specific issues::
|
||||
* Linux-specific issues::
|
||||
* Solaris-specific issues::
|
||||
@end menu
|
||||
@c }}}
|
||||
@c {{{ S:Administrative issues
|
||||
@node Administrative issues
|
||||
@section Administrative issues
|
||||
|
||||
@subsection Where can I get chrony source code?
|
||||
Tarballs are available via the @code{Download} link on the chrony web site.
|
||||
For the current development from the developers' version control system see the
|
||||
@code{Git} link on the web site.
|
||||
|
||||
@subsection Are there any packaged versions of chrony?
|
||||
We are aware of packages for Arch, CentOS, Debian, Fedora, Gentoo, Mageia,
|
||||
OpenSuse, Slackware, Ubuntu, FreeBSD and NetBSD. We are not involved with how
|
||||
these are built or distributed.
|
||||
|
||||
@subsection Where is the home page?
|
||||
It is currently at
|
||||
@uref{http://chrony.tuxfamily.org, http://chrony.tuxfamily.org}.
|
||||
|
||||
@subsection Is there a mailing list?
|
||||
Yes, it's currently at @email{chrony-users@@chrony.tuxfamily.org}. There is a
|
||||
low-volume list called chrony-announce which is just for announcements of new
|
||||
releases or similar matters of high importance. You can join the lists by
|
||||
sending a message with the subject subscribe to
|
||||
@email{chrony-users-request@@chrony.tuxfamily.org} or
|
||||
@email{chrony-announce-request@@chrony.tuxfamily.org} respectively.
|
||||
|
||||
For those who want to contribute to the development of chrony, there is a
|
||||
developers' mailing list. You can subscribe by sending mail with the subject
|
||||
subscribe to @email{chrony-dev-request@@chrony.tuxfamily.org}.
|
||||
|
||||
@subsection What licence is applied to chrony?
|
||||
Starting from version 1.15, chrony is licensed under the GNU General Public
|
||||
License, Version 2. Versions prior to 1.15 were licensed under a custom
|
||||
BSD-like license.
|
||||
@c }}}
|
||||
@c {{{ S:Chrony compared to other programs
|
||||
@node Chrony compared to other programs
|
||||
@section Chrony compared to other programs
|
||||
@subsection How does chrony compare to ntpd?
|
||||
Chrony can usually synchronise the system clock faster and with better time
|
||||
accuracy, but it doesn't implement all NTP features, e.g. broadcast/multicast
|
||||
mode, or authentication based on public-key cryptography. For a more detailed
|
||||
comparison, see section @code{Comparison with ntpd} in the manual.
|
||||
|
||||
If your computer connects to the 'net only for few minutes at a time, you turn
|
||||
your Linux computer off or suspend it frequently, the clock is not very stable
|
||||
(e.g. it is a virtual machine), or you want to use NTP on an isolated network
|
||||
with no hardware clocks in sight, chrony will probably work much better for
|
||||
you.
|
||||
|
||||
The original reason chrony was written was that ntpd (called xntpd at the
|
||||
time) could not to do anything sensible on a PC which was connected to
|
||||
the 'net only for about 5 minutes once or twice a day, mainly to
|
||||
upload/download email and news. The requirements were
|
||||
|
||||
@itemize @bullet
|
||||
@item slew the time to correct it when going online and NTP servers become
|
||||
visible
|
||||
@item determine the rate at which the computer gains or loses time and use this
|
||||
information to keep it reasonably correct between connects to the 'net. This
|
||||
has to be done using a method that does not care about the intermittent
|
||||
availability of the references or the fact the computer is turned off between
|
||||
groups of measurements.
|
||||
@item maintain the time across reboots, by working out the error and drift rate
|
||||
of the computer's real-time clock and using this information to set the system
|
||||
clock correctly at boot up.
|
||||
@end itemize
|
||||
|
||||
Also, when working with isolated networks with no true time references at all
|
||||
ntpd was found to give no help with managing the local clock's gain/loss rate
|
||||
on the NTP master node (which was set from watch). Some automated support was
|
||||
added to chrony to deal with this.
|
||||
|
||||
@c }}}
|
||||
@c {{{ S:Configuration issues
|
||||
@node Configuration issues
|
||||
@section Configuration issues
|
||||
|
||||
@subsection I have several computers on a LAN. Should be all clients of an external server?
|
||||
The best configuration is usually to make one computer the master, with the
|
||||
others as clients of it. Add a @code{local} directive to the master's
|
||||
chrony.conf file. This configuration will be better because
|
||||
|
||||
@itemize @bullet
|
||||
@item the load on the external connection is less
|
||||
@item the load on the external NTP server(s) is less
|
||||
@item if your external connection goes down, the computers on the LAN will
|
||||
maintain a common time with each other.
|
||||
@end itemize
|
||||
|
||||
@subsection Must I specify servers by IP address if DNS is not available on chronyd start?
|
||||
No. Starting from version 1.25, @code{chronyd} will keep trying to resolve the
|
||||
hostnames specified in the @code{server} and @code{peer} directives in
|
||||
increasing intervals until it succeeds. The @code{online} command can be
|
||||
issued from @code{chronyc} to try to resolve them immediately.
|
||||
|
||||
@subsection How can I make chronyd more secure?
|
||||
If you don't need to serve time to NTP clients or peers, you can add
|
||||
@code{port 0} to the @file{chrony.conf} file to completely disable the NTP
|
||||
server functionality and prevent NTP requests from reaching @code{chronyd}.
|
||||
Starting from version 2.0, the NTP server port is open only when client access
|
||||
is allowed by the @code{allow} directive or command, an NTP peer is configured,
|
||||
or the @code{broadcast} directive is used.
|
||||
|
||||
If you don't need to use @code{chronyc} remotely, you can add the following
|
||||
directives to the configuration file to bind the command sockets to the
|
||||
loopback interface. This is done by default since version 2.0.
|
||||
|
||||
@example
|
||||
bindcmdaddress 127.0.0.1
|
||||
bindcmdaddress ::1
|
||||
@end example
|
||||
|
||||
If you don't need to use @code{chronyc} at all, you can disable the command
|
||||
sockets by adding @code{cmdport 0} to the configuration file.
|
||||
|
||||
On Linux, if @code{chronyd} is compiled with support for Linux capabilities
|
||||
(available in the libcap library), you can specify an unprivileged user with
|
||||
the `-u' option or @code{user} directive in the @file{chrony.conf} file to drop
|
||||
root privileges after start. The configure option @code{--with-user} can be
|
||||
used to drop the privileges by default.
|
||||
|
||||
@subsection How can I improve the accuracy of the system clock with NTP sources?
|
||||
Select NTP servers that are well synchronised, stable and close to your network.
|
||||
It's better to use more than one server, three or four is usually recommended as
|
||||
the minimum, so @code{chronyd} can detect falsetickers and combine measurements
|
||||
from multiple sources.
|
||||
|
||||
There are also useful options which can be set in the @code{server} directive,
|
||||
they are @code{minpoll}, @code{maxpoll}, @code{polltarget}, @code{maxdelay},
|
||||
@code{maxdelayratio} and @code{maxdelaydevratio}.
|
||||
|
||||
The first three options set the minimum and maximum allowed polling interval,
|
||||
and how should be the actual interval adjusted in the specified range. Their
|
||||
default values are 6 (64 seconds) for @code{minpoll}, 10 (1024 seconds) for
|
||||
@code{maxpoll} and 6 (samples) for @code{polltarget}. The default values
|
||||
should be used for general servers on the internet. With your own NTP servers
|
||||
or if have permission to poll some servers more frequently, setting these
|
||||
options for shorter polling intervals may significantly improve the accuracy of
|
||||
the system clock.
|
||||
|
||||
The optimal polling interval depends on many factors, including the ratio
|
||||
between the wander of the clock and the network jitter (sometimes expressed in
|
||||
NTP documents as the Allan intercept), the temperature sensitivity of the
|
||||
crystal oscillator and the maximum rate of change of the temperature.
|
||||
|
||||
An example of the directive for an NTP server on the internet that you are
|
||||
allowed to poll frequently could be
|
||||
|
||||
@example
|
||||
server foo.example.net minpoll 4 maxpoll 6 polltarget 16
|
||||
@end example
|
||||
|
||||
An example using very short polling intervals for a server located in the
|
||||
same LAN could be
|
||||
|
||||
@example
|
||||
server ntp.local minpoll 2 maxpoll 4 polltarget 30
|
||||
@end example
|
||||
|
||||
The maxdelay options are useful to ignore measurements with larger delay (e.g.
|
||||
due to congestion in the network) and improve the stability of the
|
||||
synchronisation. The @code{maxdelaydevratio} option could be added to the
|
||||
example with local NTP server
|
||||
|
||||
@example
|
||||
server ntp.local minpoll 2 maxpoll 4 polltarget 30 maxdelaydevratio 2
|
||||
@end example
|
||||
|
||||
@c }}}
|
||||
@c {{{ S:Computer is not synchronising
|
||||
@node Computer is not synchronising
|
||||
@section Computer is not synchronising
|
||||
|
||||
This is the most common problem. There are a number of reasons, see the
|
||||
following questions.
|
||||
|
||||
@subsection Behind a firewall?
|
||||
If there is a firewall between you and the NTP server you're trying to use,
|
||||
the packets may be blocked. Try using a tool like wireshark or tcpdump to see
|
||||
if you're getting responses from the server. If you have an external modem,
|
||||
see if the receive light blinks straight after the transmit light (when the
|
||||
link is quiet apart from the NTP traffic.) Try adding @code{log measurements}
|
||||
to the @file{chrony.conf} file and look in the measurements.log file after
|
||||
chrony has been running for a short period. See if any measurements appear.
|
||||
|
||||
@subsection Do you have a non-permanent (i.e. intermittent) Internet connection?
|
||||
Check that you're using chronyc's @code{online} and @code{offline} commands
|
||||
appropriately. Again, check in measurements.log to see if you're getting any
|
||||
data back from the server.
|
||||
|
||||
@subsection In measurements.log, do the '7' and '8' flag columns always show zero?
|
||||
Do you have a @code{local stratum X} directive in the @file{chrony.conf} file? If X
|
||||
is lower than the stratum of the server you're trying to use, this situation
|
||||
will arise. You should always make X quite high (e.g. 10) in this directive.
|
||||
@c }}}
|
||||
@c {{{ S:Issues with chronyc
|
||||
@node Issues with chronyc
|
||||
@section Issues with chronyc
|
||||
|
||||
@subsection I keep getting the error @code{506 Cannot talk to daemon}
|
||||
When accessing @code{chronyd} remotely, make sure that the @file{chrony.conf}
|
||||
file (on the computer where @code{chronyd} is running) has a @code{cmdallow}
|
||||
entry for the computer you are running @code{chronyc} on and an appropriate
|
||||
@code{bindcmdaddress} directive. This isn't necessary for localhost.
|
||||
|
||||
Perhaps @code{chronyd} is not running. Try using the ps command (e.g. on
|
||||
Linux, 'ps -auxw') to see if it's running. Or try 'netstat -a' and see if the
|
||||
ports 123/udp and 323/udp are listening. If @code{chronyd} is not running, you
|
||||
may have a problem with the way you are trying to start it (e.g. at boot time).
|
||||
|
||||
Perhaps you have a firewall set up in a way that blocks packets on port
|
||||
323/udp. You need to amend the firewall configuration in this case.
|
||||
|
||||
@subsection Is the chronyc<->chronyd protocol documented anywhere?
|
||||
Only by the source code :-) See cmdmon.c (@code{chronyd} side) and client.c
|
||||
(@code{chronyc} side).
|
||||
@c }}}
|
||||
@c {{{ S:Real-time clock issues
|
||||
@node Real-time clock issues
|
||||
@section Real-time clock issues
|
||||
|
||||
@subsection What is the real-time clock (RTC)?
|
||||
This is the clock which keeps the time even when your computer is turned off.
|
||||
It works with 1 second resolution. @code{chronyd} can monitor the rate at
|
||||
which the real-time clock gains or loses time, and compensate for it when you
|
||||
set the system time from it at the next reboot. See the documentation for
|
||||
details.
|
||||
|
||||
@subsection I want to use chronyd's real-time clock support. Must I disable hwclock?
|
||||
The hwclock program is often set-up by default in the boot and shutdown scripts
|
||||
with many Linux installations. If you want to use chronyd's real-time clock
|
||||
support, the important thing is to disable hwclock in the shutdown procedure.
|
||||
If you don't, it will over-write the RTC with a new value, unknown to
|
||||
@code{chronyd}. At the next reboot, @code{chronyd} will compensate this (wrong)
|
||||
time with its estimate of how far the RTC has drifted whilst the power was off,
|
||||
giving a meaningless initial system time.
|
||||
|
||||
There is no need to remove hwclock from the boot process, as long as
|
||||
@code{chronyd} is started after it has run.
|
||||
|
||||
@subsection I just keep getting the '513 RTC driver not running' message
|
||||
For the real time clock support to work, you need the following three things
|
||||
@itemize @bullet
|
||||
@item a kernel that is supported (e.g. 2.2 onwards)
|
||||
@item enhanced RTC support compiled into the kernel
|
||||
@item an @code{rtcfile} directive in your chrony.conf file
|
||||
@end itemize
|
||||
@c }}}
|
||||
@c {{{ S:Microsoft Windows
|
||||
@node Microsoft Windows
|
||||
@section Microsoft Windows
|
||||
|
||||
@subsection Does chrony support Windows?
|
||||
No. The @code{chronyc} program (the command-line client used for configuring
|
||||
@code{chronyd} while it is running) has been successfully built and run under
|
||||
Cygwin in the past. @code{chronyd} is not portable, because part of it is very
|
||||
system-dependent. It needs adapting to work with Windows' equivalent of the
|
||||
adjtimex() call, and it needs to be made to work as an NT service.
|
||||
|
||||
@subsection Are there any plans to support Windows?
|
||||
We have no plans to do this. Anyone is welcome to pick this work up and
|
||||
contribute it back to the project.
|
||||
@c }}}
|
||||
@c {{{ S:NTP-specific issues
|
||||
@node NTP-specific issues
|
||||
@section NTP-specific issues
|
||||
|
||||
@subsection Can chrony be driven from broadcast NTP servers?
|
||||
No, this NTP mode is not implemented yet.
|
||||
|
||||
@subsection Can chronyd transmit broadcast NTP packets (e.g. to synchronise other computers on a private LAN)?
|
||||
Yes. Starting from version 1.17, chrony has this capability.
|
||||
|
||||
@subsection Can chrony keep the system clock a fixed offset away from real time?
|
||||
This is not possible as the program currently stands.
|
||||
|
||||
@subsection What happens if the network connection is dropped without using chronyc's 'offline' command first?
|
||||
In this case @code{chronyd} will keep trying to access the server(s) that it
|
||||
thinks are online. Eventually it will decide that they are unreachable and no
|
||||
longer consider itself synchronised to them. If you have other computers on
|
||||
your LAN accessing the computer that is affected this way, they too will become
|
||||
'unsynchronised', unless you have the 'local' directive set up on the master
|
||||
computer.
|
||||
|
||||
The 'auto_offline' option to the 'server' entry in the chrony.conf file may be
|
||||
useful to avoid this situation.
|
||||
@c }}}
|
||||
@c {{{ S:Linux-specific issues
|
||||
@node Linux-specific issues
|
||||
@section Linux-specific issues
|
||||
|
||||
@subsection I get "Could not open /dev/rtc, Device or resource busy" in my syslog file
|
||||
Some other program running on the system may be using the device.
|
||||
@c }}}
|
||||
@c {{{ S:Solaris-specific issues
|
||||
@node Solaris-specific issues
|
||||
@section Solaris-specific issues
|
||||
|
||||
@subsection On Solaris 2.8, I get an error message about not being able to open kvm to change dosynctodr
|
||||
(The dosynctodr variable controls whether Solaris couples the equivalent of its
|
||||
BIOS clock into its system clock at regular intervals). The Solaris port of
|
||||
chrony was developed in the Solaris 2.5 era. Some aspect of the Solaris kernel
|
||||
has changed which prevents the same technique working. We no longer have root
|
||||
access to any Solaris machines to work on this, and we are reliant on somebody
|
||||
developing the patch and testing it.
|
||||
@c }}}
|
||||
@c }}}
|
||||
@c {{{ apx:GNU General Public License
|
||||
@node GPL
|
||||
@appendix GNU General Public License
|
||||
|
||||
@@ -60,8 +60,7 @@ interactively.
|
||||
To report bugs, please visit \fIhttp://chrony.tuxfamily.org\fR
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.BR chronyd(8),
|
||||
.BR chrony(1)
|
||||
.BR chronyd(8)
|
||||
|
||||
.I http://chrony.tuxfamily.org/
|
||||
|
||||
|
||||
@@ -70,8 +70,7 @@ option is useful if you want to stop and restart \fBchronyd\fR briefly for any
|
||||
reason, e.g. to install a new version. However, it only makes sense on
|
||||
systems where the kernel can maintain clock compensation whilst not under
|
||||
\fBchronyd\fR's control. The only version where this happens so far is Linux.
|
||||
On systems where this is not the case, e.g. Solaris and SunOS the option
|
||||
should not be used.
|
||||
On other systems this option should not be used.
|
||||
.TP
|
||||
.B \-R
|
||||
When this option is used, the \fIinitstepslew\fR directive and the
|
||||
@@ -135,7 +134,6 @@ To report bugs, please visit \fIhttp://chrony.tuxfamily.org/\fR
|
||||
\fBchronyd\fR is documented in detail in the documentation supplied with the
|
||||
distribution (\fIchrony.txt\fR and \fIchrony.texi\fR).
|
||||
|
||||
.BR chrony(1),
|
||||
.BR chronyc(1),
|
||||
.BR chrony.conf(5),
|
||||
.BR hwclock(8),
|
||||
|
||||
81
client.c
81
client.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2009-2014
|
||||
* Copyright (C) Miroslav Lichvar 2009-2015
|
||||
*
|
||||
* 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
|
||||
@@ -640,7 +640,8 @@ process_cmd_manual(CMD_Request *msg, const char *line)
|
||||
static int
|
||||
parse_allow_deny(CMD_Request *msg, char *line)
|
||||
{
|
||||
unsigned long a, b, c, d, n;
|
||||
unsigned long a, b, c, d;
|
||||
int n, specified_subnet_bits;
|
||||
IPAddr ip;
|
||||
char *p;
|
||||
|
||||
@@ -657,7 +658,7 @@ parse_allow_deny(CMD_Request *msg, char *line)
|
||||
|
||||
n = 0;
|
||||
if (!UTI_StringToIP(p, &ip) &&
|
||||
(n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d)) == 0) {
|
||||
(n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d)) <= 0) {
|
||||
|
||||
/* Try to parse as the name of a machine */
|
||||
if (DNS_Name2IPAddress(p, &ip, 1) != DNS_Success) {
|
||||
@@ -710,7 +711,6 @@ parse_allow_deny(CMD_Request *msg, char *line)
|
||||
UTI_IPHostToNetwork(&ip, &msg->data.allow_deny.ip);
|
||||
|
||||
if (slashpos) {
|
||||
int specified_subnet_bits, n;
|
||||
n = sscanf(slashpos+1, "%d", &specified_subnet_bits);
|
||||
if (n == 1) {
|
||||
msg->data.allow_deny.subnet_bits = htonl(specified_subnet_bits);
|
||||
@@ -1184,6 +1184,8 @@ give_help(void)
|
||||
printf("reselect : Reselect synchronisation source\n");
|
||||
printf("rtcdata : Print current RTC performance parameters\n");
|
||||
printf("settime <date/time (e.g. Nov 21, 1997 16:30:05 or 16:30:05)> : Manually set the daemon time\n");
|
||||
printf("smoothing : Display current time smoothing state\n");
|
||||
printf("smoothtime reset|activate : Reset/activate time smoothing\n");
|
||||
printf("sources [-v] : Display information about current sources\n");
|
||||
printf("sourcestats [-v] : Display estimation information about current sources\n");
|
||||
printf("tracking : Display system time information\n");
|
||||
@@ -1964,6 +1966,63 @@ process_cmd_tracking(char *line)
|
||||
}
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
process_cmd_smoothing(char *line)
|
||||
{
|
||||
CMD_Request request;
|
||||
CMD_Reply reply;
|
||||
uint32_t flags;
|
||||
double offset;
|
||||
double freq_ppm;
|
||||
double wander_ppm;
|
||||
double last_update_ago;
|
||||
double remaining_time;
|
||||
|
||||
request.command = htons(REQ_SMOOTHING);
|
||||
|
||||
if (request_reply(&request, &reply, RPY_SMOOTHING, 0)) {
|
||||
flags = ntohl(reply.data.smoothing.flags);
|
||||
offset = UTI_FloatNetworkToHost(reply.data.smoothing.offset);
|
||||
freq_ppm = UTI_FloatNetworkToHost(reply.data.smoothing.freq_ppm);
|
||||
wander_ppm = UTI_FloatNetworkToHost(reply.data.smoothing.wander_ppm);
|
||||
last_update_ago = UTI_FloatNetworkToHost(reply.data.smoothing.last_update_ago);
|
||||
remaining_time = UTI_FloatNetworkToHost(reply.data.smoothing.remaining_time);
|
||||
|
||||
printf("Active : %s%s\n",
|
||||
flags & RPY_SMT_FLAG_ACTIVE ? "Yes" : "No",
|
||||
flags & RPY_SMT_FLAG_LEAPONLY ? " (leap second only)" : "");
|
||||
printf("Offset : %+.9f seconds\n", offset);
|
||||
printf("Frequency : %+.6f ppm\n", freq_ppm);
|
||||
printf("Wander : %+.6f ppm per second\n", wander_ppm);
|
||||
printf("Last update : %.1f seconds ago\n", last_update_ago);
|
||||
printf("Remaining time : %.1f seconds\n", remaining_time);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
process_cmd_smoothtime(CMD_Request *msg, const char *line)
|
||||
{
|
||||
if (!strcmp(line, "reset")) {
|
||||
msg->data.smoothtime.option = htonl(REQ_SMOOTHTIME_RESET);
|
||||
} else if (!strcmp(line, "activate")) {
|
||||
msg->data.smoothtime.option = htonl(REQ_SMOOTHTIME_ACTIVATE);
|
||||
} else {
|
||||
fprintf(stderr, "Invalid syntax for smoothtime command\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
msg->command = htons(REQ_SMOOTHTIME);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
process_cmd_rtcreport(char *line)
|
||||
{
|
||||
@@ -2535,6 +2594,11 @@ process_line(char *line, int *quit)
|
||||
} else if (!strcmp(command, "settime")) {
|
||||
do_normal_submit = 0;
|
||||
ret = process_cmd_settime(line);
|
||||
} else if (!strcmp(command, "smoothing")) {
|
||||
do_normal_submit = 0;
|
||||
ret = process_cmd_smoothing(line);
|
||||
} else if (!strcmp(command, "smoothtime")) {
|
||||
do_normal_submit = process_cmd_smoothtime(&tx_message, line);
|
||||
} else if (!strcmp(command, "sources")) {
|
||||
do_normal_submit = 0;
|
||||
ret = process_cmd_sources(line);
|
||||
@@ -2681,7 +2745,7 @@ static void
|
||||
display_gpl(void)
|
||||
{
|
||||
printf("chrony version %s\n"
|
||||
"Copyright (C) 1997-2003, 2007, 2009-2014 Richard P. Curnow and others\n"
|
||||
"Copyright (C) 1997-2003, 2007, 2009-2015 Richard P. Curnow and others\n"
|
||||
"chrony comes with ABSOLUTELY NO WARRANTY. This is free software, and\n"
|
||||
"you are welcome to redistribute it under certain conditions. See the\n"
|
||||
"GNU General Public License version 2 for details.\n\n",
|
||||
@@ -2729,10 +2793,11 @@ main(int argc, char **argv)
|
||||
family = IPADDR_INET6;
|
||||
} else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
|
||||
printf("chronyc (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYC_FEATURES);
|
||||
exit(0);
|
||||
return 0;
|
||||
} else if (!strncmp(*argv, "-", 1)) {
|
||||
fprintf(stderr, "Usage : %s [-h <hostname>] [-p <port-number>] [-n] [-4|-6] [-m] [-a] [-f <file>]] [command]\n", progname);
|
||||
exit(1);
|
||||
fprintf(stderr, "Usage: %s [-h HOST] [-p PORT] [-n] [-4|-6] [-a] [-f FILE] [-m] [COMMAND]\n",
|
||||
progname);
|
||||
return 1;
|
||||
} else {
|
||||
break; /* And process remainder of line as a command */
|
||||
}
|
||||
|
||||
370
cmdmon.c
370
cmdmon.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2009-2014
|
||||
* Copyright (C) Miroslav Lichvar 2009-2015
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "keys.h"
|
||||
#include "ntp_sources.h"
|
||||
#include "ntp_core.h"
|
||||
#include "smooth.h"
|
||||
#include "sources.h"
|
||||
#include "sourcestats.h"
|
||||
#include "reference.h"
|
||||
@@ -162,6 +163,8 @@ static const char permissions[] = {
|
||||
PERMIT_AUTH, /* RESELECT */
|
||||
PERMIT_AUTH, /* RESELECTDISTANCE */
|
||||
PERMIT_AUTH, /* MODIFY_MAKESTEP */
|
||||
PERMIT_OPEN, /* SMOOTHING */
|
||||
PERMIT_AUTH, /* SMOOTHTIME */
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
@@ -712,13 +715,12 @@ transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to, int auth_len)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_null(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
handle_dump(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
SRC_DumpSources();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -726,16 +728,12 @@ handle_null(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
static void
|
||||
handle_online(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
int status;
|
||||
IPAddr address, mask;
|
||||
|
||||
UTI_IPNetworkToHost(&rx_message->data.online.mask, &mask);
|
||||
UTI_IPNetworkToHost(&rx_message->data.online.address, &address);
|
||||
status = NSR_TakeSourcesOnline(&mask, &address);
|
||||
if (status) {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
} else {
|
||||
if (!NSR_TakeSourcesOnline(&mask, &address))
|
||||
tx_message->status = htons(STT_NOSUCHSOURCE);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -743,16 +741,12 @@ handle_online(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
static void
|
||||
handle_offline(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
int status;
|
||||
IPAddr address, mask;
|
||||
|
||||
UTI_IPNetworkToHost(&rx_message->data.offline.mask, &mask);
|
||||
UTI_IPNetworkToHost(&rx_message->data.offline.address, &address);
|
||||
status = NSR_TakeSourcesOffline(&mask, &address);
|
||||
if (status) {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
} else {
|
||||
if (!NSR_TakeSourcesOffline(&mask, &address))
|
||||
tx_message->status = htons(STT_NOSUCHSOURCE);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -760,19 +754,14 @@ handle_offline(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
static void
|
||||
handle_burst(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
int status;
|
||||
IPAddr address, mask;
|
||||
|
||||
UTI_IPNetworkToHost(&rx_message->data.burst.mask, &mask);
|
||||
UTI_IPNetworkToHost(&rx_message->data.burst.address, &address);
|
||||
status = NSR_InitiateSampleBurst(ntohl(rx_message->data.burst.n_good_samples),
|
||||
ntohl(rx_message->data.burst.n_total_samples),
|
||||
&mask, &address);
|
||||
|
||||
if (status) {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
} else {
|
||||
if (!NSR_InitiateSampleBurst(ntohl(rx_message->data.burst.n_good_samples),
|
||||
ntohl(rx_message->data.burst.n_total_samples),
|
||||
&mask, &address))
|
||||
tx_message->status = htons(STT_NOSUCHSOURCE);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -780,17 +769,12 @@ handle_burst(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
static void
|
||||
handle_modify_minpoll(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
int status;
|
||||
IPAddr address;
|
||||
|
||||
UTI_IPNetworkToHost(&rx_message->data.modify_minpoll.address, &address);
|
||||
status = NSR_ModifyMinpoll(&address,
|
||||
ntohl(rx_message->data.modify_minpoll.new_minpoll));
|
||||
|
||||
if (status) {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
} else {
|
||||
if (!NSR_ModifyMinpoll(&address,
|
||||
ntohl(rx_message->data.modify_minpoll.new_minpoll)))
|
||||
tx_message->status = htons(STT_NOSUCHSOURCE);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -798,17 +782,12 @@ handle_modify_minpoll(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
static void
|
||||
handle_modify_maxpoll(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
int status;
|
||||
IPAddr address;
|
||||
|
||||
UTI_IPNetworkToHost(&rx_message->data.modify_minpoll.address, &address);
|
||||
status = NSR_ModifyMaxpoll(&address,
|
||||
ntohl(rx_message->data.modify_minpoll.new_minpoll));
|
||||
|
||||
if (status) {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
} else {
|
||||
if (!NSR_ModifyMaxpoll(&address,
|
||||
ntohl(rx_message->data.modify_minpoll.new_minpoll)))
|
||||
tx_message->status = htons(STT_NOSUCHSOURCE);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -816,16 +795,12 @@ handle_modify_maxpoll(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
static void
|
||||
handle_modify_maxdelay(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
int status;
|
||||
IPAddr address;
|
||||
|
||||
UTI_IPNetworkToHost(&rx_message->data.modify_maxdelay.address, &address);
|
||||
status = NSR_ModifyMaxdelay(&address,
|
||||
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelay.new_max_delay));
|
||||
if (status) {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
} else {
|
||||
if (!NSR_ModifyMaxdelay(&address,
|
||||
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelay.new_max_delay)))
|
||||
tx_message->status = htons(STT_NOSUCHSOURCE);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -833,16 +808,12 @@ handle_modify_maxdelay(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
static void
|
||||
handle_modify_maxdelayratio(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
int status;
|
||||
IPAddr address;
|
||||
|
||||
UTI_IPNetworkToHost(&rx_message->data.modify_maxdelayratio.address, &address);
|
||||
status = NSR_ModifyMaxdelayratio(&address,
|
||||
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelayratio.new_max_delay_ratio));
|
||||
if (status) {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
} else {
|
||||
if (!NSR_ModifyMaxdelayratio(&address,
|
||||
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelayratio.new_max_delay_ratio)))
|
||||
tx_message->status = htons(STT_NOSUCHSOURCE);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -850,16 +821,12 @@ handle_modify_maxdelayratio(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
static void
|
||||
handle_modify_maxdelaydevratio(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
int status;
|
||||
IPAddr address;
|
||||
|
||||
UTI_IPNetworkToHost(&rx_message->data.modify_maxdelaydevratio.address, &address);
|
||||
status = NSR_ModifyMaxdelaydevratio(&address,
|
||||
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelaydevratio.new_max_delay_dev_ratio));
|
||||
if (status) {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
} else {
|
||||
if (!NSR_ModifyMaxdelaydevratio(&address,
|
||||
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelaydevratio.new_max_delay_dev_ratio)))
|
||||
tx_message->status = htons(STT_NOSUCHSOURCE);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -867,17 +834,12 @@ handle_modify_maxdelaydevratio(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
static void
|
||||
handle_modify_minstratum(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
int status;
|
||||
IPAddr address;
|
||||
|
||||
UTI_IPNetworkToHost(&rx_message->data.modify_minpoll.address, &address);
|
||||
status = NSR_ModifyMinstratum(&address,
|
||||
ntohl(rx_message->data.modify_minstratum.new_min_stratum));
|
||||
|
||||
if (status) {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
} else {
|
||||
if (!NSR_ModifyMinstratum(&address,
|
||||
ntohl(rx_message->data.modify_minstratum.new_min_stratum)))
|
||||
tx_message->status = htons(STT_NOSUCHSOURCE);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -885,17 +847,12 @@ handle_modify_minstratum(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
static void
|
||||
handle_modify_polltarget(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
int status;
|
||||
IPAddr address;
|
||||
|
||||
UTI_IPNetworkToHost(&rx_message->data.modify_polltarget.address, &address);
|
||||
status = NSR_ModifyPolltarget(&address,
|
||||
ntohl(rx_message->data.modify_polltarget.new_poll_target));
|
||||
|
||||
if (status) {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
} else {
|
||||
if (!NSR_ModifyPolltarget(&address,
|
||||
ntohl(rx_message->data.modify_polltarget.new_poll_target)))
|
||||
tx_message->status = htons(STT_NOSUCHSOURCE);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -904,7 +861,6 @@ static void
|
||||
handle_modify_maxupdateskew(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
REF_ModifyMaxupdateskew(UTI_FloatNetworkToHost(rx_message->data.modify_maxupdateskew.new_max_update_skew));
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -914,7 +870,6 @@ handle_modify_makestep(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
REF_ModifyMakestep(ntohl(rx_message->data.modify_makestep.limit),
|
||||
UTI_FloatNetworkToHost(rx_message->data.modify_makestep.threshold));
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -929,7 +884,6 @@ handle_settime(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
if (!MNL_IsEnabled()) {
|
||||
tx_message->status = htons(STT_NOTENABLED);
|
||||
} else if (MNL_AcceptTimestamp(&ts, &offset_cs, &dfreq_ppm, &new_afreq_ppm)) {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
tx_message->reply = htons(RPY_MANUAL_TIMESTAMP);
|
||||
tx_message->data.manual_timestamp.centiseconds = htonl((int32_t)offset_cs);
|
||||
tx_message->data.manual_timestamp.dfreq_ppm = UTI_FloatHostToNetwork(dfreq_ppm);
|
||||
@@ -952,7 +906,6 @@ handle_local(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
} else {
|
||||
REF_DisableLocal();
|
||||
}
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -972,8 +925,10 @@ handle_manual(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
case 2:
|
||||
MNL_Reset();
|
||||
break;
|
||||
default:
|
||||
tx_message->status = htons(STT_INVALID);
|
||||
break;
|
||||
}
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -983,7 +938,6 @@ handle_n_sources(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
int n_sources;
|
||||
n_sources = SRC_ReadNumberOfSources();
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
tx_message->reply = htons(RPY_N_SOURCES);
|
||||
tx_message->data.n_sources.n_sources = htonl(n_sources);
|
||||
}
|
||||
@@ -997,7 +951,7 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
struct timeval now_corr;
|
||||
|
||||
/* Get data */
|
||||
LCL_ReadCookedTime(&now_corr, NULL);
|
||||
SCH_GetLastEventTime(&now_corr, NULL, NULL);
|
||||
if (SRC_ReportSource(ntohl(rx_message->data.source_data.index), &report, &now_corr)) {
|
||||
switch (SRC_GetType(ntohl(rx_message->data.source_data.index))) {
|
||||
case SRC_NTP:
|
||||
@@ -1008,7 +962,6 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
break;
|
||||
}
|
||||
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
tx_message->reply = htons(RPY_SOURCE_DATA);
|
||||
|
||||
UTI_IPHostToNetwork(&report.ip_addr, &tx_message->data.source_data.ip_addr);
|
||||
@@ -1071,136 +1024,35 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
static void
|
||||
handle_rekey(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
KEY_Reload();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_allow(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
handle_allowdeny(CMD_Request *rx_message, CMD_Reply *tx_message, int allow, int all)
|
||||
{
|
||||
IPAddr ip;
|
||||
int subnet_bits;
|
||||
|
||||
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
|
||||
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
|
||||
if (NCR_AddAccessRestriction(&ip, subnet_bits, 1, 0)) {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
} else {
|
||||
if (!NCR_AddAccessRestriction(&ip, subnet_bits, allow, all))
|
||||
tx_message->status = htons(STT_BADSUBNET);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_allowall(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
handle_cmdallowdeny(CMD_Request *rx_message, CMD_Reply *tx_message, int allow, int all)
|
||||
{
|
||||
IPAddr ip;
|
||||
int subnet_bits;
|
||||
|
||||
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
|
||||
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
|
||||
if (NCR_AddAccessRestriction(&ip, subnet_bits, 1, 1)) {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
} else {
|
||||
if (!CAM_AddAccessRestriction(&ip, subnet_bits, allow, all))
|
||||
tx_message->status = htons(STT_BADSUBNET);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_deny(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
IPAddr ip;
|
||||
int subnet_bits;
|
||||
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
|
||||
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
|
||||
if (NCR_AddAccessRestriction(&ip, subnet_bits, 0, 0)) {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
} else {
|
||||
tx_message->status = htons(STT_BADSUBNET);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_denyall(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
IPAddr ip;
|
||||
int subnet_bits;
|
||||
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
|
||||
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
|
||||
if (NCR_AddAccessRestriction(&ip, subnet_bits, 0, 1)) {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
} else {
|
||||
tx_message->status = htons(STT_BADSUBNET);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_cmdallow(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
IPAddr ip;
|
||||
int subnet_bits;
|
||||
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
|
||||
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
|
||||
if (CAM_AddAccessRestriction(&ip, subnet_bits, 1, 0)) {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
} else {
|
||||
tx_message->status = htons(STT_BADSUBNET);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_cmdallowall(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
IPAddr ip;
|
||||
int subnet_bits;
|
||||
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
|
||||
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
|
||||
if (CAM_AddAccessRestriction(&ip, subnet_bits, 1, 1)) {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
} else {
|
||||
tx_message->status = htons(STT_BADSUBNET);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_cmddeny(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
IPAddr ip;
|
||||
int subnet_bits;
|
||||
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
|
||||
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
|
||||
if (CAM_AddAccessRestriction(&ip, subnet_bits, 0, 0)) {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
} else {
|
||||
tx_message->status = htons(STT_BADSUBNET);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_cmddenyall(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
IPAddr ip;
|
||||
int subnet_bits;
|
||||
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
|
||||
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
|
||||
if (CAM_AddAccessRestriction(&ip, subnet_bits, 0, 1)) {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
} else {
|
||||
tx_message->status = htons(STT_BADSUBNET);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1266,7 +1118,6 @@ handle_add_source(NTP_Source_Type type, CMD_Request *rx_message, CMD_Reply *tx_m
|
||||
status = NSR_AddSource(&rem_addr, type, ¶ms);
|
||||
switch (status) {
|
||||
case NSR_Success:
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
break;
|
||||
case NSR_AlreadyInUse:
|
||||
tx_message->status = htons(STT_SOURCEALREADYKNOWN);
|
||||
@@ -1297,7 +1148,6 @@ handle_del_source(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
status = NSR_RemoveSource(&rem_addr);
|
||||
switch (status) {
|
||||
case NSR_Success:
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
break;
|
||||
case NSR_NoSuchSource:
|
||||
tx_message->status = htons(STT_NOSUCHSOURCE);
|
||||
@@ -1317,7 +1167,6 @@ handle_writertc(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
switch (RTC_WriteParameters()) {
|
||||
case RTC_ST_OK:
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
break;
|
||||
case RTC_ST_NODRV:
|
||||
tx_message->status = htons(STT_NORTC);
|
||||
@@ -1337,7 +1186,6 @@ handle_dfreq(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
dfreq = UTI_FloatNetworkToHost(rx_message->data.dfreq.dfreq);
|
||||
LCL_AccumulateDeltaFrequency(dfreq * 1.0e-6);
|
||||
LOG(LOGS_INFO, LOGF_CmdMon, "Accumulated delta freq of %.3fppm", dfreq);
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1352,7 +1200,6 @@ handle_doffset(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
doffset = (double) sec + 1.0e-6 * (double) usec;
|
||||
LOG(LOGS_INFO, LOGF_CmdMon, "Accumulated delta offset of %.6f seconds", doffset);
|
||||
LCL_AccumulateOffset(doffset, 0.0);
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1363,7 +1210,6 @@ handle_tracking(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
RPT_TrackingReport rpt;
|
||||
|
||||
REF_GetTrackingReport(&rpt);
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
tx_message->reply = htons(RPY_TRACKING);
|
||||
tx_message->data.tracking.ref_id = htonl(rpt.ref_id);
|
||||
UTI_IPHostToNetwork(&rpt.ip_addr, &tx_message->data.tracking.ip_addr);
|
||||
@@ -1383,6 +1229,60 @@ handle_tracking(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_smoothing(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
RPT_SmoothingReport report;
|
||||
struct timeval now;
|
||||
|
||||
SCH_GetLastEventTime(&now, NULL, NULL);
|
||||
|
||||
if (!SMT_GetSmoothingReport(&report, &now)) {
|
||||
tx_message->status = htons(STT_NOTENABLED);
|
||||
return;
|
||||
}
|
||||
|
||||
tx_message->reply = htons(RPY_SMOOTHING);
|
||||
tx_message->data.smoothing.flags = htonl((report.active ? RPY_SMT_FLAG_ACTIVE : 0) |
|
||||
(report.leap_only ? RPY_SMT_FLAG_LEAPONLY : 0));
|
||||
tx_message->data.smoothing.offset = UTI_FloatHostToNetwork(report.offset);
|
||||
tx_message->data.smoothing.freq_ppm = UTI_FloatHostToNetwork(report.freq_ppm);
|
||||
tx_message->data.smoothing.wander_ppm = UTI_FloatHostToNetwork(report.wander_ppm);
|
||||
tx_message->data.smoothing.last_update_ago = UTI_FloatHostToNetwork(report.last_update_ago);
|
||||
tx_message->data.smoothing.remaining_time = UTI_FloatHostToNetwork(report.remaining_time);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_smoothtime(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
struct timeval now;
|
||||
int option;
|
||||
|
||||
if (!SMT_IsEnabled()) {
|
||||
tx_message->status = htons(STT_NOTENABLED);
|
||||
return;
|
||||
}
|
||||
|
||||
option = ntohl(rx_message->data.smoothtime.option);
|
||||
SCH_GetLastEventTime(&now, NULL, NULL);
|
||||
|
||||
switch (option) {
|
||||
case REQ_SMOOTHTIME_RESET:
|
||||
SMT_Reset(&now);
|
||||
break;
|
||||
case REQ_SMOOTHTIME_ACTIVATE:
|
||||
SMT_Activate(&now);
|
||||
break;
|
||||
default:
|
||||
tx_message->status = htons(STT_INVALID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_sourcestats(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
@@ -1390,12 +1290,11 @@ handle_sourcestats(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
RPT_SourcestatsReport report;
|
||||
struct timeval now_corr;
|
||||
|
||||
LCL_ReadCookedTime(&now_corr, NULL);
|
||||
SCH_GetLastEventTime(&now_corr, NULL, NULL);
|
||||
status = SRC_ReportSourcestats(ntohl(rx_message->data.sourcestats.index),
|
||||
&report, &now_corr);
|
||||
|
||||
if (status) {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
tx_message->reply = htons(RPY_SOURCESTATS);
|
||||
tx_message->data.sourcestats.ref_id = htonl(report.ref_id);
|
||||
UTI_IPHostToNetwork(&report.ip_addr, &tx_message->data.sourcestats.ip_addr);
|
||||
@@ -1421,7 +1320,6 @@ handle_rtcreport(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
RPT_RTC_Report report;
|
||||
status = RTC_GetReport(&report);
|
||||
if (status) {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
tx_message->reply = htons(RPY_RTC);
|
||||
UTI_TimevalHostToNetwork(&report.ref_time, &tx_message->data.rtc.ref_time);
|
||||
tx_message->data.rtc.n_samples = htons(report.n_samples);
|
||||
@@ -1439,13 +1337,8 @@ handle_rtcreport(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
static void
|
||||
handle_trimrtc(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
int status;
|
||||
status = RTC_Trim();
|
||||
if (status) {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
} else {
|
||||
if (!RTC_Trim())
|
||||
tx_message->status = htons(STT_NORTC);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1454,8 +1347,6 @@ static void
|
||||
handle_cyclelogs(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
LOG_CycleLogFiles();
|
||||
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1469,14 +1360,13 @@ handle_client_accesses_by_index(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
int i, j;
|
||||
struct timeval now;
|
||||
|
||||
LCL_ReadCookedTime(&now, NULL);
|
||||
SCH_GetLastEventTime(&now, NULL, NULL);
|
||||
|
||||
first_index = ntohl(rx_message->data.client_accesses_by_index.first_index);
|
||||
n_indices = ntohl(rx_message->data.client_accesses_by_index.n_indices);
|
||||
if (n_indices > MAX_CLIENT_ACCESSES)
|
||||
n_indices = MAX_CLIENT_ACCESSES;
|
||||
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
tx_message->reply = htons(RPY_CLIENT_ACCESSES_BY_INDEX);
|
||||
|
||||
for (i = 0, j = 0; i < n_indices; i++) {
|
||||
@@ -1521,7 +1411,6 @@ handle_manual_list(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
RPY_ManualListSample *sample;
|
||||
RPT_ManualSamplesReport report[MAX_MANUAL_LIST_SAMPLES];
|
||||
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
tx_message->reply = htons(RPY_MANUAL_LIST);
|
||||
|
||||
MNL_ReportSamples(report, MAX_MANUAL_LIST_SAMPLES, &n_samples);
|
||||
@@ -1540,16 +1429,11 @@ handle_manual_list(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
static void
|
||||
handle_manual_delete(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
int status;
|
||||
int index;
|
||||
|
||||
index = ntohl(rx_message->data.manual_delete.index);
|
||||
status = MNL_DeleteSample(index);
|
||||
if (!status) {
|
||||
if (!MNL_DeleteSample(index))
|
||||
tx_message->status = htons(STT_BADSAMPLE);
|
||||
} else {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1557,11 +1441,8 @@ handle_manual_delete(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
static void
|
||||
handle_make_step(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
if (!LCL_MakeStep()) {
|
||||
if (!LCL_MakeStep())
|
||||
tx_message->status = htons(STT_FAILED);
|
||||
} else {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1576,7 +1457,6 @@ handle_activity(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
tx_message->data.activity.burst_online = htonl(report.burst_online);
|
||||
tx_message->data.activity.burst_offline = htonl(report.burst_offline);
|
||||
tx_message->data.activity.unresolved = htonl(report.unresolved);
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
tx_message->reply = htons(RPY_ACTIVITY);
|
||||
}
|
||||
|
||||
@@ -1588,7 +1468,6 @@ handle_reselect_distance(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
double dist;
|
||||
dist = UTI_FloatNetworkToHost(rx_message->data.reselect_distance.distance);
|
||||
SRC_SetReselectDistance(dist);
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1597,7 +1476,6 @@ static void
|
||||
handle_reselect(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
SRC_ReselectSource();
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1653,8 +1531,8 @@ read_from_cmd_socket(void *anything)
|
||||
|
||||
read_length = status;
|
||||
|
||||
LCL_ReadRawTime(&now);
|
||||
LCL_CookTime(&now, &cooked_now, NULL);
|
||||
/* Get current time cheaply */
|
||||
SCH_GetLastEventTime(&cooked_now, NULL, &now);
|
||||
|
||||
UTI_SockaddrToIPAndPort(&where_from.u, &remote_ip, &remote_port);
|
||||
|
||||
@@ -1709,6 +1587,7 @@ read_from_cmd_socket(void *anything)
|
||||
tx_message.command = rx_message.command;
|
||||
tx_message.sequence = rx_message.sequence;
|
||||
tx_message.reply = htons(RPY_NULL);
|
||||
tx_message.status = htons(STT_SUCCESS);
|
||||
tx_message.pad1 = 0;
|
||||
tx_message.pad2 = 0;
|
||||
tx_message.pad3 = 0;
|
||||
@@ -1909,7 +1788,11 @@ read_from_cmd_socket(void *anything)
|
||||
if (allowed) {
|
||||
switch(rx_command) {
|
||||
case REQ_NULL:
|
||||
handle_null(&rx_message, &tx_message);
|
||||
/* Do nothing */
|
||||
break;
|
||||
|
||||
case REQ_DUMP:
|
||||
handle_dump(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_ONLINE:
|
||||
@@ -1932,11 +1815,6 @@ read_from_cmd_socket(void *anything)
|
||||
handle_modify_maxpoll(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_DUMP:
|
||||
SRC_DumpSources();
|
||||
tx_message.status = htons(STT_SUCCESS);
|
||||
break;
|
||||
|
||||
case REQ_MODIFY_MAXDELAY:
|
||||
handle_modify_maxdelay(&rx_message, &tx_message);
|
||||
break;
|
||||
@@ -2004,35 +1882,35 @@ read_from_cmd_socket(void *anything)
|
||||
break;
|
||||
|
||||
case REQ_ALLOW:
|
||||
handle_allow(&rx_message, &tx_message);
|
||||
handle_allowdeny(&rx_message, &tx_message, 1, 0);
|
||||
break;
|
||||
|
||||
case REQ_ALLOWALL:
|
||||
handle_allowall(&rx_message, &tx_message);
|
||||
handle_allowdeny(&rx_message, &tx_message, 1, 1);
|
||||
break;
|
||||
|
||||
case REQ_DENY:
|
||||
handle_deny(&rx_message, &tx_message);
|
||||
handle_allowdeny(&rx_message, &tx_message, 0, 0);
|
||||
break;
|
||||
|
||||
case REQ_DENYALL:
|
||||
handle_denyall(&rx_message, &tx_message);
|
||||
handle_allowdeny(&rx_message, &tx_message, 0, 1);
|
||||
break;
|
||||
|
||||
case REQ_CMDALLOW:
|
||||
handle_cmdallow(&rx_message, &tx_message);
|
||||
handle_cmdallowdeny(&rx_message, &tx_message, 1, 0);
|
||||
break;
|
||||
|
||||
case REQ_CMDALLOWALL:
|
||||
handle_cmdallowall(&rx_message, &tx_message);
|
||||
handle_cmdallowdeny(&rx_message, &tx_message, 1, 1);
|
||||
break;
|
||||
|
||||
case REQ_CMDDENY:
|
||||
handle_cmddeny(&rx_message, &tx_message);
|
||||
handle_cmdallowdeny(&rx_message, &tx_message, 0, 0);
|
||||
break;
|
||||
|
||||
case REQ_CMDDENYALL:
|
||||
handle_cmddenyall(&rx_message, &tx_message);
|
||||
handle_cmdallowdeny(&rx_message, &tx_message, 0, 1);
|
||||
break;
|
||||
|
||||
case REQ_ACCHECK:
|
||||
@@ -2071,6 +1949,14 @@ read_from_cmd_socket(void *anything)
|
||||
handle_tracking(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_SMOOTHING:
|
||||
handle_smoothing(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_SMOOTHTIME:
|
||||
handle_smoothtime(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_SOURCESTATS:
|
||||
handle_sourcestats(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2013
|
||||
* 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
|
||||
|
||||
20
conf.c
20
conf.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2009-2014
|
||||
* Copyright (C) Miroslav Lichvar 2009-2015
|
||||
*
|
||||
* 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
|
||||
@@ -189,6 +189,7 @@ static char *pidfile;
|
||||
/* Smoothing constants */
|
||||
static double smooth_max_freq = 0.0; /* in ppm */
|
||||
static double smooth_max_wander = 0.0; /* in ppm/s */
|
||||
static int smooth_leap_only = 0;
|
||||
|
||||
/* Temperature sensor, update interval and compensation coefficients */
|
||||
static char *tempcomp_sensor_file = NULL;
|
||||
@@ -1174,11 +1175,23 @@ parse_broadcast(char *line)
|
||||
static void
|
||||
parse_smoothtime(char *line)
|
||||
{
|
||||
check_number_of_args(line, 2);
|
||||
if (get_number_of_args(line) != 3)
|
||||
check_number_of_args(line, 2);
|
||||
|
||||
if (sscanf(line, "%lf %lf", &smooth_max_freq, &smooth_max_wander) != 2) {
|
||||
smooth_max_freq = 0.0;
|
||||
command_parse_error();
|
||||
}
|
||||
|
||||
line = CPS_SplitWord(CPS_SplitWord(line));
|
||||
smooth_leap_only = 0;
|
||||
|
||||
if (*line) {
|
||||
if (!strcasecmp(line, "leaponly"))
|
||||
smooth_leap_only = 1;
|
||||
else
|
||||
command_parse_error();
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1738,10 +1751,11 @@ CNF_GetLockMemory(void)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
CNF_GetSmooth(double *max_freq, double *max_wander)
|
||||
CNF_GetSmooth(double *max_freq, double *max_wander, int *leap_only)
|
||||
{
|
||||
*max_freq = smooth_max_freq;
|
||||
*max_wander = smooth_max_wander;
|
||||
*leap_only = smooth_leap_only;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
2
conf.h
2
conf.h
@@ -96,7 +96,7 @@ extern void CNF_SetupAccessRestrictions(void);
|
||||
extern int CNF_GetSchedPriority(void);
|
||||
extern int CNF_GetLockMemory(void);
|
||||
|
||||
extern void CNF_GetSmooth(double *max_freq, double *max_wander);
|
||||
extern void CNF_GetSmooth(double *max_freq, double *max_wander, int *leap_only);
|
||||
extern void CNF_GetTempComp(char **file, double *interval, char **point_file, double *T0, double *k0, double *k1, double *k2);
|
||||
|
||||
extern char *CNF_GetUser(void);
|
||||
|
||||
7
configure
vendored
7
configure
vendored
@@ -404,6 +404,13 @@ case $SYSTEM in
|
||||
SYSDEFS=""
|
||||
echo "Configuring for $SYSTEM"
|
||||
;;
|
||||
Darwin-* )
|
||||
EXTRA_OBJECTS="sys_macosx.o"
|
||||
EXTRA_LIBS="-lresolv"
|
||||
EXTRA_CLI_LIBS="-lresolv"
|
||||
add_def MACOSX
|
||||
echo "Configuring for MacOS X (" $SYSTEM "MacOS X version" $VERSION ")"
|
||||
;;
|
||||
SunOS-i86pc* )
|
||||
# Doug Woodward <dougw@whistler.com> reported that this configuration
|
||||
# works for Solaris 2.8 / SunOS 5.8 on x86 platforms
|
||||
|
||||
273
doc/faq.adoc
Normal file
273
doc/faq.adoc
Normal file
@@ -0,0 +1,273 @@
|
||||
:toc:
|
||||
:numbered:
|
||||
|
||||
Frequently Asked Questions
|
||||
==========================
|
||||
|
||||
== Chrony compared to other programs
|
||||
|
||||
=== How does +chrony+ compare to +ntpd+?
|
||||
|
||||
+chrony+ can usually synchronise the system clock faster and with better time
|
||||
accuracy, but it doesn't implement all NTP features, e.g. broadcast/multicast
|
||||
mode, or authentication based on public-key cryptography. For a more detailed
|
||||
comparison, see the http://chrony.tuxfamily.org/comparison.html[comparison
|
||||
page] on the chrony website and section
|
||||
http://chrony.tuxfamily.org/manual.html#Comparison-with-ntpd[Comparison with
|
||||
ntpd] in the manual.
|
||||
|
||||
If your computer connects to the 'net only for few minutes at a time, you turn
|
||||
your Linux computer off or suspend it frequently, the clock is not very stable
|
||||
(e.g. it is a virtual machine), or you want to use NTP on an isolated network
|
||||
with no hardware clocks in sight, +chrony+ will probably work much better for
|
||||
you.
|
||||
|
||||
The original reason +chrony+ was written was that ntpd (called xntpd at the
|
||||
time) could not to do anything sensible on a PC which was connected to the 'net
|
||||
only for about 5 minutes once or twice a day, mainly to upload/download email
|
||||
and news. The requirements were
|
||||
|
||||
* slew the time to correct it when going 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.
|
||||
|
||||
Also, when working with isolated networks with no true time references at all
|
||||
ntpd was found to give no help with managing the local clock's gain/loss rate
|
||||
on the NTP master node (which was set from watch). Some automated support was
|
||||
added to +chrony+ to deal with this.
|
||||
|
||||
== Configuration issues
|
||||
|
||||
=== I have several computers on a LAN. Should be all clients of an external server?
|
||||
|
||||
The best configuration is usually to make one computer the master, with
|
||||
the others as clients of it. Add a +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.
|
||||
|
||||
=== Must I specify servers by IP address if DNS is not available on chronyd start?
|
||||
|
||||
No. Starting from version 1.25, +chronyd+ will keep trying to resolve
|
||||
the hostnames specified in the +server+ and +peer+ directives in
|
||||
increasing intervals until it succeeds. The +online+ command can be
|
||||
issued from +chronyc+ to try to resolve them immediately.
|
||||
|
||||
=== How can I make chronyd more secure?
|
||||
|
||||
If you don't need to serve time to NTP clients or peers, you can add +port 0+
|
||||
to the 'chrony.conf' file to completely disable the NTP server functionality
|
||||
and prevent NTP requests from reaching +chronyd+. Starting from version 2.0,
|
||||
the NTP server port is open only when client access is allowed by the +allow+
|
||||
directive or command, an NTP peer is configured, or the +broadcast+ directive
|
||||
is used.
|
||||
|
||||
If you don't need to use +chronyc+ remotely, you can add the following
|
||||
directives to the configuration file to bind the command sockets to the
|
||||
loopback interface. This is done by default since version 2.0.
|
||||
|
||||
----
|
||||
bindcmdaddress 127.0.0.1
|
||||
bindcmdaddress ::1
|
||||
----
|
||||
|
||||
If you don't need to use +chronyc+ at all, you can disable the command sockets
|
||||
by adding +cmdport 0+ to the configuration file.
|
||||
|
||||
On Linux, if +chronyd+ is compiled with support for Linux capabilities
|
||||
(available in the libcap library), you can specify an unprivileged user with
|
||||
the +-u+ option or +user+ directive in the 'chrony.conf' file to drop root
|
||||
privileges after start. The configure option +--with-user+ can be used to drop
|
||||
the privileges by default.
|
||||
|
||||
=== How can I improve the accuracy of the system clock with NTP sources?
|
||||
|
||||
Select NTP servers that are well synchronised, stable and close to your
|
||||
network. It's better to use more than one server, three or four is usually
|
||||
recommended as the minimum, so +chronyd+ can detect falsetickers and combine
|
||||
measurements from multiple sources.
|
||||
|
||||
There are also useful options which can be set in the +server+ directive, they
|
||||
are +minpoll+, +maxpoll+, +polltarget+, +maxdelay+, +maxdelayratio+ and
|
||||
+maxdelaydevratio+.
|
||||
|
||||
The first three options set the minimum and maximum allowed polling interval,
|
||||
and how should be the actual interval adjusted in the specified range. Their
|
||||
default values are 6 (64 seconds) for +minpoll+, 10 (1024 seconds) for
|
||||
+maxpoll+ and 6 (samples) for +polltarget+. The default values should be used
|
||||
for general servers on the internet. With your own NTP servers or if have
|
||||
permission to poll some servers more frequently, setting these options for
|
||||
shorter polling intervals may significantly improve the accuracy of the system
|
||||
clock.
|
||||
|
||||
The optimal polling interval depends on many factors, including the ratio
|
||||
between the wander of the clock and the network jitter (sometimes expressed in
|
||||
NTP documents as the Allan intercept), the temperature sensitivity of the
|
||||
crystal oscillator and the maximum rate of change of the temperature.
|
||||
|
||||
An example of the directive for an NTP server on the internet that you are
|
||||
allowed to poll frequently could be
|
||||
|
||||
----
|
||||
server foo.example.net minpoll 4 maxpoll 6 polltarget 16
|
||||
----
|
||||
|
||||
An example using very short polling intervals for a server located in the same
|
||||
LAN could be
|
||||
|
||||
----
|
||||
server ntp.local minpoll 2 maxpoll 4 polltarget 30
|
||||
----
|
||||
|
||||
The maxdelay options are useful to ignore measurements with larger delay (e.g.
|
||||
due to congestion in the network) and improve the stability of the
|
||||
synchronisation. The +maxdelaydevratio+ option could be added to the example
|
||||
with local NTP server
|
||||
|
||||
----
|
||||
server ntp.local minpoll 2 maxpoll 4 polltarget 30 maxdelaydevratio 2
|
||||
----
|
||||
|
||||
== Computer is not synchronising
|
||||
|
||||
This is the most common problem. There are a number of reasons, see the
|
||||
following questions.
|
||||
|
||||
=== Behind a firewall?
|
||||
|
||||
If there is a firewall between you and the NTP server you're trying to use, the
|
||||
packets may be blocked. Try using a tool like wireshark or tcpdump to see if
|
||||
you're getting responses from the server. If you have an external modem, see
|
||||
if the receive light blinks straight after the transmit light (when the link is
|
||||
quiet apart from the NTP traffic.) Try adding +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.
|
||||
|
||||
=== Are NTP servers specified with the +offline+ option?
|
||||
|
||||
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.
|
||||
|
||||
== Issues with +chronyc+
|
||||
|
||||
=== I keep getting the error +506 Cannot talk to daemon+
|
||||
|
||||
When accessing +chronyd+ remotely, 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 and an appropriate 'bindcmdaddress'
|
||||
directive. This isn't necessary for localhost.
|
||||
|
||||
Perhaps +chronyd+ is not running. Try using the +ps+ command (e.g. on Linux,
|
||||
+ps -auxw+) to see if it's running. Or try +netstat -a+ and see if the ports
|
||||
123/udp and 323/udp are listening. If +chronyd+ is not running, you may have a
|
||||
problem with the way you are trying to start it (e.g. at boot time).
|
||||
|
||||
Perhaps you have a firewall set up in a way that blocks packets on port
|
||||
323/udp. You need to amend the firewall configuration in this case.
|
||||
|
||||
=== Is the +chronyc+ / +chronyd+ protocol documented anywhere?
|
||||
|
||||
Only by the source code :-) See 'cmdmon.c' (+chronyd+ side) and 'client.c'
|
||||
(+chronyc+ side).
|
||||
|
||||
== Real-time clock issues
|
||||
|
||||
=== 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.
|
||||
|
||||
=== I want to use +chronyd+'s real-time clock support. Must I disable hwclock?
|
||||
|
||||
The hwclock program is often set-up by default in the boot and shutdown scripts
|
||||
with many Linux installations. If you want to use +chronyd+'s real-time clock
|
||||
support, the important thing is to disable hwclock in the shutdown procedure.
|
||||
If you don't, it will over-write the RTC with a new value, unknown to
|
||||
+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.
|
||||
|
||||
=== 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
|
||||
|
||||
== Microsoft Windows
|
||||
|
||||
=== 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 a
|
||||
service.
|
||||
|
||||
=== 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.
|
||||
|
||||
== NTP-specific issues
|
||||
|
||||
=== Can +chrony+ be driven from broadcast NTP servers?
|
||||
|
||||
No, this NTP mode is not implemented yet.
|
||||
|
||||
=== 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.
|
||||
|
||||
=== Can +chrony+ keep the system clock a fixed offset away from real time?
|
||||
|
||||
This is not possible as the program currently stands.
|
||||
|
||||
=== What happens if the network connection is dropped without using +chronyc+'s +offline+ command first?
|
||||
|
||||
+chronyd+ will keep trying to access the server(s) that it thinks are online.
|
||||
When the network is connected again, it will take some time (on average half of
|
||||
the current polling interval) before new measurements are made and the clock is
|
||||
corrected. If the servers were set to offline and the +online+ command was
|
||||
issued when the network was connected, +chronyd+ would make new measurements
|
||||
immediately.
|
||||
|
||||
The +auto_offline+ option to the +server+ entry in the 'chrony.conf' file may
|
||||
be useful to switch the servers to the offline state automatically.
|
||||
|
||||
== Linux-specific issues
|
||||
|
||||
=== I get +Could not open /dev/rtc, Device or resource busy+ in my syslog file
|
||||
|
||||
Some other program running on the system may be using the device.
|
||||
|
||||
== Solaris-specific issues
|
||||
|
||||
=== I get an error message about not being able to open kvm to change dosynctodr
|
||||
|
||||
(The dosynctodr variable controls whether Solaris couples the equivalent
|
||||
of its BIOS clock into its system clock at regular intervals). The
|
||||
Solaris port of +chrony+ was developed in the Solaris 2.5 era. Some
|
||||
aspect of the Solaris kernel has changed which prevents the same
|
||||
technique working. We no longer have root access to any Solaris
|
||||
machines to work on this, and we are reliant on somebody developing the
|
||||
patch and testing it.
|
||||
@@ -45,7 +45,6 @@ cp chrony.info* $RPM_BUILD_ROOT%{_infodir}
|
||||
%{_sbindir}/chronyd
|
||||
%{_bindir}/chronyc
|
||||
%{_infodir}/chrony.info*
|
||||
%{_mandir}/man1/chrony.1.gz
|
||||
%{_mandir}/man1/chronyc.1.gz
|
||||
%{_mandir}/man5/chrony.conf.5.gz
|
||||
%{_mandir}/man8/chronyd.8.gz
|
||||
|
||||
5
local.c
5
local.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2011, 2014
|
||||
* Copyright (C) Miroslav Lichvar 2011, 2014-2015
|
||||
*
|
||||
* 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
|
||||
@@ -564,6 +564,9 @@ LCL_NotifyLeap(int leap)
|
||||
LCL_ReadRawTime(&raw);
|
||||
LCL_CookTime(&raw, &cooked, NULL);
|
||||
|
||||
/* Smooth the leap second out */
|
||||
SMT_Leap(&cooked, leap);
|
||||
|
||||
/* Dispatch to all handlers as if the clock was stepped */
|
||||
invoke_parameter_change_handlers(&raw, &cooked, 0.0, -leap, LCL_ChangeStep);
|
||||
}
|
||||
|
||||
@@ -94,6 +94,7 @@ typedef enum {
|
||||
LOGF_Sys,
|
||||
LOGF_SysGeneric,
|
||||
LOGF_SysLinux,
|
||||
LOGF_SysMacOSX,
|
||||
LOGF_SysNetBSD,
|
||||
LOGF_SysSolaris,
|
||||
LOGF_SysSunOS,
|
||||
|
||||
9
main.c
9
main.c
@@ -347,6 +347,7 @@ int main
|
||||
(int argc, char **argv)
|
||||
{
|
||||
const char *conf_file = DEFAULT_CONF_FILE;
|
||||
const char *progname = argv[0];
|
||||
char *user = NULL;
|
||||
int debug = 0, nofork = 0, address_family = IPADDR_UNSPEC;
|
||||
int do_init_rtc = 0, restarted = 0;
|
||||
@@ -386,7 +387,7 @@ int main
|
||||
} 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 (%s)\n", CHRONY_VERSION, CHRONYD_FEATURES);
|
||||
exit(0);
|
||||
return 0;
|
||||
} else if (!strcmp("-n", *argv)) {
|
||||
nofork = 1;
|
||||
} else if (!strcmp("-d", *argv)) {
|
||||
@@ -405,6 +406,10 @@ int main
|
||||
address_family = IPADDR_INET4;
|
||||
} else if (!strcmp("-6", *argv)) {
|
||||
address_family = IPADDR_INET6;
|
||||
} else if (!strcmp("-h", *argv) || !strcmp("--help", *argv)) {
|
||||
printf("Usage: %s [-4|-6] [-n|-d] [-q|-Q] [-r] [-R] [-s] [-f FILE|COMMAND...]\n",
|
||||
progname);
|
||||
return 0;
|
||||
} else if (*argv[0] == '-') {
|
||||
LOG_FATAL(LOGF_Main, "Unrecognized command line option [%s]", *argv);
|
||||
} else {
|
||||
@@ -417,7 +422,7 @@ int main
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Turn into a daemon */
|
||||
|
||||
14
make_release
14
make_release
@@ -39,7 +39,7 @@ echo $version > version.txt
|
||||
|
||||
sed -i -e "s%@@VERSION@@%${version}%" examples/chrony.spec
|
||||
|
||||
for m in chrony.1 chronyc.1.in chrony.conf.5.in chronyd.8.in; do
|
||||
for m in 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
|
||||
@@ -59,15 +59,9 @@ if [ $(wc -l < INSTALL) -gt 100 -o $(wc -l < INSTALL) -lt 85 ]; then
|
||||
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
|
||||
a2x --lynx -f text doc/faq.adoc || exit 1
|
||||
mv doc/faq.text FAQ
|
||||
rm -rf doc
|
||||
|
||||
rm -f config.h config.log make_release .gitignore
|
||||
|
||||
|
||||
5
ntp.h
5
ntp.h
@@ -109,4 +109,9 @@ typedef struct {
|
||||
#define NTP_LVM(leap, version, mode) \
|
||||
((((leap) << 6) & 0xc0) | (((version) << 3) & 0x38) | ((mode) & 0x07))
|
||||
|
||||
/* Special NTP reference IDs */
|
||||
#define NTP_REFID_UNSYNC 0x0UL
|
||||
#define NTP_REFID_LOCAL 0x7F7F0101UL /* 127.127.1.1 */
|
||||
#define NTP_REFID_SMOOTH 0x7F7F01FFUL /* 127.127.1.255 */
|
||||
|
||||
#endif /* GOT_NTP_H */
|
||||
|
||||
26
ntp_core.c
26
ntp_core.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2009-2014
|
||||
* Copyright (C) Miroslav Lichvar 2009-2015
|
||||
*
|
||||
* 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
|
||||
@@ -316,7 +316,7 @@ NCR_Initialise(void)
|
||||
do_time_checks();
|
||||
|
||||
logfileid = CNF_GetLogMeasurements() ? LOG_FileOpen("measurements",
|
||||
" Date (UTC) Time IP Address L St 123 567 ABCD LP RP Score Offset Peer del. Peer disp. Root del. Root disp.")
|
||||
" Date (UTC) Time IP Address L St 123 567 ABCD LP RP Score Offset Peer del. Peer disp. Root del. Root disp.")
|
||||
: -1;
|
||||
|
||||
access_auth_table = ADF_CreateTable();
|
||||
@@ -789,8 +789,8 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||
|
||||
/* Get current smoothing offset when sending packet to a client */
|
||||
if (SMT_IsEnabled() && (my_mode == MODE_SERVER || my_mode == MODE_BROADCAST)) {
|
||||
smooth_time = 1;
|
||||
smooth_offset = SMT_GetOffset(&local_transmit);
|
||||
smooth_time = fabs(smooth_offset) > LCL_GetSysPrecisionAsQuantum();
|
||||
|
||||
/* Suppress leap second when smoothing and slew mode are enabled */
|
||||
if (REF_GetLeapMode() == REF_LeapModeSlew &&
|
||||
@@ -801,6 +801,14 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||
smooth_offset = 0.0;
|
||||
}
|
||||
|
||||
if (smooth_time) {
|
||||
our_ref_id = NTP_REFID_SMOOTH;
|
||||
UTI_AddDoubleToTimeval(&our_ref_time, smooth_offset, &our_ref_time);
|
||||
UTI_AddDoubleToTimeval(local_rx, smooth_offset, &local_receive);
|
||||
} else {
|
||||
local_receive = *local_rx;
|
||||
}
|
||||
|
||||
if (are_we_synchronised) {
|
||||
leap = (int) leap_status;
|
||||
} else {
|
||||
@@ -824,17 +832,10 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||
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);
|
||||
message.reference_id = htonl(our_ref_id);
|
||||
|
||||
/* Now fill in timestamps */
|
||||
|
||||
if (smooth_time) {
|
||||
UTI_AddDoubleToTimeval(&our_ref_time, smooth_offset, &our_ref_time);
|
||||
UTI_AddDoubleToTimeval(local_rx, smooth_offset, &local_receive);
|
||||
} else {
|
||||
local_receive = *local_rx;
|
||||
}
|
||||
|
||||
UTI_TimevalToInt64(&our_ref_time, &message.reference_ts, 0);
|
||||
|
||||
/* Originate - this comes from the last packet the source sent us */
|
||||
@@ -1230,7 +1231,8 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
|
||||
inst->local_ntp_tx.hi = inst->local_ntp_tx.lo = 0;
|
||||
|
||||
if (valid_packet) {
|
||||
precision = LCL_GetSysPrecisionAsQuantum();
|
||||
precision = LCL_GetSysPrecisionAsQuantum() +
|
||||
UTI_Log2ToDouble(message->precision);
|
||||
|
||||
SRC_GetFrequencyRange(inst->source, &source_freq_lo, &source_freq_hi);
|
||||
|
||||
|
||||
11
ntp_io.c
11
ntp_io.c
@@ -4,7 +4,7 @@
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Timo Teras 2009
|
||||
* Copyright (C) Miroslav Lichvar 2009, 2013-2014
|
||||
* Copyright (C) Miroslav Lichvar 2009, 2013-2015
|
||||
*
|
||||
* 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
|
||||
@@ -97,8 +97,13 @@ prepare_socket(int family, int port_number, int client_only)
|
||||
sock_fd = socket(family, SOCK_DGRAM, 0);
|
||||
|
||||
if (sock_fd < 0) {
|
||||
LOG(LOGS_ERR, LOGF_NtpIO, "Could not open %s NTP socket : %s",
|
||||
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
|
||||
if (!client_only) {
|
||||
LOG(LOGS_ERR, LOGF_NtpIO, "Could not open %s NTP socket : %s",
|
||||
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
|
||||
} else {
|
||||
DEBUG_LOG(LOGF_NtpIO, "Could not open %s NTP socket : %s",
|
||||
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
|
||||
}
|
||||
return INVALID_SOCK_FD;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ typedef struct {
|
||||
NTP_Remote_Address *remote_addr; /* The address of this source, non-NULL
|
||||
means this slot in table is in use */
|
||||
NCR_Instance data; /* Data for the protocol engine for this source */
|
||||
char *name; /* Name of the source, may be NULL */
|
||||
int pool; /* Number of the pool from which was this source
|
||||
added or INVALID_POOL */
|
||||
int tentative; /* Flag indicating there was no valid response
|
||||
@@ -85,6 +86,7 @@ struct UnresolvedSource {
|
||||
#define RESOLVE_INTERVAL_UNIT 7
|
||||
#define MIN_RESOLVE_INTERVAL 2
|
||||
#define MAX_RESOLVE_INTERVAL 9
|
||||
#define MIN_REPLACEMENT_INTERVAL 8
|
||||
|
||||
static struct UnresolvedSource *unresolved_sources = NULL;
|
||||
static int resolving_interval = 0;
|
||||
@@ -92,15 +94,11 @@ static SCH_TimeoutID resolving_id;
|
||||
static struct UnresolvedSource *resolving_source = NULL;
|
||||
static NSR_SourceResolvingEndHandler resolving_end_handler = NULL;
|
||||
|
||||
#define MIN_POOL_RESOLVE_INTERVAL 5
|
||||
#define MAX_POOL_SOURCES 16
|
||||
#define INVALID_POOL (-1)
|
||||
|
||||
/* Pool of sources, the name is expected to resolve to multiple addresses
|
||||
which change over time */
|
||||
/* Pool of sources with the same name */
|
||||
struct SourcePool {
|
||||
char *name;
|
||||
int port;
|
||||
/* Number of sources added from this pool (ignoring tentative sources) */
|
||||
int sources;
|
||||
/* Maximum number of sources */
|
||||
@@ -115,6 +113,7 @@ static ARR_Instance pools;
|
||||
|
||||
static void resolve_sources(void *arg);
|
||||
static void rehash_records(void);
|
||||
static void clean_source_record(SourceRecord *record);
|
||||
|
||||
static void
|
||||
slew_sources(struct timeval *raw,
|
||||
@@ -162,16 +161,12 @@ NSR_Finalise(void)
|
||||
struct UnresolvedSource *us;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARR_GetSize(pools); i++)
|
||||
Free(((struct SourcePool *)ARR_GetElement(pools, i))->name);
|
||||
ARR_DestroyInstance(pools);
|
||||
|
||||
for (i = 0; i < ARR_GetSize(records); i++) {
|
||||
record = get_record(i);
|
||||
if (!record->remote_addr)
|
||||
continue;
|
||||
record->remote_addr = NULL;
|
||||
NCR_DestroyInstance(record->data);
|
||||
if (record->remote_addr)
|
||||
clean_source_record(record);
|
||||
}
|
||||
|
||||
ARR_DestroyInstance(records);
|
||||
@@ -296,7 +291,7 @@ rehash_records(void)
|
||||
|
||||
/* Procedure to add a new source */
|
||||
static NSR_Status
|
||||
add_source(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params, int pool)
|
||||
add_source(NTP_Remote_Address *remote_addr, char *name, NTP_Source_Type type, SourceParameters *params, int pool)
|
||||
{
|
||||
SourceRecord *record;
|
||||
int slot, found;
|
||||
@@ -323,6 +318,7 @@ add_source(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParamete
|
||||
record = get_record(slot);
|
||||
record->data = NCR_GetInstance(remote_addr, type, params);
|
||||
record->remote_addr = NCR_GetRemoteAddress(record->data);
|
||||
record->name = name ? Strdup(name) : NULL;
|
||||
record->pool = pool;
|
||||
record->tentative = pool != INVALID_POOL ? 1 : 0;
|
||||
|
||||
@@ -373,7 +369,7 @@ process_resolved_name(struct UnresolvedSource *us, IPAddr *ip_addrs, int n_addrs
|
||||
int i, added;
|
||||
|
||||
for (i = added = 0; i < n_addrs; i++) {
|
||||
DEBUG_LOG(LOGF_NtpSources, "%s resolved to %s", us->name, UTI_IPToString(&ip_addrs[i]));
|
||||
DEBUG_LOG(LOGF_NtpSources, "(%d) %s", i + 1, UTI_IPToString(&ip_addrs[i]));
|
||||
|
||||
address.ip_addr = ip_addrs[i];
|
||||
address.port = us->port;
|
||||
@@ -382,7 +378,7 @@ process_resolved_name(struct UnresolvedSource *us, IPAddr *ip_addrs, int n_addrs
|
||||
if (replace_source(&us->replace_source, &address) != NSR_AlreadyInUse)
|
||||
break;
|
||||
} else {
|
||||
if (add_source(&address, us->new_source.type, &us->new_source.params,
|
||||
if (add_source(&address, us->name, us->new_source.type, &us->new_source.params,
|
||||
us->new_source.pool) == NSR_Success)
|
||||
added++;
|
||||
|
||||
@@ -403,6 +399,8 @@ name_resolve_handler(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *any
|
||||
|
||||
assert(us == resolving_source);
|
||||
|
||||
DEBUG_LOG(LOGF_NtpSources, "%s resolved to %d addrs", us->name, n_addrs);
|
||||
|
||||
switch (status) {
|
||||
case DNS_TryAgain:
|
||||
break;
|
||||
@@ -495,7 +493,7 @@ append_unresolved_source(struct UnresolvedSource *us)
|
||||
NSR_Status
|
||||
NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params)
|
||||
{
|
||||
return add_source(remote_addr, type, params, INVALID_POOL);
|
||||
return add_source(remote_addr, NULL, type, params, INVALID_POOL);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -505,6 +503,15 @@ NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, Source
|
||||
{
|
||||
struct UnresolvedSource *us;
|
||||
struct SourcePool *sp;
|
||||
NTP_Remote_Address remote_addr;
|
||||
|
||||
/* If the name is an IP address, don't bother with full resolving now
|
||||
or later when trying to replace the source */
|
||||
if (UTI_StringToIP(name, &remote_addr.ip_addr)) {
|
||||
remote_addr.port = port;
|
||||
NSR_AddSource(&remote_addr, type, params);
|
||||
return;
|
||||
}
|
||||
|
||||
us = MallocNew(struct UnresolvedSource);
|
||||
us->name = Strdup(name);
|
||||
@@ -518,8 +525,6 @@ NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, Source
|
||||
us->new_source.max_new_sources = 1;
|
||||
} else {
|
||||
sp = (struct SourcePool *)ARR_GetNewElement(pools);
|
||||
sp->name = Strdup(name);
|
||||
sp->port = port;
|
||||
sp->sources = 0;
|
||||
sp->max_sources = params->max_sources;
|
||||
us->new_source.pool = ARR_GetSize(pools) - 1;
|
||||
@@ -587,6 +592,8 @@ clean_source_record(SourceRecord *record)
|
||||
assert(record->remote_addr);
|
||||
record->remote_addr = NULL;
|
||||
NCR_DestroyInstance(record->data);
|
||||
if (record->name)
|
||||
Free(record->name);
|
||||
|
||||
n_sources--;
|
||||
}
|
||||
@@ -640,15 +647,18 @@ NSR_RemoveAllSources(void)
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
resolve_pool_replacement(struct SourcePool *sp, NTP_Remote_Address *addr)
|
||||
resolve_source_replacement(SourceRecord *record)
|
||||
{
|
||||
struct UnresolvedSource *us;
|
||||
|
||||
DEBUG_LOG(LOGF_NtpSources, "trying to replace %s",
|
||||
UTI_IPToString(&record->remote_addr->ip_addr));
|
||||
|
||||
us = MallocNew(struct UnresolvedSource);
|
||||
us->name = Strdup(sp->name);
|
||||
us->port = sp->port;
|
||||
us->name = Strdup(record->name);
|
||||
us->port = record->remote_addr->port;
|
||||
us->replacement = 1;
|
||||
us->replace_source = *addr;
|
||||
us->replace_source = *record->remote_addr;
|
||||
|
||||
append_unresolved_source(us);
|
||||
NSR_ResolveSources();
|
||||
@@ -662,32 +672,33 @@ NSR_HandleBadSource(IPAddr *address)
|
||||
static struct timeval last_replacement;
|
||||
struct timeval now;
|
||||
NTP_Remote_Address remote_addr;
|
||||
struct SourcePool *pool;
|
||||
int pool_index, slot, found;
|
||||
SourceRecord *record;
|
||||
int slot, found;
|
||||
double diff;
|
||||
|
||||
remote_addr.ip_addr = *address;
|
||||
remote_addr.port = 0;
|
||||
|
||||
/* Only sources from a pool can be replaced */
|
||||
find_slot(&remote_addr, &slot, &found);
|
||||
if (!found || (pool_index = get_record(slot)->pool) == INVALID_POOL)
|
||||
if (!found)
|
||||
return;
|
||||
|
||||
pool = (struct SourcePool *)ARR_GetElement(pools, pool_index);
|
||||
record = get_record(slot);
|
||||
|
||||
/* Don't resolve the pool name too frequently */
|
||||
/* Only sources with a name can be replaced */
|
||||
if (!record->name)
|
||||
return;
|
||||
|
||||
/* Don't resolve names too frequently */
|
||||
SCH_GetLastEventTime(NULL, NULL, &now);
|
||||
UTI_DiffTimevalsToDouble(&diff, &now, &last_replacement);
|
||||
if (fabs(diff) < RESOLVE_INTERVAL_UNIT * (1 << MIN_POOL_RESOLVE_INTERVAL)) {
|
||||
if (fabs(diff) < RESOLVE_INTERVAL_UNIT * (1 << MIN_REPLACEMENT_INTERVAL)) {
|
||||
DEBUG_LOG(LOGF_NtpSources, "replacement postponed");
|
||||
return;
|
||||
}
|
||||
last_replacement = now;
|
||||
|
||||
DEBUG_LOG(LOGF_NtpSources, "pool replacement for %s", UTI_IPToString(address));
|
||||
|
||||
resolve_pool_replacement(pool, &remote_addr);
|
||||
resolve_source_replacement(record);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -741,7 +752,7 @@ NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP
|
||||
pool->sources++;
|
||||
|
||||
DEBUG_LOG(LOGF_NtpSources, "pool %s has %d confirmed sources",
|
||||
pool->name, pool->sources);
|
||||
record->name, pool->sources);
|
||||
|
||||
/* If the number of sources reached the configured maximum, remove
|
||||
the tentative sources added from this pool */
|
||||
|
||||
58
pktlength.c
58
pktlength.c
@@ -44,9 +44,8 @@ command_unpadded_length(CMD_Request *r)
|
||||
return 0;
|
||||
} else {
|
||||
switch (type) {
|
||||
|
||||
case REQ_NULL:
|
||||
return offsetof(CMD_Request, data);
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_ONLINE:
|
||||
return offsetof(CMD_Request, data.online.EOR);
|
||||
case REQ_OFFLINE:
|
||||
@@ -78,11 +77,11 @@ command_unpadded_length(CMD_Request *r)
|
||||
case REQ_MANUAL :
|
||||
return offsetof(CMD_Request, data.manual.EOR);
|
||||
case REQ_N_SOURCES :
|
||||
return offsetof(CMD_Request, data.n_sources.EOR);
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_SOURCE_DATA :
|
||||
return offsetof(CMD_Request, data.source_data.EOR);
|
||||
case REQ_REKEY :
|
||||
return offsetof(CMD_Request, data.rekey.EOR);
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_ALLOW :
|
||||
return offsetof(CMD_Request, data.allow_deny.EOR);
|
||||
case REQ_ALLOWALL :
|
||||
@@ -110,21 +109,21 @@ command_unpadded_length(CMD_Request *r)
|
||||
case REQ_DEL_SOURCE :
|
||||
return offsetof(CMD_Request, data.del_source.EOR);
|
||||
case REQ_WRITERTC :
|
||||
return offsetof(CMD_Request, data.writertc.EOR);
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_DFREQ :
|
||||
return offsetof(CMD_Request, data.dfreq.EOR);
|
||||
case REQ_DOFFSET :
|
||||
return offsetof(CMD_Request, data.doffset.EOR);
|
||||
case REQ_TRACKING :
|
||||
return offsetof(CMD_Request, data.tracking.EOR);
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_SOURCESTATS :
|
||||
return offsetof(CMD_Request, data.sourcestats.EOR);
|
||||
case REQ_RTCREPORT :
|
||||
return offsetof(CMD_Request, data.rtcreport.EOR);
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_TRIMRTC :
|
||||
return offsetof(CMD_Request, data.trimrtc.EOR);
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_CYCLELOGS :
|
||||
return offsetof(CMD_Request, data.cyclelogs.EOR);
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_SUBNETS_ACCESSED :
|
||||
case REQ_CLIENT_ACCESSES:
|
||||
/* No longer supported */
|
||||
@@ -132,21 +131,25 @@ command_unpadded_length(CMD_Request *r)
|
||||
case REQ_CLIENT_ACCESSES_BY_INDEX:
|
||||
return offsetof(CMD_Request, data.client_accesses_by_index.EOR);
|
||||
case REQ_MANUAL_LIST:
|
||||
return offsetof(CMD_Request, data.manual_list.EOR);
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_MANUAL_DELETE:
|
||||
return offsetof(CMD_Request, data.manual_delete.EOR);
|
||||
case REQ_MAKESTEP:
|
||||
return offsetof(CMD_Request, data.make_step.EOR);
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_ACTIVITY:
|
||||
return offsetof(CMD_Request, data.activity.EOR);
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_RESELECT:
|
||||
return offsetof(CMD_Request, data.reselect.EOR);
|
||||
return offsetof(CMD_Request, data.null.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);
|
||||
case REQ_SMOOTHING:
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_SMOOTHTIME:
|
||||
return offsetof(CMD_Request, data.smoothtime.EOR);
|
||||
default:
|
||||
/* If we fall through the switch, it most likely means we've forgotten to implement a new case */
|
||||
assert(0);
|
||||
@@ -228,11 +231,11 @@ PKL_CommandPaddingLength(CMD_Request *r)
|
||||
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);
|
||||
return PADDING_LENGTH(data.null.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);
|
||||
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
|
||||
case REQ_ALLOW:
|
||||
return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR);
|
||||
case REQ_ALLOWALL:
|
||||
@@ -260,21 +263,21 @@ PKL_CommandPaddingLength(CMD_Request *r)
|
||||
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);
|
||||
return PADDING_LENGTH(data.null.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);
|
||||
return PADDING_LENGTH(data.null.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);
|
||||
return PADDING_LENGTH(data.null.EOR, data.rtc.EOR);
|
||||
case REQ_TRIMRTC:
|
||||
return PADDING_LENGTH(data.trimrtc.EOR, data.null.EOR);
|
||||
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
|
||||
case REQ_CYCLELOGS:
|
||||
return PADDING_LENGTH(data.cyclelogs.EOR, data.null.EOR);
|
||||
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
|
||||
case REQ_SUBNETS_ACCESSED:
|
||||
case REQ_CLIENT_ACCESSES:
|
||||
/* No longer supported */
|
||||
@@ -282,21 +285,25 @@ PKL_CommandPaddingLength(CMD_Request *r)
|
||||
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);
|
||||
return PADDING_LENGTH(data.null.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);
|
||||
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
|
||||
case REQ_ACTIVITY:
|
||||
return PADDING_LENGTH(data.activity.EOR, data.activity.EOR);
|
||||
return PADDING_LENGTH(data.null.EOR, data.activity.EOR);
|
||||
case REQ_RESELECT:
|
||||
return PADDING_LENGTH(data.reselect.EOR, data.null.EOR);
|
||||
return PADDING_LENGTH(data.null.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);
|
||||
case REQ_SMOOTHING:
|
||||
return PADDING_LENGTH(data.null.EOR, data.smoothing.EOR);
|
||||
case REQ_SMOOTHTIME:
|
||||
return PADDING_LENGTH(data.smoothtime.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);
|
||||
@@ -360,7 +367,8 @@ PKL_ReplyLength(CMD_Reply *r)
|
||||
}
|
||||
case RPY_ACTIVITY:
|
||||
return offsetof(CMD_Reply, data.activity.EOR);
|
||||
|
||||
case RPY_SMOOTHING:
|
||||
return offsetof(CMD_Reply, data.smoothing.EOR);
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
13
refclock.c
13
refclock.c
@@ -499,15 +499,6 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static double
|
||||
poll_interval(int poll)
|
||||
{
|
||||
if (poll >= 0)
|
||||
return 1 << poll;
|
||||
else
|
||||
return 1.0 / (1 << -poll);
|
||||
}
|
||||
|
||||
static int
|
||||
valid_sample_time(RCL_Instance instance, struct timeval *tv)
|
||||
{
|
||||
@@ -516,7 +507,7 @@ valid_sample_time(RCL_Instance instance, struct timeval *tv)
|
||||
|
||||
LCL_ReadRawTime(&raw_time);
|
||||
UTI_DiffTimevalsToDouble(&diff, &raw_time, tv);
|
||||
if (diff < 0.0 || diff > poll_interval(instance->poll + 1)) {
|
||||
if (diff < 0.0 || diff > UTI_Log2ToDouble(instance->poll + 1)) {
|
||||
DEBUG_LOG(LOGF_Refclock, "%s refclock sample not valid age=%.6f tv=%s",
|
||||
UTI_RefidToString(instance->ref_id), diff, UTI_TimevalToString(tv));
|
||||
return 0;
|
||||
@@ -595,7 +586,7 @@ poll_timeout(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
inst->timeout_id = SCH_AddTimeoutByDelay(poll_interval(poll), poll_timeout, arg);
|
||||
inst->timeout_id = SCH_AddTimeoutByDelay(UTI_Log2ToDouble(poll), poll_timeout, arg);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
29
reference.c
29
reference.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2009-2014
|
||||
* Copyright (C) Miroslav Lichvar 2009-2015
|
||||
*
|
||||
* 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
|
||||
@@ -120,11 +120,6 @@ static LOG_FileID logfileid;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Reference ID supplied when we are locally referenced */
|
||||
#define LOCAL_REFERENCE_ID 0x7f7f0101UL
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Exponential moving averages of absolute clock frequencies
|
||||
used as a fallback when synchronisation is lost. */
|
||||
|
||||
@@ -248,9 +243,9 @@ REF_Initialise(void)
|
||||
|
||||
leap_tzname = CNF_GetLeapSecTimezone();
|
||||
if (leap_tzname) {
|
||||
/* Check that the timezone has good data for Jun 30 2008 and Dec 31 2008 */
|
||||
if (get_tz_leap(1214784000) == LEAP_Normal &&
|
||||
get_tz_leap(1230681600) == LEAP_InsertSecond) {
|
||||
/* Check that the timezone has good data for Jun 30 2012 and Dec 31 2012 */
|
||||
if (get_tz_leap(1341014400) == LEAP_InsertSecond &&
|
||||
get_tz_leap(1356912000) == LEAP_Normal) {
|
||||
LOG(LOGS_INFO, LOGF_Reference, "Using %s timezone to obtain leap second data", leap_tzname);
|
||||
} else {
|
||||
LOG(LOGS_WARN, LOGF_Reference, "Timezone %s failed leap second check, ignoring", leap_tzname);
|
||||
@@ -1109,12 +1104,10 @@ REF_SetManualReference
|
||||
double skew
|
||||
)
|
||||
{
|
||||
uint32_t manual_refid = 0x4D414E55; /* MANU */
|
||||
|
||||
/* We are not synchronised to an external source, as such. This is
|
||||
only supposed to be used with the local source option, really
|
||||
... */
|
||||
REF_SetReference(0, LEAP_Unsynchronised, 1, manual_refid, NULL,
|
||||
only supposed to be used with the local source option, really.
|
||||
Log as MANU in the tracking log, packets will have NTP_REFID_LOCAL. */
|
||||
REF_SetReference(0, LEAP_Unsynchronised, 1, 0x4D414E55UL, NULL,
|
||||
ref_time, offset, 0.0, frequency, skew, 0.0, 0.0);
|
||||
}
|
||||
|
||||
@@ -1200,7 +1193,7 @@ REF_GetReferenceParams
|
||||
*is_synchronised = 1;
|
||||
|
||||
*stratum = local_stratum;
|
||||
*ref_id = LOCAL_REFERENCE_ID;
|
||||
*ref_id = NTP_REFID_LOCAL;
|
||||
/* Make the reference time be now less a second - this will
|
||||
scarcely affect the client, but will ensure that the transmit
|
||||
timestamp cannot come before this (which would cause test 7 to
|
||||
@@ -1222,7 +1215,7 @@ REF_GetReferenceParams
|
||||
|
||||
*leap_status = LEAP_Unsynchronised;
|
||||
*stratum = NTP_MAX_STRATUM;
|
||||
*ref_id = 0;
|
||||
*ref_id = NTP_REFID_UNSYNC;
|
||||
ref_time->tv_sec = ref_time->tv_usec = 0;
|
||||
/* These values seem to be standard for a client, and
|
||||
any peer or client of ours will ignore them anyway because
|
||||
@@ -1336,7 +1329,7 @@ REF_GetTrackingReport(RPT_TrackingReport *rep)
|
||||
LCL_GetOffsetCorrection(&now_raw, &correction, NULL);
|
||||
UTI_AddDoubleToTimeval(&now_raw, correction, &now_cooked);
|
||||
|
||||
rep->ref_id = 0;
|
||||
rep->ref_id = NTP_REFID_UNSYNC;
|
||||
rep->ip_addr.family = IPADDR_UNSPEC;
|
||||
rep->stratum = 0;
|
||||
rep->leap_status = our_leap_status;
|
||||
@@ -1368,7 +1361,7 @@ REF_GetTrackingReport(RPT_TrackingReport *rep)
|
||||
|
||||
} else if (enable_local_stratum) {
|
||||
|
||||
rep->ref_id = LOCAL_REFERENCE_ID;
|
||||
rep->ref_id = NTP_REFID_LOCAL;
|
||||
rep->ip_addr.family = IPADDR_UNSPEC;
|
||||
rep->stratum = local_stratum;
|
||||
rep->ref_time = now_cooked;
|
||||
|
||||
10
reports.h
10
reports.h
@@ -112,4 +112,14 @@ typedef struct {
|
||||
int unresolved;
|
||||
} RPT_ActivityReport;
|
||||
|
||||
typedef struct {
|
||||
int active;
|
||||
int leap_only;
|
||||
double offset;
|
||||
double freq_ppm;
|
||||
double wander_ppm;
|
||||
double last_update_ago;
|
||||
double remaining_time;
|
||||
} RPT_SmoothingReport;
|
||||
|
||||
#endif /* GOT_REPORTS_H */
|
||||
|
||||
4
sched.c
4
sched.c
@@ -330,6 +330,10 @@ SCH_AddTimeoutByDelay(double delay, SCH_TimeoutHandler handler, SCH_ArbitraryArg
|
||||
|
||||
LCL_ReadRawTime(&now);
|
||||
UTI_AddDoubleToTimeval(&now, delay, &then);
|
||||
if (UTI_CompareTimevals(&now, &then) > 0) {
|
||||
LOG_FATAL(LOGF_Scheduler, "Timeout overflow");
|
||||
}
|
||||
|
||||
return SCH_AddTimeout(&then, handler, arg);
|
||||
|
||||
}
|
||||
|
||||
111
smooth.c
111
smooth.c
@@ -77,6 +77,10 @@ static struct stage stages[NUM_STAGES];
|
||||
/* Enabled/disabled smoothing */
|
||||
static int enabled;
|
||||
|
||||
/* Enabled/disabled mode where only leap seconds are smoothed out and normal
|
||||
offset/frequency changes are ignored */
|
||||
static int leap_only_mode;
|
||||
|
||||
/* Maximum skew/max_wander ratio to start updating offset and frequency */
|
||||
#define UNLOCK_SKEW_WANDER_RATIO 10000
|
||||
|
||||
@@ -93,15 +97,17 @@ static struct timeval last_update;
|
||||
|
||||
|
||||
static void
|
||||
get_offset_freq(struct timeval *now, double *offset, double *freq)
|
||||
get_smoothing(struct timeval *now, double *poffset, double *pfreq,
|
||||
double *pwander)
|
||||
{
|
||||
double elapsed, length;
|
||||
double elapsed, length, offset, freq, wander;
|
||||
int i;
|
||||
|
||||
UTI_DiffTimevalsToDouble(&elapsed, now, &last_update);
|
||||
|
||||
*offset = smooth_offset;
|
||||
*freq = smooth_freq;
|
||||
offset = smooth_offset;
|
||||
freq = smooth_freq;
|
||||
wander = 0.0;
|
||||
|
||||
for (i = 0; i < NUM_STAGES; i++) {
|
||||
if (elapsed <= 0.0)
|
||||
@@ -111,13 +117,21 @@ get_offset_freq(struct timeval *now, double *offset, double *freq)
|
||||
if (length >= elapsed)
|
||||
length = elapsed;
|
||||
|
||||
*offset -= length * (2.0 * *freq + stages[i].wander * length) / 2.0;
|
||||
*freq += stages[i].wander * length;
|
||||
wander = stages[i].wander;
|
||||
offset -= length * (2.0 * freq + wander * length) / 2.0;
|
||||
freq += wander * length;
|
||||
elapsed -= length;
|
||||
}
|
||||
|
||||
if (elapsed > 0.0)
|
||||
*offset -= elapsed * *freq;
|
||||
if (elapsed > 0.0) {
|
||||
wander = 0.0;
|
||||
offset -= elapsed * freq;
|
||||
}
|
||||
|
||||
*poffset = offset;
|
||||
*pfreq = freq;
|
||||
if (pwander)
|
||||
*pwander = wander;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -185,14 +199,12 @@ update_smoothing(struct timeval *now, double offset, double freq)
|
||||
{
|
||||
/* Don't accept offset/frequency until the clock has stabilized */
|
||||
if (locked) {
|
||||
if (REF_GetSkew() / max_wander < UNLOCK_SKEW_WANDER_RATIO) {
|
||||
LOG(LOGS_INFO, LOGF_Smooth, "Time smoothing activated");
|
||||
locked = 0;
|
||||
}
|
||||
if (REF_GetSkew() / max_wander < UNLOCK_SKEW_WANDER_RATIO || leap_only_mode)
|
||||
SMT_Activate(now);
|
||||
return;
|
||||
}
|
||||
|
||||
get_offset_freq(now, &smooth_offset, &smooth_freq);
|
||||
get_smoothing(now, &smooth_offset, &smooth_freq, NULL);
|
||||
smooth_offset += offset;
|
||||
smooth_freq = (smooth_freq - freq) / (1.0 - freq);
|
||||
last_update = *now;
|
||||
@@ -208,15 +220,19 @@ handle_slew(struct timeval *raw, struct timeval *cooked, double dfreq,
|
||||
{
|
||||
double delta;
|
||||
|
||||
if (change_type == LCL_ChangeAdjust)
|
||||
update_smoothing(cooked, doffset, dfreq);
|
||||
if (change_type == LCL_ChangeAdjust) {
|
||||
if (leap_only_mode)
|
||||
update_smoothing(cooked, 0.0, 0.0);
|
||||
else
|
||||
update_smoothing(cooked, doffset, dfreq);
|
||||
}
|
||||
|
||||
UTI_AdjustTimeval(&last_update, cooked, &last_update, &delta, dfreq, doffset);
|
||||
}
|
||||
|
||||
void SMT_Initialise(void)
|
||||
{
|
||||
CNF_GetSmooth(&max_freq, &max_wander);
|
||||
CNF_GetSmooth(&max_freq, &max_wander, &leap_only_mode);
|
||||
if (max_freq <= 0.0 || max_wander <= 0.0) {
|
||||
enabled = 0;
|
||||
return;
|
||||
@@ -249,19 +265,78 @@ SMT_GetOffset(struct timeval *now)
|
||||
if (!enabled)
|
||||
return 0.0;
|
||||
|
||||
get_offset_freq(now, &offset, &freq);
|
||||
get_smoothing(now, &offset, &freq, NULL);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
void
|
||||
SMT_Activate(struct timeval *now)
|
||||
{
|
||||
if (!enabled || !locked)
|
||||
return;
|
||||
|
||||
LOG(LOGS_INFO, LOGF_Smooth, "Time smoothing activated%s", leap_only_mode ?
|
||||
" (leap seconds only)" : "");
|
||||
locked = 0;
|
||||
last_update = *now;
|
||||
}
|
||||
|
||||
void
|
||||
SMT_Reset(struct timeval *now)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
locked = 1;
|
||||
smooth_offset = 0.0;
|
||||
smooth_freq = 0.0;
|
||||
last_update = *now;
|
||||
|
||||
for (i = 0; i < NUM_STAGES; i++)
|
||||
stages[i].wander = stages[i].length = 0.0;
|
||||
}
|
||||
|
||||
void
|
||||
SMT_Leap(struct timeval *now, int leap)
|
||||
{
|
||||
/* When the leap-only mode is disabled, the leap second will be accumulated
|
||||
in handle_slew() as a normal offset */
|
||||
if (!enabled || !leap_only_mode)
|
||||
return;
|
||||
|
||||
update_smoothing(now, leap, 0.0);
|
||||
}
|
||||
|
||||
int
|
||||
SMT_GetSmoothingReport(RPT_SmoothingReport *report, struct timeval *now)
|
||||
{
|
||||
double length, elapsed;
|
||||
int i;
|
||||
|
||||
if (!enabled)
|
||||
return 0;
|
||||
|
||||
report->active = !locked;
|
||||
report->leap_only = leap_only_mode;
|
||||
|
||||
get_smoothing(now, &report->offset, &report->freq_ppm, &report->wander_ppm);
|
||||
|
||||
/* Convert to ppm and negate (positive values mean faster/speeding up) */
|
||||
report->freq_ppm *= -1.0e6;
|
||||
report->wander_ppm *= -1.0e6;
|
||||
|
||||
UTI_DiffTimevalsToDouble(&elapsed, now, &last_update);
|
||||
if (!locked && elapsed >= 0.0) {
|
||||
for (i = 0, length = 0.0; i < NUM_STAGES; i++)
|
||||
length += stages[i].length;
|
||||
report->last_update_ago = elapsed;
|
||||
report->remaining_time = elapsed < length ? length - elapsed : 0.0;
|
||||
} else {
|
||||
report->last_update_ago = 0.0;
|
||||
report->remaining_time = 0.0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
8
smooth.h
8
smooth.h
@@ -27,6 +27,8 @@
|
||||
#ifndef GOT_SMOOTH_H
|
||||
#define GOT_SMOOTH_H
|
||||
|
||||
#include "reports.h"
|
||||
|
||||
extern void SMT_Initialise(void);
|
||||
|
||||
extern void SMT_Finalise(void);
|
||||
@@ -35,6 +37,12 @@ extern int SMT_IsEnabled(void);
|
||||
|
||||
extern double SMT_GetOffset(struct timeval *now);
|
||||
|
||||
extern void SMT_Activate(struct timeval *now);
|
||||
|
||||
extern void SMT_Reset(struct timeval *now);
|
||||
|
||||
extern void SMT_Leap(struct timeval *now, int leap);
|
||||
|
||||
extern int SMT_GetSmoothingReport(RPT_SmoothingReport *report, struct timeval *now);
|
||||
|
||||
#endif
|
||||
|
||||
58
sources.c
58
sources.c
@@ -513,7 +513,7 @@ combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
|
||||
{
|
||||
struct timeval src_ref_time;
|
||||
double src_offset, src_offset_sd, src_frequency, src_skew;
|
||||
double src_root_delay, src_root_dispersion, elapsed;
|
||||
double src_root_delay, src_root_dispersion, sel_src_distance, elapsed;
|
||||
double offset_weight, sum_offset_weight, sum_offset, sum2_offset_sd;
|
||||
double frequency_weight, sum_frequency_weight, sum_frequency, inv_sum2_skew;
|
||||
int i, index, combined;
|
||||
@@ -524,6 +524,10 @@ combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
|
||||
sum_offset_weight = sum_offset = sum2_offset_sd = 0.0;
|
||||
sum_frequency_weight = sum_frequency = inv_sum2_skew = 0.0;
|
||||
|
||||
sel_src_distance = sources[selected_source_index]->sel_info.root_distance;
|
||||
if (sources[selected_source_index]->type == SRC_NTP)
|
||||
sel_src_distance += reselect_distance;
|
||||
|
||||
for (i = combined = 0; i < n_sel_sources; i++) {
|
||||
index = sel_sources[i];
|
||||
SST_GetTrackingData(sources[index]->stats, &src_ref_time,
|
||||
@@ -536,8 +540,7 @@ combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
|
||||
are not close, or it was recently marked as distant */
|
||||
|
||||
if (index != selected_source_index &&
|
||||
(sources[index]->sel_info.root_distance > combine_limit *
|
||||
(reselect_distance + sources[selected_source_index]->sel_info.root_distance) ||
|
||||
(sources[index]->sel_info.root_distance > combine_limit * sel_src_distance ||
|
||||
fabs(*frequency - src_frequency) >
|
||||
combine_limit * (*skew + src_skew + LCL_GetMaxClockError()))) {
|
||||
/* Use a smaller penalty in first few updates */
|
||||
@@ -804,43 +807,6 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* We now have a list of indices for the sources which pass the
|
||||
false-ticker test. Now go on to reject those whose variance is
|
||||
greater than the minimum distance of any other */
|
||||
|
||||
/* Find minimum distance */
|
||||
index = sel_sources[0];
|
||||
min_distance = sources[index]->sel_info.root_distance;
|
||||
for (i = 1; i < n_sel_sources; i++) {
|
||||
index = sel_sources[i];
|
||||
distance = sources[index]->sel_info.root_distance;
|
||||
if (distance < min_distance) {
|
||||
min_distance = distance;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now go through and prune any NTP sources that have excessive
|
||||
variance */
|
||||
for (i = 0; i < n_sel_sources; i++) {
|
||||
index = sel_sources[i];
|
||||
if (sources[index]->type == SRC_NTP &&
|
||||
sqrt(sources[index]->sel_info.variance) > min_distance) {
|
||||
sel_sources[i] = INVALID_SOURCE;
|
||||
sources[index]->status = SRC_JITTERY;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now crunch the list and mark all sources as selectable */
|
||||
for (i = j = 0; i < n_sel_sources; i++) {
|
||||
index = sel_sources[i];
|
||||
if (index == INVALID_SOURCE)
|
||||
continue;
|
||||
sel_sources[j++] = index;
|
||||
}
|
||||
n_sel_sources = j;
|
||||
#endif
|
||||
|
||||
if (n_sel_sources == 0 || n_sel_sources < CNF_GetMinSources()) {
|
||||
if (selected_source_index != INVALID_SOURCE) {
|
||||
log_selection_message("Can't synchronise: %s selectable sources",
|
||||
@@ -869,16 +835,18 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
|
||||
/* If there are any sources with prefer option, reduce the list again
|
||||
only to the preferred sources */
|
||||
for (i = j = 0; i < n_sel_sources; i++) {
|
||||
for (i = 0; i < n_sel_sources; i++) {
|
||||
if (sources[sel_sources[i]]->sel_option == SRC_SelectPrefer)
|
||||
sel_sources[j++] = sel_sources[i];
|
||||
break;
|
||||
}
|
||||
|
||||
if (j > 0) {
|
||||
for (i = 0; i < n_sel_sources; i++) {
|
||||
if (i < n_sel_sources) {
|
||||
for (i = j = 0; i < n_sel_sources; i++) {
|
||||
if (sources[sel_sources[i]]->sel_option != SRC_SelectPrefer)
|
||||
sources[sel_sources[i]]->status = SRC_NONPREFERRED;
|
||||
else
|
||||
sel_sources[j++] = sel_sources[i];
|
||||
}
|
||||
assert(j > 0);
|
||||
n_sel_sources = j;
|
||||
sel_prefer = 1;
|
||||
} else {
|
||||
|
||||
12
sys.c
12
sys.c
@@ -46,6 +46,10 @@
|
||||
#include "sys_netbsd.h"
|
||||
#endif
|
||||
|
||||
#if defined (MACOSX)
|
||||
#include "sys_macosx.h"
|
||||
#endif
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
@@ -68,6 +72,10 @@ SYS_Initialise(void)
|
||||
SYS_NetBSD_Initialise();
|
||||
#endif
|
||||
|
||||
#if defined(MACOSX)
|
||||
SYS_MacOSX_Initialise();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -91,6 +99,10 @@ SYS_Finalise(void)
|
||||
#if defined(__NetBSD__)
|
||||
SYS_NetBSD_Finalise();
|
||||
#endif
|
||||
|
||||
#if defined(MACOSX)
|
||||
SYS_MacOSX_Finalise();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -107,6 +107,18 @@ handle_step(struct timeval *raw, struct timeval *cooked, double dfreq,
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static double
|
||||
clamp_freq(double freq)
|
||||
{
|
||||
if (freq > max_freq)
|
||||
return max_freq;
|
||||
if (freq < -max_freq)
|
||||
return -max_freq;
|
||||
return freq;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* End currently running slew and start a new one */
|
||||
|
||||
@@ -144,11 +156,7 @@ update_slew(void)
|
||||
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;
|
||||
total_freq = clamp_freq(base_freq + corr_freq * (1.0e6 - base_freq));
|
||||
|
||||
/* Set the new frequency (the actual frequency returned by the call may be
|
||||
slightly different from the requested frequency due to rounding) */
|
||||
@@ -330,7 +338,7 @@ SYS_Generic_Finalise(void)
|
||||
slew_timer_running = 0;
|
||||
}
|
||||
|
||||
(*drv_set_freq)(base_freq);
|
||||
(*drv_set_freq)(clamp_freq(base_freq));
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
314
sys_macosx.c
Normal file
314
sys_macosx.c
Normal file
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2001
|
||||
* Copyright (C) J. Hannken-Illjes 2001
|
||||
* Copyright (C) Bryan Christianson 2015
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Driver file for the MacOS X operating system.
|
||||
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef MACOSX
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <nlist.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "sys_macosx.h"
|
||||
#include "localp.h"
|
||||
#include "logging.h"
|
||||
#include "util.h"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* This register contains the number of seconds by which the local
|
||||
clock was estimated to be fast of reference time at the epoch when
|
||||
gettimeofday() returned T0 */
|
||||
|
||||
static double offset_register;
|
||||
|
||||
/* This register contains the epoch to which the offset is referenced */
|
||||
|
||||
static struct timeval T0;
|
||||
|
||||
/* This register contains the current estimate of the system
|
||||
frequency, in absolute (NOT ppm) */
|
||||
|
||||
static double current_freq;
|
||||
|
||||
/* This register contains the number of seconds of adjustment that
|
||||
were passed to adjtime last time it was called. */
|
||||
|
||||
static double adjustment_requested;
|
||||
|
||||
/* Kernel parameters to calculate adjtime error. */
|
||||
|
||||
static int kern_tickadj;
|
||||
static long kern_bigadj;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
clock_initialise(void)
|
||||
{
|
||||
struct timeval newadj, oldadj;
|
||||
|
||||
offset_register = 0.0;
|
||||
adjustment_requested = 0.0;
|
||||
current_freq = 0.0;
|
||||
|
||||
if (gettimeofday(&T0, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_SysMacOSX, "gettimeofday() failed");
|
||||
}
|
||||
|
||||
newadj.tv_sec = 0;
|
||||
newadj.tv_usec = 0;
|
||||
|
||||
if (adjtime(&newadj, &oldadj) < 0) {
|
||||
LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed");
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
clock_finalise(void)
|
||||
{
|
||||
/* Nothing to do yet */
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
start_adjust(void)
|
||||
{
|
||||
struct timeval newadj, oldadj;
|
||||
struct timeval T1;
|
||||
double elapsed, accrued_error;
|
||||
double adjust_required;
|
||||
struct timeval exact_newadj;
|
||||
long delta, tickdelta;
|
||||
double rounding_error;
|
||||
double old_adjust_remaining;
|
||||
|
||||
/* Determine the amount of error built up since the last adjustment */
|
||||
if (gettimeofday(&T1, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_SysMacOSX, "gettimeofday() failed");
|
||||
}
|
||||
|
||||
UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0);
|
||||
accrued_error = elapsed * current_freq;
|
||||
|
||||
adjust_required = - (accrued_error + offset_register);
|
||||
|
||||
UTI_DoubleToTimeval(adjust_required, &exact_newadj);
|
||||
|
||||
/* At this point, we need to round the required adjustment the
|
||||
same way the kernel does. */
|
||||
|
||||
delta = exact_newadj.tv_sec * 1000000 + exact_newadj.tv_usec;
|
||||
if (delta > kern_bigadj || delta < -kern_bigadj)
|
||||
tickdelta = 10 * kern_tickadj;
|
||||
else
|
||||
tickdelta = kern_tickadj;
|
||||
if (delta % tickdelta)
|
||||
delta = delta / tickdelta * tickdelta;
|
||||
newadj.tv_sec = 0;
|
||||
newadj.tv_usec = (int)delta;
|
||||
UTI_NormaliseTimeval(&newadj);
|
||||
|
||||
/* Add rounding error back onto offset register. */
|
||||
UTI_DiffTimevalsToDouble(&rounding_error, &newadj, &exact_newadj);
|
||||
|
||||
if (adjtime(&newadj, &oldadj) < 0) {
|
||||
LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed");
|
||||
}
|
||||
|
||||
UTI_TimevalToDouble(&oldadj, &old_adjust_remaining);
|
||||
|
||||
offset_register = rounding_error - old_adjust_remaining;
|
||||
|
||||
T0 = T1;
|
||||
UTI_TimevalToDouble(&newadj, &adjustment_requested);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
stop_adjust(void)
|
||||
{
|
||||
struct timeval T1;
|
||||
struct timeval zeroadj, remadj;
|
||||
double adjustment_remaining, adjustment_achieved;
|
||||
double elapsed, elapsed_plus_adjust;
|
||||
|
||||
zeroadj.tv_sec = 0;
|
||||
zeroadj.tv_usec = 0;
|
||||
|
||||
if (adjtime(&zeroadj, &remadj) < 0) {
|
||||
LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed");
|
||||
}
|
||||
|
||||
if (gettimeofday(&T1, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_SysMacOSX, "gettimeofday() failed");
|
||||
}
|
||||
|
||||
UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0);
|
||||
UTI_TimevalToDouble(&remadj, &adjustment_remaining);
|
||||
|
||||
adjustment_achieved = adjustment_requested - adjustment_remaining;
|
||||
elapsed_plus_adjust = elapsed - adjustment_achieved;
|
||||
|
||||
offset_register += current_freq * elapsed_plus_adjust - adjustment_remaining;
|
||||
|
||||
adjustment_requested = 0.0;
|
||||
T0 = T1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Positive offset means system clock is fast of true time, therefore
|
||||
slew backwards */
|
||||
|
||||
static void
|
||||
accrue_offset(double offset, double corr_rate)
|
||||
{
|
||||
stop_adjust();
|
||||
offset_register += offset;
|
||||
start_adjust();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Positive offset means system clock is fast of true time, therefore
|
||||
step backwards */
|
||||
|
||||
static int
|
||||
apply_step_offset(double offset)
|
||||
{
|
||||
struct timeval old_time, new_time, T1;
|
||||
|
||||
stop_adjust();
|
||||
|
||||
if (gettimeofday(&old_time, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_SysMacOSX, "gettimeofday() failed");
|
||||
}
|
||||
|
||||
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
|
||||
|
||||
if (settimeofday(&new_time, NULL) < 0) {
|
||||
DEBUG_LOG(LOGF_SysMacOSX, "settimeofday() failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
UTI_AddDoubleToTimeval(&T0, offset, &T1);
|
||||
T0 = T1;
|
||||
|
||||
start_adjust();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static double
|
||||
set_frequency(double new_freq_ppm)
|
||||
{
|
||||
stop_adjust();
|
||||
current_freq = new_freq_ppm * 1.0e-6;
|
||||
start_adjust();
|
||||
|
||||
return current_freq * 1.0e6;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static double
|
||||
read_frequency(void)
|
||||
{
|
||||
return current_freq * 1.0e6;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
get_offset_correction(struct timeval *raw,
|
||||
double *corr, double *err)
|
||||
{
|
||||
stop_adjust();
|
||||
*corr = -offset_register;
|
||||
start_adjust();
|
||||
if (err)
|
||||
*err = 0.0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SYS_MacOSX_Initialise(void)
|
||||
{
|
||||
int result;
|
||||
size_t len;
|
||||
struct clockinfo clockinfo;
|
||||
int mib[2];
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_CLOCKRATE;
|
||||
|
||||
len = sizeof(clockinfo);
|
||||
result = sysctl(mib, 2, &clockinfo, &len, NULL, 0);
|
||||
|
||||
if(result < 0) {
|
||||
LOG_FATAL(LOGF_SysMacOSX, "Cannot read clockinfo");
|
||||
}
|
||||
kern_tickadj = clockinfo.tickadj;
|
||||
kern_bigadj = clockinfo.tick;
|
||||
|
||||
clock_initialise();
|
||||
|
||||
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
|
||||
accrue_offset, apply_step_offset,
|
||||
get_offset_correction,
|
||||
NULL /* set_leap */,
|
||||
NULL /* set_sync_status */);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SYS_MacOSX_Finalise(void)
|
||||
{
|
||||
clock_finalise();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#endif
|
||||
37
sys_macosx.h
Normal file
37
sys_macosx.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2001
|
||||
* Copyright (C) J. Hannken-Illjes 2001
|
||||
* Copyright (C) Bryan Christianson 2015
|
||||
*
|
||||
* 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 MacOS X driver
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GOT_SYS_MACOSX_H
|
||||
#define GOT_SYS_MACOSX_H
|
||||
|
||||
void SYS_MacOSX_Initialise(void);
|
||||
|
||||
void SYS_MacOSX_Finalise(void);
|
||||
|
||||
#endif
|
||||
@@ -29,9 +29,9 @@
|
||||
#ifndef GOT_SYSINCL_H
|
||||
#define GOT_SYSINCL_H
|
||||
|
||||
#if defined (SOLARIS) || defined(SUNOS) || defined(LINUX) || defined(__NetBSD__)
|
||||
#if defined (SOLARIS) || defined(SUNOS) || defined(LINUX) || defined(__NetBSD__) || defined (MACOSX)
|
||||
|
||||
#if !defined(__NetBSD__) && !defined(__FreeBSD__)
|
||||
#if !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(MACOSX)
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
@@ -39,7 +39,7 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <float.h>
|
||||
#if !defined(__FreeBSD__)
|
||||
#if !defined(__FreeBSD__) && !defined(MACOSX)
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#include <math.h>
|
||||
|
||||
@@ -27,18 +27,20 @@ for leapmode in system step slew; do
|
||||
check_sync || test_fail
|
||||
done
|
||||
|
||||
server_conf="refclock SHM 0 dpoll 10 poll 10
|
||||
leapsectz right/UTC
|
||||
leapsecmode slew
|
||||
smoothtime 400 0.001"
|
||||
client_conf="leapsecmode system"
|
||||
min_sync_time=230000
|
||||
max_sync_time=240000
|
||||
for smoothmode in "" "leaponly"; do
|
||||
server_conf="refclock SHM 0 dpoll 10 poll 10
|
||||
leapsectz right/UTC
|
||||
leapsecmode slew
|
||||
smoothtime 400 0.001 $smoothmode"
|
||||
client_conf="leapsecmode system"
|
||||
min_sync_time=230000
|
||||
max_sync_time=240000
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_packet_interval || test_fail
|
||||
check_sync || test_fail
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_packet_interval || test_fail
|
||||
check_sync || test_fail
|
||||
done
|
||||
|
||||
test_pass
|
||||
|
||||
21
test/simulation/202-prefer
Executable file
21
test/simulation/202-prefer
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
. test.common
|
||||
|
||||
# Test fix in commit 4253075a97141edfa62043ab71bd0673587e6629
|
||||
|
||||
test_start "prefer option"
|
||||
|
||||
servers=3
|
||||
client_server_conf="
|
||||
server 192.168.123.1
|
||||
server 192.168.123.2
|
||||
server 192.168.123.3 prefer"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_packet_interval || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
test_pass
|
||||
@@ -18,7 +18,7 @@ export PATH=../../:$PATH
|
||||
export CLKNETSIM_PATH=clknetsim
|
||||
|
||||
# Known working clknetsim revision
|
||||
clknetsim_revision=3eb3a8d9acf60c31f5acc66617175fc748ef367e
|
||||
clknetsim_revision=1e56224dee1db69c0027e9bd63c2a202d4765959
|
||||
clknetsim_url=https://github.com/mlichvar/clknetsim/archive/$clknetsim_revision.tar.gz
|
||||
|
||||
# Only Linux is supported
|
||||
@@ -65,6 +65,7 @@ default_chronyc_start=1000.0
|
||||
default_server_step=""
|
||||
default_client_step=""
|
||||
|
||||
default_client_server_conf=""
|
||||
default_server_server_options=""
|
||||
default_client_server_options=""
|
||||
default_server_peer_options=""
|
||||
@@ -192,9 +193,13 @@ get_chronyd_conf() {
|
||||
done
|
||||
echo "$server_conf"
|
||||
else
|
||||
for i in $(seq 1 $servers); do
|
||||
echo "server 192.168.123.$[$servers * ($stratum - 2) + $i] $client_server_options"
|
||||
done
|
||||
if [ -n "$client_server_conf" ]; then
|
||||
echo "$client_server_conf"
|
||||
else
|
||||
for i in $(seq 1 $servers); do
|
||||
echo "server 192.168.123.$[$servers * ($stratum - 2) + $i] $client_server_options"
|
||||
done
|
||||
fi
|
||||
for i in $(seq 1 $peers); do
|
||||
[ $i -eq $peer -o $i -gt $clients ] && continue
|
||||
echo "peer 192.168.123.$[$servers * ($stratum - 1) + $i] $client_peer_options"
|
||||
|
||||
29
util.c
29
util.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2009, 2012-2013
|
||||
* Copyright (C) Miroslav Lichvar 2009, 2012-2015
|
||||
*
|
||||
* 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
|
||||
@@ -609,6 +609,9 @@ UTI_Int64ToTimeval(NTP_int64 *src,
|
||||
/* Maximum offset between two sane times */
|
||||
#define MAX_OFFSET 4294967296.0
|
||||
|
||||
/* Minimum allowed distance from maximum 32-bit time_t */
|
||||
#define MIN_ENDOFTIME_DISTANCE (365 * 24 * 3600)
|
||||
|
||||
int
|
||||
UTI_IsTimeOffsetSane(struct timeval *tv, double offset)
|
||||
{
|
||||
@@ -629,6 +632,10 @@ UTI_IsTimeOffsetSane(struct timeval *tv, double offset)
|
||||
/* Check if it's in the interval to which NTP time is mapped */
|
||||
if (t < (double)NTP_ERA_SPLIT || t > (double)(NTP_ERA_SPLIT + (1LL << 32)))
|
||||
return 0;
|
||||
#else
|
||||
/* Don't get too close to 32-bit time_t overflow */
|
||||
if (t > (double)(0x7fffffff - MIN_ENDOFTIME_DISTANCE))
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
@@ -636,6 +643,22 @@ UTI_IsTimeOffsetSane(struct timeval *tv, double offset)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
double
|
||||
UTI_Log2ToDouble(int l)
|
||||
{
|
||||
if (l >= 0) {
|
||||
if (l > 31)
|
||||
l = 31;
|
||||
return 1 << l;
|
||||
} else {
|
||||
if (l < -31)
|
||||
l = -31;
|
||||
return 1.0 / (1 << -l);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
UTI_TimevalNetworkToHost(Timeval *src, struct timeval *dest)
|
||||
{
|
||||
@@ -700,7 +723,11 @@ UTI_FloatHostToNetwork(double x)
|
||||
if (x < 0.0) {
|
||||
x = -x;
|
||||
neg = 1;
|
||||
} else if (x >= 0.0) {
|
||||
neg = 0;
|
||||
} else {
|
||||
/* Save NaN as zero */
|
||||
x = 0.0;
|
||||
neg = 0;
|
||||
}
|
||||
|
||||
|
||||
3
util.h
3
util.h
@@ -107,6 +107,9 @@ extern void UTI_Int64ToTimeval(NTP_int64 *src, struct timeval *dest);
|
||||
/* Check if time + offset is sane */
|
||||
extern int UTI_IsTimeOffsetSane(struct timeval *tv, double offset);
|
||||
|
||||
/* Get 2 raised to power of a signed integer */
|
||||
extern double UTI_Log2ToDouble(int l);
|
||||
|
||||
extern void UTI_TimevalNetworkToHost(Timeval *src, struct timeval *dest);
|
||||
extern void UTI_TimevalHostToNetwork(struct timeval *src, Timeval *dest);
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ TMX_ResetOffset(void)
|
||||
|
||||
/* Set status back */
|
||||
txc.modes = ADJ_STATUS;
|
||||
txc.modes = status;
|
||||
txc.status = status;
|
||||
if (adjtimex(&txc) < 0)
|
||||
return -1;
|
||||
|
||||
@@ -193,12 +193,12 @@ TMX_ApplyStepOffset(double offset)
|
||||
struct timex txc;
|
||||
|
||||
txc.modes = ADJ_SETOFFSET | ADJ_NANO;
|
||||
if (offset >= 0) {
|
||||
txc.time.tv_sec = offset;
|
||||
} else {
|
||||
txc.time.tv_sec = offset - 1;
|
||||
}
|
||||
txc.time.tv_sec = offset;
|
||||
txc.time.tv_usec = 1.0e9 * (offset - txc.time.tv_sec);
|
||||
if (txc.time.tv_usec < 0) {
|
||||
txc.time.tv_sec--;
|
||||
txc.time.tv_usec += 1000000000;
|
||||
}
|
||||
|
||||
return adjtimex(&txc);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user