mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-03 21:35:06 -05:00
Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
074dac4195 | ||
|
|
a8239b865a | ||
|
|
f6a9c5c1b7 | ||
|
|
42774ee851 | ||
|
|
4e26f48781 | ||
|
|
aec97397e8 | ||
|
|
183a648d01 | ||
|
|
27f8ad7fd1 | ||
|
|
a79fbef21e | ||
|
|
565976acbe | ||
|
|
54bbd2b1c0 | ||
|
|
10b2b53aa7 | ||
|
|
e18ee0bb46 | ||
|
|
857d51ea8e | ||
|
|
ba85544611 | ||
|
|
293806d52d | ||
|
|
7f45eb7957 | ||
|
|
f0c48680fe | ||
|
|
78283dd822 | ||
|
|
bbdf708d1a | ||
|
|
08195d7e41 | ||
|
|
9ff0dbb7a4 | ||
|
|
6ba97f9161 | ||
|
|
4eca60e7dc | ||
|
|
2af6f8cf78 | ||
|
|
d9a84d24cf | ||
|
|
09ce631e21 | ||
|
|
f93f2a15af | ||
|
|
47839b7701 | ||
|
|
41e99afe54 | ||
|
|
80af04040a | ||
|
|
3caa1e2f71 | ||
|
|
ddbbe30b9e | ||
|
|
802a98e7fc | ||
|
|
bb21841659 | ||
|
|
3f9691baff | ||
|
|
f8db832491 | ||
|
|
c68a92ba80 | ||
|
|
e5cf4645fe | ||
|
|
fad97e12da | ||
|
|
2f6152a580 |
@@ -40,7 +40,7 @@ HASH_OBJ = @HASH_OBJ@
|
||||
|
||||
OBJS = array.o cmdparse.o conf.o local.o logging.o main.o memory.o mkdirpp.o \
|
||||
reference.o regress.o rtc.o sched.o sources.o sourcestats.o stubs.o \
|
||||
sys.o tempcomp.o util.o $(HASH_OBJ)
|
||||
sys.o smooth.o tempcomp.o util.o $(HASH_OBJ)
|
||||
|
||||
EXTRA_OBJS=@EXTRA_OBJECTS@
|
||||
|
||||
|
||||
20
NEWS
20
NEWS
@@ -5,6 +5,8 @@ Enhancements
|
||||
------------
|
||||
* Update to NTP version 4 (RFC 5905)
|
||||
* Add pool directive to specify pool of NTP servers
|
||||
* Add leapsecmode directive to select how to correct clock for leap second
|
||||
* Add smoothtime directive to smooth served time and enable leap smear
|
||||
* Add minsources directive to set required number of selectable sources
|
||||
* Add minsamples and maxsamples options for all sources
|
||||
* Add tempcomp configuration with list of points
|
||||
@@ -15,6 +17,7 @@ Enhancements
|
||||
* Open NTP server port only when necessary (client access is allowed by
|
||||
allow directive/command, peer or broadcast is configured)
|
||||
* Change default bindcmdaddress to loopback address
|
||||
* Change default maxdelay to 3 seconds
|
||||
* Change default stratumweight to 0.001
|
||||
* Update adjtimex synchronisation status
|
||||
* Use system headers for adjtimex
|
||||
@@ -25,9 +28,20 @@ Enhancements
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix accepting requests from configured sources when acquisitionport
|
||||
is equal to server port
|
||||
* Fix allocation of slots saving replies to authenticated commands
|
||||
* Add sanity checks for time and frequency offset
|
||||
* Don't report synchronised status during leap second
|
||||
* Fix accepting requests from configured sources
|
||||
* Fix initial fallback drift setting
|
||||
|
||||
New in version 1.31.1
|
||||
=====================
|
||||
|
||||
Security fixes
|
||||
--------------
|
||||
* Protect authenticated symmetric NTP associations against DoS attacks
|
||||
(CVE-2015-1799)
|
||||
* Fix access configuration with subnet size indivisible by 4 (CVE-2015-1821)
|
||||
* Fix initialization of reply slots for authenticated commands (CVE-2015-1822)
|
||||
|
||||
New in version 1.31
|
||||
===================
|
||||
|
||||
@@ -199,7 +199,10 @@ set_subnet(TableNode *start_node,
|
||||
|
||||
/* How many subnet entries to set : 1->8, 2->4, 3->2 */
|
||||
N = 1 << (NBITS-bits_to_go);
|
||||
subnet = get_subnet(ip, bits_consumed);
|
||||
|
||||
subnet = get_subnet(ip, bits_consumed) & ~(N - 1);
|
||||
assert(subnet + N <= TABLE_SIZE);
|
||||
|
||||
if (!(node->extended)) {
|
||||
open_node(node);
|
||||
}
|
||||
|
||||
11
candm.h
11
candm.h
@@ -300,11 +300,6 @@ typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_CycleLogs;
|
||||
|
||||
typedef struct {
|
||||
IPAddr ip;
|
||||
uint32_t bits_specd;
|
||||
} REQ_SubnetsAccessed_Subnet;
|
||||
|
||||
/* This is based on the response size rather than the
|
||||
request size */
|
||||
#define MAX_CLIENT_ACCESSES 8
|
||||
@@ -589,12 +584,6 @@ typedef struct {
|
||||
int32_t EOR;
|
||||
} RPY_ManualTimestamp;
|
||||
|
||||
typedef struct {
|
||||
IPAddr ip;
|
||||
uint32_t bits_specd;
|
||||
uint32_t bitmap[8];
|
||||
} RPY_SubnetsAccessed_Subnet;
|
||||
|
||||
typedef struct {
|
||||
IPAddr ip;
|
||||
uint32_t client_hits;
|
||||
|
||||
115
chrony.texi.in
115
chrony.texi.in
@@ -1158,6 +1158,7 @@ the configuration file is ignored.
|
||||
* include directive:: Include a configuration file
|
||||
* initstepslew directive:: Trim the system clock on boot-up
|
||||
* keyfile directive:: Specify location of file containing keys
|
||||
* leapsecmode directive:: Select leap second handling mode
|
||||
* leapsectz directive:: Read leap second data from tz database
|
||||
* local directive:: Allow unsynchronised machine to act as server
|
||||
* lock_all directive:: Require that chronyd be locked into RAM
|
||||
@@ -1189,6 +1190,7 @@ the configuration file is ignored.
|
||||
* rtcsync directive:: Specify that RTC should be automatically synchronised by kernel
|
||||
* sched_priority directive:: Require real-time scheduling and specify a priority for it
|
||||
* server directive:: Specify an NTP server
|
||||
* smoothtime directive:: Smooth served time to keep clients close together
|
||||
* stratumweight directive:: Specify how important is stratum when selecting source
|
||||
* tempcomp directive:: Specify temperature sensor and compensation coefficients
|
||||
* user directive:: Specify user for dropping root privileges
|
||||
@@ -1636,14 +1638,13 @@ the program exits. (See the dumpdir command above).
|
||||
@subsection fallbackdrift
|
||||
Fallback drifts are long-term averages of the system clock drift
|
||||
calculated over exponentially increasing intervals. They are used
|
||||
when the clock is unsynchronised to avoid quickly drifting away from
|
||||
true time if there was a short-term deviation in drift before the
|
||||
synchronisation was lost.
|
||||
when the clock is no longer synchronised to avoid quickly drifting
|
||||
away from true time if there was a short-term deviation in the drift
|
||||
before the synchronisation was lost.
|
||||
|
||||
The directive specifies the minimum and maximum interval for how long
|
||||
the system clock has to be unsynchronised to switch between fallback
|
||||
drifts. They are defined as a power of 2 (in seconds). The syntax is
|
||||
as follows
|
||||
The directive specifies the minimum and maximum interval since last
|
||||
clock update to switch between fallback drifts. They are defined as a
|
||||
power of 2 (in seconds). The syntax is as follows
|
||||
|
||||
@example
|
||||
fallbackdrift 16 19
|
||||
@@ -1651,13 +1652,13 @@ fallbackdrift 16 19
|
||||
|
||||
In this example, the minimum interval is 16 (18 hours) and maximum
|
||||
interval is 19 (6 days). The system clock frequency will be set to
|
||||
the first fallback 18 hours after the synchronisation was lost, to the
|
||||
the first fallback 18 hours after last clock update, to the
|
||||
second after 36 hours, etc. This might be a good setting to cover
|
||||
daily and weekly temperature fluctuations.
|
||||
|
||||
By default (or if the specified maximum or minimum is 0), no fallbacks
|
||||
will be used and the clock frequency will stay at the last value
|
||||
calculated before synchronisation was lost.
|
||||
are used and the clock frequency changes only with new measurements from
|
||||
NTP, reference clocks or manual input.
|
||||
@c }}}
|
||||
@c {{{ generatecommandkey
|
||||
@node generatecommandkey directive
|
||||
@@ -1808,6 +1809,62 @@ The ID for the chronyc authentication key is specified with the commandkey
|
||||
command (see earlier). The command key can be generated automatically on
|
||||
start with the @code{generatecommandkey} directive.
|
||||
@c }}}
|
||||
@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.
|
||||
|
||||
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).
|
||||
@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.
|
||||
@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.
|
||||
@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
|
||||
estimated offset includes the one second error.
|
||||
@end table
|
||||
|
||||
An example of the command is
|
||||
|
||||
@example
|
||||
leapsecmode slew
|
||||
@end example
|
||||
|
||||
An example enabling the leap smear for NTP clients with the @code{smoothtime}
|
||||
directive could be
|
||||
|
||||
@example
|
||||
leapsecmode slew
|
||||
smoothtime 400 0.001
|
||||
@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.
|
||||
@c }}}
|
||||
@c {{{ leapsectz
|
||||
@node leapsectz directive
|
||||
@subsection leapsectz
|
||||
@@ -2873,7 +2930,7 @@ If the user knows that round trip delays above a certain level should
|
||||
cause the measurement to be ignored, this level can be defined with the
|
||||
maxdelay command. For example, @code{maxdelay 0.3} would indicate that
|
||||
measurements with a round-trip delay of 0.3 seconds or more should be
|
||||
ignored.
|
||||
ignored. The default value is 3 seconds.
|
||||
|
||||
@item maxdelayratio
|
||||
This option is similar to the maxdelay option above. @code{chronyd}
|
||||
@@ -2981,6 +3038,42 @@ Set the maximum number of samples kept for this source. This overrides the
|
||||
|
||||
@end table
|
||||
@c }}}
|
||||
@c {{{ smoothtime
|
||||
@node smoothtime directive
|
||||
@subsection smoothtime
|
||||
The @code{smoothtime} directive can be used to enable smoothing of the time
|
||||
that @code{chronyd} serves to its clients to make it easier for them to track
|
||||
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.
|
||||
|
||||
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 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).
|
||||
|
||||
An example suitable for clients using @code{ntpd} and 1024 second polling
|
||||
interval could be
|
||||
|
||||
@example
|
||||
smoothtime 400 0.001
|
||||
@end example
|
||||
|
||||
An example suitable for clients using @code{chronyd} on Linux could be
|
||||
|
||||
@example
|
||||
smoothtime 50000 0.01
|
||||
@end example
|
||||
@c }}}
|
||||
@c {{{ stratumweight
|
||||
@node stratumweight directive
|
||||
@subsection stratumweight
|
||||
|
||||
30
cmdmon.c
30
cmdmon.c
@@ -926,14 +926,16 @@ handle_settime(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
long offset_cs;
|
||||
double dfreq_ppm, new_afreq_ppm;
|
||||
UTI_TimevalNetworkToHost(&rx_message->data.settime.ts, &ts);
|
||||
if (MNL_AcceptTimestamp(&ts, &offset_cs, &dfreq_ppm, &new_afreq_ppm)) {
|
||||
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);
|
||||
tx_message->data.manual_timestamp.new_afreq_ppm = UTI_FloatHostToNetwork(new_afreq_ppm);
|
||||
} else {
|
||||
tx_message->status = htons(STT_NOTENABLED);
|
||||
tx_message->status = htons(STT_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1051,7 +1053,7 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
tx_message->data.source_data.flags = htons(RPY_SD_FLAG_PREFER);
|
||||
break;
|
||||
case RPT_NOSELECT:
|
||||
tx_message->data.source_data.flags = htons(RPY_SD_FLAG_PREFER);
|
||||
tx_message->data.source_data.flags = htons(RPY_SD_FLAG_NOSELECT);
|
||||
break;
|
||||
}
|
||||
tx_message->data.source_data.reachability = htons(report.reachability);
|
||||
@@ -1463,7 +1465,7 @@ handle_client_accesses_by_index(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
CLG_Status result;
|
||||
RPT_ClientAccessByIndex_Report report;
|
||||
unsigned long first_index, n_indices, last_index, n_indices_in_table;
|
||||
unsigned long first_index, n_indices, n_indices_in_table;
|
||||
int i, j;
|
||||
struct timeval now;
|
||||
|
||||
@@ -1471,16 +1473,15 @@ handle_client_accesses_by_index(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
|
||||
first_index = ntohl(rx_message->data.client_accesses_by_index.first_index);
|
||||
n_indices = ntohl(rx_message->data.client_accesses_by_index.n_indices);
|
||||
last_index = first_index + n_indices - 1;
|
||||
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 = first_index, j = 0;
|
||||
(i <= last_index) && (j < MAX_CLIENT_ACCESSES);
|
||||
i++) {
|
||||
|
||||
result = CLG_GetClientAccessReportByIndex(i, &report, now.tv_sec, &n_indices_in_table);
|
||||
for (i = 0, j = 0; i < n_indices; i++) {
|
||||
result = CLG_GetClientAccessReportByIndex(first_index + i, &report,
|
||||
now.tv_sec, &n_indices_in_table);
|
||||
tx_message->data.client_accesses_by_index.n_indices = htonl(n_indices_in_table);
|
||||
|
||||
switch (result) {
|
||||
@@ -1506,7 +1507,7 @@ handle_client_accesses_by_index(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
}
|
||||
}
|
||||
|
||||
tx_message->data.client_accesses_by_index.next_index = htonl(i);
|
||||
tx_message->data.client_accesses_by_index.next_index = htonl(first_index + i);
|
||||
tx_message->data.client_accesses_by_index.n_clients = htonl(j);
|
||||
}
|
||||
|
||||
@@ -1556,8 +1557,11 @@ handle_manual_delete(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
static void
|
||||
handle_make_step(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
LCL_MakeStep();
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
if (!LCL_MakeStep()) {
|
||||
tx_message->status = htons(STT_FAILED);
|
||||
} else {
|
||||
tx_message->status = htons(STT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
58
conf.c
58
conf.c
@@ -63,6 +63,7 @@ static void parse_deny(char *);
|
||||
static void parse_fallbackdrift(char *);
|
||||
static void parse_include(char *);
|
||||
static void parse_initstepslew(char *);
|
||||
static void parse_leapsecmode(char *);
|
||||
static void parse_local(char *);
|
||||
static void parse_log(char *);
|
||||
static void parse_mailonchange(char *);
|
||||
@@ -72,6 +73,7 @@ static void parse_peer(char *);
|
||||
static void parse_pool(char *);
|
||||
static void parse_refclock(char *);
|
||||
static void parse_server(char *);
|
||||
static void parse_smoothtime(char *);
|
||||
static void parse_tempcomp(char *);
|
||||
|
||||
/* ================================================== */
|
||||
@@ -184,6 +186,10 @@ static IPAddr bind_cmd_address4, bind_cmd_address6;
|
||||
* chronyds being started. */
|
||||
static char *pidfile;
|
||||
|
||||
/* Smoothing constants */
|
||||
static double smooth_max_freq = 0.0; /* in ppm */
|
||||
static double smooth_max_wander = 0.0; /* in ppm/s */
|
||||
|
||||
/* Temperature sensor, update interval and compensation coefficients */
|
||||
static char *tempcomp_sensor_file = NULL;
|
||||
static char *tempcomp_point_file = NULL;
|
||||
@@ -193,6 +199,9 @@ static double tempcomp_T0, tempcomp_k0, tempcomp_k1, tempcomp_k2;
|
||||
static int sched_priority = 0;
|
||||
static int lock_memory = 0;
|
||||
|
||||
/* Leap second handling mode */
|
||||
static REF_LeapMode leapsec_mode = REF_LeapModeSystem;
|
||||
|
||||
/* Name of a system timezone containing leap seconds occuring at midnight */
|
||||
static char *leapsec_tz = NULL;
|
||||
|
||||
@@ -440,6 +449,8 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
parse_initstepslew(p);
|
||||
} else if (!strcasecmp(command, "keyfile")) {
|
||||
parse_string(p, &keys_file);
|
||||
} else if (!strcasecmp(command, "leapsecmode")) {
|
||||
parse_leapsecmode(p);
|
||||
} else if (!strcasecmp(command, "leapsectz")) {
|
||||
parse_string(p, &leapsec_tz);
|
||||
} else if (!strcasecmp(command, "linux_freq_scale")) {
|
||||
@@ -506,6 +517,8 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
parse_int(p, &sched_priority);
|
||||
} else if (!strcasecmp(command, "server")) {
|
||||
parse_server(p);
|
||||
} else if (!strcasecmp(command, "smoothtime")) {
|
||||
parse_smoothtime(p);
|
||||
} else if (!strcasecmp(command, "stratumweight")) {
|
||||
parse_double(p, &stratum_weight);
|
||||
} else if (!strcasecmp(command, "tempcomp")) {
|
||||
@@ -830,6 +843,23 @@ parse_initstepslew(char *line)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
parse_leapsecmode(char *line)
|
||||
{
|
||||
if (!strcasecmp(line, "system"))
|
||||
leapsec_mode = REF_LeapModeSystem;
|
||||
else if (!strcasecmp(line, "slew"))
|
||||
leapsec_mode = REF_LeapModeSlew;
|
||||
else if (!strcasecmp(line, "step"))
|
||||
leapsec_mode = REF_LeapModeStep;
|
||||
else if (!strcasecmp(line, "ignore"))
|
||||
leapsec_mode = REF_LeapModeIgnore;
|
||||
else
|
||||
command_parse_error();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
parse_clientloglimit(char *line)
|
||||
{
|
||||
@@ -1141,6 +1171,17 @@ parse_broadcast(char *line)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
parse_smoothtime(char *line)
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
static void
|
||||
parse_tempcomp(char *line)
|
||||
{
|
||||
@@ -1664,6 +1705,14 @@ CNF_GetPidFile(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
REF_LeapMode
|
||||
CNF_GetLeapSecMode(void)
|
||||
{
|
||||
return leapsec_mode;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
char *
|
||||
CNF_GetLeapSecTimezone(void)
|
||||
{
|
||||
@@ -1688,6 +1737,15 @@ CNF_GetLockMemory(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
CNF_GetSmooth(double *max_freq, double *max_wander)
|
||||
{
|
||||
*max_freq = smooth_max_freq;
|
||||
*max_wander = smooth_max_wander;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
CNF_GetTempComp(char **file, double *interval, char **point_file, double *T0, double *k0, double *k1, double *k2)
|
||||
{
|
||||
|
||||
3
conf.h
3
conf.h
@@ -29,6 +29,7 @@
|
||||
#define GOT_CONF_H
|
||||
|
||||
#include "addressing.h"
|
||||
#include "reference.h"
|
||||
|
||||
extern void CNF_Initialise(int restarted);
|
||||
extern void CNF_Finalise(void);
|
||||
@@ -75,6 +76,7 @@ extern void CNF_GetBindAddress(int family, IPAddr *addr);
|
||||
extern void CNF_GetBindAcquisitionAddress(int family, IPAddr *addr);
|
||||
extern void CNF_GetBindCommandAddress(int family, IPAddr *addr);
|
||||
extern char *CNF_GetPidFile(void);
|
||||
extern REF_LeapMode CNF_GetLeapSecMode(void);
|
||||
extern char *CNF_GetLeapSecTimezone(void);
|
||||
|
||||
/* Value returned in ppm, as read from file */
|
||||
@@ -94,6 +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_GetTempComp(char **file, double *interval, char **point_file, double *T0, double *k0, double *k1, double *k2);
|
||||
|
||||
extern char *CNF_GetUser(void);
|
||||
|
||||
89
local.c
89
local.c
@@ -36,11 +36,16 @@
|
||||
#include "local.h"
|
||||
#include "localp.h"
|
||||
#include "memory.h"
|
||||
#include "smooth.h"
|
||||
#include "util.h"
|
||||
#include "logging.h"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Maximum allowed frequency offset in ppm, the time must not stop
|
||||
or run backwards */
|
||||
#define MAX_FREQ 500000.0
|
||||
|
||||
/* Variable to store the current frequency, in ppm */
|
||||
static double current_freq_ppm;
|
||||
|
||||
@@ -397,6 +402,33 @@ LCL_ReadAbsoluteFrequency(void)
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static double
|
||||
clamp_freq(double freq)
|
||||
{
|
||||
if (freq <= MAX_FREQ && freq >= -MAX_FREQ)
|
||||
return freq;
|
||||
|
||||
LOG(LOGS_WARN, LOGF_Local, "Frequency %.1f ppm exceeds allowed maximum", freq);
|
||||
|
||||
return freq >= MAX_FREQ ? MAX_FREQ : -MAX_FREQ;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
check_offset(struct timeval *now, double offset)
|
||||
{
|
||||
/* Check if the time will be still sane with accumulated offset */
|
||||
if (UTI_IsTimeOffsetSane(now, -offset))
|
||||
return 1;
|
||||
|
||||
LOG(LOGS_WARN, LOGF_Local, "Adjustment of %.1f seconds is invalid", -offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* This involves both setting the absolute frequency with the
|
||||
system-specific driver, as well as calling all notify handlers */
|
||||
|
||||
@@ -406,6 +438,8 @@ LCL_SetAbsoluteFrequency(double afreq_ppm)
|
||||
struct timeval raw, cooked;
|
||||
double dfreq;
|
||||
|
||||
afreq_ppm = clamp_freq(afreq_ppm);
|
||||
|
||||
/* Apply temperature compensation */
|
||||
if (temp_comp_ppm != 0.0) {
|
||||
afreq_ppm = afreq_ppm * (1.0 - 1.0e-6 * temp_comp_ppm) - temp_comp_ppm;
|
||||
@@ -443,6 +477,8 @@ LCL_AccumulateDeltaFrequency(double dfreq)
|
||||
|
||||
current_freq_ppm += dfreq * (1.0e6 - current_freq_ppm);
|
||||
|
||||
current_freq_ppm = clamp_freq(current_freq_ppm);
|
||||
|
||||
/* Call the system-specific driver for setting the frequency */
|
||||
current_freq_ppm = (*drv_set_freq)(current_freq_ppm);
|
||||
dfreq = (current_freq_ppm - old_freq_ppm) / (1.0e6 - old_freq_ppm);
|
||||
@@ -467,6 +503,9 @@ LCL_AccumulateOffset(double offset, double corr_rate)
|
||||
LCL_ReadRawTime(&raw);
|
||||
LCL_CookTime(&raw, &cooked, NULL);
|
||||
|
||||
if (!check_offset(&cooked, offset))
|
||||
return;
|
||||
|
||||
(*drv_accrue_offset)(offset, corr_rate);
|
||||
|
||||
/* Dispatch to all handlers */
|
||||
@@ -475,7 +514,7 @@ LCL_AccumulateOffset(double offset, double corr_rate)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
int
|
||||
LCL_ApplyStepOffset(double offset)
|
||||
{
|
||||
struct timeval raw, cooked;
|
||||
@@ -486,10 +525,21 @@ LCL_ApplyStepOffset(double offset)
|
||||
LCL_ReadRawTime(&raw);
|
||||
LCL_CookTime(&raw, &cooked, NULL);
|
||||
|
||||
(*drv_apply_step_offset)(offset);
|
||||
if (!check_offset(&raw, offset))
|
||||
return 0;
|
||||
|
||||
if (!(*drv_apply_step_offset)(offset)) {
|
||||
LOG(LOGS_ERR, LOGF_Local, "Could not step clock");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reset smoothing on all clock steps */
|
||||
SMT_Reset(&cooked);
|
||||
|
||||
/* Dispatch to all handlers */
|
||||
invoke_parameter_change_handlers(&raw, &cooked, 0.0, offset, LCL_ChangeStep);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -506,6 +556,20 @@ LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked,
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LCL_NotifyLeap(int leap)
|
||||
{
|
||||
struct timeval raw, cooked;
|
||||
|
||||
LCL_ReadRawTime(&raw);
|
||||
LCL_CookTime(&raw, &cooked, NULL);
|
||||
|
||||
/* Dispatch to all handlers as if the clock was stepped */
|
||||
invoke_parameter_change_handlers(&raw, &cooked, 0.0, -leap, LCL_ChangeStep);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
|
||||
{
|
||||
@@ -517,6 +581,9 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
|
||||
to the change we are about to make */
|
||||
LCL_CookTime(&raw, &cooked, NULL);
|
||||
|
||||
if (!check_offset(&cooked, doffset))
|
||||
return;
|
||||
|
||||
old_freq_ppm = current_freq_ppm;
|
||||
|
||||
/* Work out new absolute frequency. Note that absolute frequencies
|
||||
@@ -524,6 +591,8 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
|
||||
terms of the gradient of the (offset) v (local time) function. */
|
||||
current_freq_ppm += dfreq * (1.0e6 - current_freq_ppm);
|
||||
|
||||
current_freq_ppm = clamp_freq(current_freq_ppm);
|
||||
|
||||
DEBUG_LOG(LOGF_Local, "old_freq=%.3fppm new_freq=%.3fppm offset=%.6fsec",
|
||||
old_freq_ppm, current_freq_ppm, doffset);
|
||||
|
||||
@@ -587,9 +656,13 @@ LCL_MakeStep(void)
|
||||
LCL_ReadRawTime(&raw);
|
||||
LCL_GetOffsetCorrection(&raw, &correction, NULL);
|
||||
|
||||
if (!check_offset(&raw, -correction))
|
||||
return 0;
|
||||
|
||||
/* Cancel remaining slew and make the step */
|
||||
LCL_AccumulateOffset(correction, 0.0);
|
||||
LCL_ApplyStepOffset(-correction);
|
||||
if (!LCL_ApplyStepOffset(-correction))
|
||||
return 0;
|
||||
|
||||
LOG(LOGS_WARN, LOGF_Local, "System clock was stepped by %.6f seconds", correction);
|
||||
|
||||
@@ -598,8 +671,16 @@ LCL_MakeStep(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
LCL_CanSystemLeap(void)
|
||||
{
|
||||
return drv_set_leap ? 1 : 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LCL_SetLeap(int leap)
|
||||
LCL_SetSystemLeap(int leap)
|
||||
{
|
||||
if (drv_set_leap) {
|
||||
(drv_set_leap)(leap);
|
||||
|
||||
18
local.h
18
local.h
@@ -159,13 +159,17 @@ extern void LCL_AccumulateOffset(double offset, double corr_rate);
|
||||
the system clock is fast on true time, i.e. it needs to be stepped
|
||||
backwards. (Same convention as for AccumulateOffset routine). */
|
||||
|
||||
extern void LCL_ApplyStepOffset(double offset);
|
||||
extern int LCL_ApplyStepOffset(double offset);
|
||||
|
||||
/* Routine to invoke notify handlers on an unexpected time jump
|
||||
in system clock */
|
||||
extern void LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked,
|
||||
double offset, double dispersion);
|
||||
|
||||
/* Routine to invoke notify handlers on leap second when the system clock
|
||||
doesn't correct itself */
|
||||
extern void LCL_NotifyLeap(int leap);
|
||||
|
||||
/* Perform the combination of modifying the frequency and applying
|
||||
a slew, in one easy step */
|
||||
extern void LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate);
|
||||
@@ -194,10 +198,14 @@ extern void LCL_Finalise(void);
|
||||
to a timezone problem. */
|
||||
extern int LCL_MakeStep(void);
|
||||
|
||||
/* Routine to schedule a leap second. Leap second will be inserted
|
||||
at the end of the day if argument is positive, deleted if negative,
|
||||
and zero cancels scheduled leap second. */
|
||||
extern void LCL_SetLeap(int leap);
|
||||
/* Check if the system driver supports leap seconds, i.e. LCL_SetSystemLeap
|
||||
does something */
|
||||
extern int LCL_CanSystemLeap(void);
|
||||
|
||||
/* Routine to set the system clock to correct itself for a leap second if
|
||||
supported. Leap second will be inserted at the end of the day if the
|
||||
argument is positive, deleted if negative, and zero resets the setting. */
|
||||
extern void LCL_SetSystemLeap(int leap);
|
||||
|
||||
/* Routine to set a frequency correction (in ppm) that should be applied
|
||||
to local clock to compensate for temperature changes. A positive
|
||||
|
||||
2
localp.h
2
localp.h
@@ -47,7 +47,7 @@ typedef void (*lcl_AccrueOffsetDriver)(double offset, double corr_rate);
|
||||
|
||||
/* System driver to apply a step offset. A positive argument means step
|
||||
the clock forwards. */
|
||||
typedef void (*lcl_ApplyStepOffsetDriver)(double offset);
|
||||
typedef int (*lcl_ApplyStepOffsetDriver)(double offset);
|
||||
|
||||
/* System driver to convert a raw time to an adjusted (cooked) time.
|
||||
The number of seconds returned in 'corr' have to be added to the
|
||||
|
||||
@@ -100,7 +100,8 @@ typedef enum {
|
||||
LOGF_SysWinnt,
|
||||
LOGF_TempComp,
|
||||
LOGF_RtcLinux,
|
||||
LOGF_Refclock
|
||||
LOGF_Refclock,
|
||||
LOGF_Smooth,
|
||||
} LOG_Facility;
|
||||
|
||||
/* Init function */
|
||||
|
||||
3
main.c
3
main.c
@@ -49,6 +49,7 @@
|
||||
#include "refclock.h"
|
||||
#include "clientlog.h"
|
||||
#include "nameserv.h"
|
||||
#include "smooth.h"
|
||||
#include "tempcomp.h"
|
||||
|
||||
/* ================================================== */
|
||||
@@ -88,6 +89,7 @@ MAI_CleanupAndExit(void)
|
||||
/* Don't update clock when removing sources */
|
||||
REF_SetMode(REF_ModeIgnore);
|
||||
|
||||
SMT_Finalise();
|
||||
TMC_Finalise();
|
||||
MNL_Finalise();
|
||||
CLG_Finalise();
|
||||
@@ -495,6 +497,7 @@ int main
|
||||
CLG_Initialise();
|
||||
MNL_Initialise();
|
||||
TMC_Initialise();
|
||||
SMT_Initialise();
|
||||
|
||||
/* From now on, it is safe to do finalisation on exit */
|
||||
initialised = 1;
|
||||
|
||||
26
manual.c
26
manual.c
@@ -54,6 +54,8 @@ typedef struct {
|
||||
(measured-predicted)) */
|
||||
} Sample;
|
||||
|
||||
#define MIN_SAMPLE_SEPARATION 1.0
|
||||
|
||||
#define MAX_SAMPLES 16
|
||||
|
||||
static Sample samples[16];
|
||||
@@ -174,14 +176,24 @@ int
|
||||
MNL_AcceptTimestamp(struct timeval *ts, long *offset_cs, double *dfreq_ppm, double *new_afreq_ppm)
|
||||
{
|
||||
struct timeval now;
|
||||
double offset;
|
||||
double offset, diff;
|
||||
int i;
|
||||
|
||||
if (enabled) {
|
||||
|
||||
/* Check whether timestamp is within margin of old one */
|
||||
LCL_ReadCookedTime(&now, NULL);
|
||||
|
||||
/* Make sure the provided timestamp is sane and the sample
|
||||
is not too close to the last one */
|
||||
|
||||
if (!UTI_IsTimeOffsetSane(ts, 0.0))
|
||||
return 0;
|
||||
|
||||
if (n_samples) {
|
||||
UTI_DiffTimevalsToDouble(&diff, &now, &samples[n_samples - 1].when);
|
||||
if (diff < MIN_SAMPLE_SEPARATION)
|
||||
return 0;
|
||||
}
|
||||
|
||||
UTI_DiffTimevalsToDouble(&offset, &now, ts);
|
||||
|
||||
/* Check if buffer full up */
|
||||
@@ -258,6 +270,14 @@ MNL_Reset(void)
|
||||
n_samples = 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
MNL_IsEnabled(void)
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Generate report data for the REQ_MANUAL_LIST command/monitoring
|
||||
protocol */
|
||||
|
||||
1
manual.h
1
manual.h
@@ -38,6 +38,7 @@ extern int MNL_AcceptTimestamp(struct timeval *ts, long *offset_cs, double *dfre
|
||||
extern void MNL_Enable(void);
|
||||
extern void MNL_Disable(void);
|
||||
extern void MNL_Reset(void);
|
||||
extern int MNL_IsEnabled(void);
|
||||
|
||||
extern void MNL_ReportSamples(RPT_ManualSamplesReport *report, int max, int *n);
|
||||
extern int MNL_DeleteSample(int index);
|
||||
|
||||
60
ntp_core.c
60
ntp_core.c
@@ -36,6 +36,7 @@
|
||||
#include "sched.h"
|
||||
#include "reference.h"
|
||||
#include "local.h"
|
||||
#include "smooth.h"
|
||||
#include "sources.h"
|
||||
#include "util.h"
|
||||
#include "conf.h"
|
||||
@@ -216,8 +217,9 @@ static ARR_Instance broadcasts;
|
||||
/* Invalid stratum number */
|
||||
#define NTP_INVALID_STRATUM 0
|
||||
|
||||
/* Minimum allowed poll interval */
|
||||
/* Minimum and maximum allowed poll interval */
|
||||
#define MIN_POLL 0
|
||||
#define MAX_POLL 24
|
||||
|
||||
/* Kiss-o'-Death codes */
|
||||
#define KOD_RATE 0x52415445UL /* RATE */
|
||||
@@ -444,9 +446,13 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
|
||||
result->minpoll = params->minpoll;
|
||||
if (result->minpoll < MIN_POLL)
|
||||
result->minpoll = SRC_DEFAULT_MINPOLL;
|
||||
else if (result->minpoll > MAX_POLL)
|
||||
result->minpoll = MAX_POLL;
|
||||
result->maxpoll = params->maxpoll;
|
||||
if (result->maxpoll < MIN_POLL)
|
||||
result->maxpoll = SRC_DEFAULT_MAXPOLL;
|
||||
else if (result->maxpoll > MAX_POLL)
|
||||
result->maxpoll = MAX_POLL;
|
||||
if (result->maxpoll < result->minpoll)
|
||||
result->maxpoll = result->minpoll;
|
||||
|
||||
@@ -757,14 +763,14 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||
{
|
||||
NTP_Packet message;
|
||||
int leap, auth_len, length, ret;
|
||||
struct timeval local_transmit;
|
||||
struct timeval local_receive, local_transmit;
|
||||
|
||||
/* Parameters read from reference module */
|
||||
int are_we_synchronised, our_stratum;
|
||||
int are_we_synchronised, our_stratum, smooth_time;
|
||||
NTP_Leap leap_status;
|
||||
uint32_t our_ref_id, ts_fuzz;
|
||||
struct timeval our_ref_time;
|
||||
double our_root_delay, our_root_dispersion;
|
||||
double our_root_delay, our_root_dispersion, smooth_offset;
|
||||
|
||||
/* Don't reply with version higher than ours */
|
||||
if (version > NTP_VERSION) {
|
||||
@@ -781,6 +787,20 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||
&our_ref_id, &our_ref_time,
|
||||
&our_root_delay, &our_root_dispersion);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Suppress leap second when smoothing and slew mode are enabled */
|
||||
if (REF_GetLeapMode() == REF_LeapModeSlew &&
|
||||
(leap_status == LEAP_InsertSecond || leap_status == LEAP_DeleteSecond))
|
||||
leap_status = LEAP_Normal;
|
||||
} else {
|
||||
smooth_time = 0;
|
||||
smooth_offset = 0.0;
|
||||
}
|
||||
|
||||
if (are_we_synchronised) {
|
||||
leap = (int) leap_status;
|
||||
} else {
|
||||
@@ -807,6 +827,14 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||
message.reference_id = htonl((NTP_int32) 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 */
|
||||
@@ -816,7 +844,7 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||
This timestamp will have been adjusted so that it will now look to
|
||||
the source like we have been running on our latest estimate of
|
||||
frequency all along */
|
||||
UTI_TimevalToInt64(local_rx, &message.receive_ts, 0);
|
||||
UTI_TimevalToInt64(&local_receive, &message.receive_ts, 0);
|
||||
|
||||
/* Prepare random bits which will be added to the transmit timestamp. */
|
||||
ts_fuzz = UTI_GetNTPTsFuzz(message.precision);
|
||||
@@ -826,6 +854,9 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||
from the source we're sending to now. */
|
||||
LCL_ReadCookedTime(&local_transmit, NULL);
|
||||
|
||||
if (smooth_time)
|
||||
UTI_AddDoubleToTimeval(&local_transmit, smooth_offset, &local_transmit);
|
||||
|
||||
length = NTP_NORMAL_PACKET_LENGTH;
|
||||
|
||||
/* Authenticate */
|
||||
@@ -1151,6 +1182,7 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
|
||||
association if not properly 'up'. */
|
||||
test3 = (message->originate_ts.hi || message->originate_ts.lo) &&
|
||||
(message->receive_ts.hi || message->receive_ts.lo) &&
|
||||
(message->reference_ts.hi || message->reference_ts.lo) &&
|
||||
(message->transmit_ts.hi || message->transmit_ts.lo);
|
||||
|
||||
/* Test 4 would check for denied access. It would always pass as this
|
||||
@@ -1185,11 +1217,13 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
|
||||
kod_rate = 1;
|
||||
}
|
||||
|
||||
/* Regardless of any validity checks we apply, we are required to
|
||||
save these fields from the packet into the ntp source instance record.
|
||||
Note we can't do this assignment before test 1 has been carried out. */
|
||||
inst->remote_orig = message->transmit_ts;
|
||||
inst->local_rx = *now;
|
||||
/* The transmit timestamp and local receive timestamp must not be saved when
|
||||
the authentication test failed to prevent denial-of-service attacks on
|
||||
symmetric associations using authentication */
|
||||
if (test5) {
|
||||
inst->remote_orig = message->transmit_ts;
|
||||
inst->local_rx = *now;
|
||||
}
|
||||
|
||||
/* This protects against replay of the last packet we sent */
|
||||
if (test2)
|
||||
@@ -1243,7 +1277,7 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
|
||||
minimum one currently in the stats data register is less than an
|
||||
administrator-defined value */
|
||||
testB = inst->max_delay_ratio <= 1.0 ||
|
||||
delay / SRC_MinRoundTripDelay(inst->source) > inst->max_delay_ratio;
|
||||
delay / SRC_MinRoundTripDelay(inst->source) <= inst->max_delay_ratio;
|
||||
|
||||
/* Test C requires that the ratio of the increase in delay from the minimum
|
||||
one in the stats data register to the standard deviation of the offsets
|
||||
@@ -1707,7 +1741,7 @@ NCR_TakeSourceOffline(NCR_Instance inst)
|
||||
void
|
||||
NCR_ModifyMinpoll(NCR_Instance inst, int new_minpoll)
|
||||
{
|
||||
if (new_minpoll < MIN_POLL)
|
||||
if (new_minpoll < MIN_POLL || new_minpoll > MAX_POLL)
|
||||
return;
|
||||
inst->minpoll = new_minpoll;
|
||||
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new minpoll %d", UTI_IPToString(&inst->remote_addr.ip_addr), new_minpoll);
|
||||
@@ -1720,7 +1754,7 @@ NCR_ModifyMinpoll(NCR_Instance inst, int new_minpoll)
|
||||
void
|
||||
NCR_ModifyMaxpoll(NCR_Instance inst, int new_maxpoll)
|
||||
{
|
||||
if (new_maxpoll < MIN_POLL)
|
||||
if (new_maxpoll < MIN_POLL || new_maxpoll > MAX_POLL)
|
||||
return;
|
||||
inst->maxpoll = new_maxpoll;
|
||||
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new maxpoll %d", UTI_IPToString(&inst->remote_addr.ip_addr), new_maxpoll);
|
||||
|
||||
@@ -226,7 +226,7 @@ RCL_AddRefclock(RefclockParameters *params)
|
||||
inst->ref_id = params->ref_id;
|
||||
else {
|
||||
unsigned char ref[5] = { 0, 0, 0, 0, 0 };
|
||||
unsigned int index = ARR_GetSize(refclocks);
|
||||
unsigned int index = ARR_GetSize(refclocks) - 1;
|
||||
|
||||
snprintf((char *)ref, sizeof (ref), "%3.3s", params->driver_name);
|
||||
ref[3] = index % 10 + '0';
|
||||
@@ -367,7 +367,9 @@ RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset,
|
||||
UTI_AddDoubleToTimeval(sample_time, correction, &cooked_time);
|
||||
dispersion += instance->precision;
|
||||
|
||||
if (!valid_sample_time(instance, sample_time))
|
||||
/* Make sure the timestamp and offset provided by the driver are sane */
|
||||
if (!UTI_IsTimeOffsetSane(sample_time, offset) ||
|
||||
!valid_sample_time(instance, sample_time))
|
||||
return 0;
|
||||
|
||||
filter_add_sample(&instance->filter, &cooked_time, offset - correction + instance->offset, dispersion);
|
||||
@@ -407,7 +409,8 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
|
||||
UTI_AddDoubleToTimeval(pulse_time, correction, &cooked_time);
|
||||
dispersion += instance->precision;
|
||||
|
||||
if (!valid_sample_time(instance, pulse_time))
|
||||
if (!UTI_IsTimeOffsetSane(pulse_time, 0.0) ||
|
||||
!valid_sample_time(instance, pulse_time))
|
||||
return 0;
|
||||
|
||||
rate = instance->pps_rate;
|
||||
|
||||
172
reference.c
172
reference.c
@@ -50,7 +50,7 @@ static int our_leap_sec;
|
||||
static int our_stratum;
|
||||
static uint32_t our_ref_id;
|
||||
static IPAddr our_ref_ip;
|
||||
struct timeval our_ref_time; /* Stored relative to reference, NOT local time */
|
||||
struct timeval our_ref_time;
|
||||
static double our_skew;
|
||||
static double our_residual_freq;
|
||||
static double our_root_delay;
|
||||
@@ -98,6 +98,17 @@ static double drift_file_age;
|
||||
|
||||
static void update_drift_file(double, double);
|
||||
|
||||
/* Leap second handling mode */
|
||||
static REF_LeapMode leap_mode;
|
||||
|
||||
/* Flag indicating the clock was recently corrected for leap second and it may
|
||||
not have correct time yet (missing 23:59:60 in the UTC time scale) */
|
||||
static int leap_in_progress;
|
||||
|
||||
/* Timer for the leap second handler */
|
||||
static int leap_timer_running;
|
||||
static SCH_TimeoutID leap_timeout_id;
|
||||
|
||||
/* Name of a system timezone containing leap seconds occuring at midnight */
|
||||
static char *leap_tzname;
|
||||
static time_t last_tz_leap_check;
|
||||
@@ -136,6 +147,7 @@ static double last_ref_update_interval;
|
||||
/* ================================================== */
|
||||
|
||||
static NTP_Leap get_tz_leap(time_t when);
|
||||
static void update_leap_status(NTP_Leap leap, time_t now, int reset);
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -148,6 +160,9 @@ handle_slew(struct timeval *raw,
|
||||
void *anything)
|
||||
{
|
||||
double delta;
|
||||
struct timeval now;
|
||||
|
||||
UTI_AdjustTimeval(&our_ref_time, cooked, &our_ref_time, &delta, dfreq, doffset);
|
||||
|
||||
if (change_type == LCL_ChangeUnknownStep) {
|
||||
last_ref_update.tv_sec = 0;
|
||||
@@ -155,6 +170,13 @@ handle_slew(struct timeval *raw,
|
||||
} else if (last_ref_update.tv_sec) {
|
||||
UTI_AdjustTimeval(&last_ref_update, cooked, &last_ref_update, &delta, dfreq, doffset);
|
||||
}
|
||||
|
||||
/* When the clock was stepped, check if that doesn't change our leap status
|
||||
and also reset the leap timeout to undo the shift in the scheduler */
|
||||
if (change_type != LCL_ChangeAdjust && our_leap_sec && !leap_in_progress) {
|
||||
LCL_ReadRawTime(&now);
|
||||
update_leap_status(our_leap_status, now.tv_sec, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -217,6 +239,13 @@ REF_Initialise(void)
|
||||
|
||||
enable_local_stratum = CNF_AllowLocalReference(&local_stratum);
|
||||
|
||||
leap_timer_running = 0;
|
||||
leap_in_progress = 0;
|
||||
leap_mode = CNF_GetLeapSecMode();
|
||||
/* Switch to step mode if the system driver doesn't support leap */
|
||||
if (leap_mode == REF_LeapModeSystem && !LCL_CanSystemLeap())
|
||||
leap_mode = REF_LeapModeStep;
|
||||
|
||||
leap_tzname = CNF_GetLeapSecTimezone();
|
||||
if (leap_tzname) {
|
||||
/* Check that the timezone has good data for Jun 30 2008 and Dec 31 2008 */
|
||||
@@ -263,9 +292,7 @@ REF_Initialise(void)
|
||||
void
|
||||
REF_Finalise(void)
|
||||
{
|
||||
if (our_leap_sec) {
|
||||
LCL_SetLeap(0);
|
||||
}
|
||||
update_leap_status(LEAP_Unsynchronised, 0, 0);
|
||||
|
||||
if (drift_file) {
|
||||
update_drift_file(LCL_ReadAbsoluteFrequency(), our_skew);
|
||||
@@ -301,6 +328,14 @@ REF_SetModeEndHandler(REF_ModeEndHandler handler)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
REF_LeapMode
|
||||
REF_GetLeapMode(void)
|
||||
{
|
||||
return leap_mode;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static double
|
||||
Sqr(double x)
|
||||
{
|
||||
@@ -403,14 +438,10 @@ update_fb_drifts(double freq_ppm, double update_interval)
|
||||
fb_drift_timeout_id = -1;
|
||||
}
|
||||
|
||||
if (update_interval < 0.0 || update_interval > last_ref_update_interval * 4.0)
|
||||
if (update_interval < 1.0 || update_interval > last_ref_update_interval * 4.0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < fb_drift_max - fb_drift_min + 1; i++) {
|
||||
/* Don't allow differences larger than 10 ppm */
|
||||
if (fabs(freq_ppm - fb_drifts[i].freq) > 10.0)
|
||||
fb_drifts[i].secs = 0.0;
|
||||
|
||||
secs = 1 << (i + fb_drift_min);
|
||||
if (fb_drifts[i].secs < secs) {
|
||||
/* Calculate average over 2 * secs interval before switching to
|
||||
@@ -436,11 +467,12 @@ update_fb_drifts(double freq_ppm, double update_interval)
|
||||
static void
|
||||
fb_drift_timeout(void *arg)
|
||||
{
|
||||
assert(are_we_synchronised == 0);
|
||||
assert(next_fb_drift >= fb_drift_min && next_fb_drift <= fb_drift_max);
|
||||
|
||||
fb_drift_timeout_id = -1;
|
||||
|
||||
DEBUG_LOG(LOGF_Reference, "Fallback drift %d active: %f ppm",
|
||||
next_fb_drift, fb_drifts[next_fb_drift - fb_drift_min].freq);
|
||||
LCL_SetAbsoluteFrequency(fb_drifts[next_fb_drift - fb_drift_min].freq);
|
||||
REF_SetUnsynchronised();
|
||||
}
|
||||
@@ -657,7 +689,89 @@ get_tz_leap(time_t when)
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
update_leap_status(NTP_Leap leap, time_t now)
|
||||
leap_end_timeout(void *arg)
|
||||
{
|
||||
leap_timer_running = 0;
|
||||
leap_in_progress = 0;
|
||||
our_leap_sec = 0;
|
||||
|
||||
if (leap_mode == REF_LeapModeSystem)
|
||||
LCL_SetSystemLeap(0);
|
||||
|
||||
if (our_leap_status == LEAP_InsertSecond ||
|
||||
our_leap_status == LEAP_DeleteSecond)
|
||||
our_leap_status = LEAP_Normal;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
leap_start_timeout(void *arg)
|
||||
{
|
||||
leap_in_progress = 1;
|
||||
|
||||
switch (leap_mode) {
|
||||
case REF_LeapModeSystem:
|
||||
DEBUG_LOG(LOGF_Reference, "Waiting for system clock leap second correction");
|
||||
break;
|
||||
case REF_LeapModeSlew:
|
||||
LCL_NotifyLeap(our_leap_sec);
|
||||
LCL_AccumulateOffset(our_leap_sec, 0.0);
|
||||
LOG(LOGS_WARN, LOGF_Reference, "Adjusting system clock for leap second");
|
||||
break;
|
||||
case REF_LeapModeStep:
|
||||
LCL_NotifyLeap(our_leap_sec);
|
||||
LCL_ApplyStepOffset(our_leap_sec);
|
||||
LOG(LOGS_WARN, LOGF_Reference, "System clock was stepped for leap second");
|
||||
break;
|
||||
case REF_LeapModeIgnore:
|
||||
LOG(LOGS_WARN, LOGF_Reference, "Ignoring leap second");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Wait until the leap second is over with some extra room to be safe */
|
||||
leap_timeout_id = SCH_AddTimeoutByDelay(2.0, leap_end_timeout, NULL);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
set_leap_timeout(time_t now)
|
||||
{
|
||||
struct timeval when;
|
||||
|
||||
/* Stop old timer if there is one */
|
||||
if (leap_timer_running) {
|
||||
SCH_RemoveTimeout(leap_timeout_id);
|
||||
leap_timer_running = 0;
|
||||
leap_in_progress = 0;
|
||||
}
|
||||
|
||||
if (!our_leap_sec)
|
||||
return;
|
||||
|
||||
/* Insert leap second at 0:00:00 UTC, delete at 23:59:59 UTC. If the clock
|
||||
will be corrected by the system, timeout slightly sooner to be sure it
|
||||
will happen before the system correction. */
|
||||
when.tv_sec = (now / (24 * 3600) + 1) * (24 * 3600);
|
||||
when.tv_usec = 0;
|
||||
if (our_leap_sec < 0)
|
||||
when.tv_sec--;
|
||||
if (leap_mode == REF_LeapModeSystem) {
|
||||
when.tv_sec--;
|
||||
when.tv_usec = 500000;
|
||||
}
|
||||
|
||||
leap_timeout_id = SCH_AddTimeout(&when, leap_start_timeout, NULL);
|
||||
leap_timer_running = 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
update_leap_status(NTP_Leap leap, time_t now, int reset)
|
||||
{
|
||||
int leap_sec;
|
||||
|
||||
@@ -680,9 +794,22 @@ update_leap_status(NTP_Leap leap, time_t now)
|
||||
}
|
||||
}
|
||||
|
||||
if (leap_sec != our_leap_sec && !REF_IsLeapSecondClose()) {
|
||||
LCL_SetLeap(leap_sec);
|
||||
if (reset || (leap_sec != our_leap_sec && !REF_IsLeapSecondClose())) {
|
||||
our_leap_sec = leap_sec;
|
||||
|
||||
switch (leap_mode) {
|
||||
case REF_LeapModeSystem:
|
||||
LCL_SetSystemLeap(our_leap_sec);
|
||||
/* Fall through */
|
||||
case REF_LeapModeSlew:
|
||||
case REF_LeapModeStep:
|
||||
case REF_LeapModeIgnore:
|
||||
set_leap_timeout(now);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
our_leap_status = leap;
|
||||
@@ -920,12 +1047,12 @@ REF_SetReference(int stratum,
|
||||
our_residual_freq = frequency;
|
||||
}
|
||||
|
||||
update_leap_status(leap, raw_now.tv_sec);
|
||||
update_leap_status(leap, raw_now.tv_sec, 0);
|
||||
maybe_log_offset(our_offset, raw_now.tv_sec);
|
||||
|
||||
if (step_offset != 0.0) {
|
||||
LCL_ApplyStepOffset(step_offset);
|
||||
LOG(LOGS_WARN, LOGF_Reference, "System clock was stepped by %.6f seconds", -step_offset);
|
||||
if (LCL_ApplyStepOffset(step_offset))
|
||||
LOG(LOGS_WARN, LOGF_Reference, "System clock was stepped by %.6f seconds", -step_offset);
|
||||
}
|
||||
|
||||
LCL_SetSyncStatus(are_we_synchronised, offset_sd, offset_sd + root_delay / 2.0 + root_dispersion);
|
||||
@@ -955,6 +1082,7 @@ REF_SetReference(int stratum,
|
||||
/* Update fallback drifts */
|
||||
if (fb_drifts) {
|
||||
update_fb_drifts(abs_freq_ppm, update_interval);
|
||||
schedule_fb_drift(&now);
|
||||
}
|
||||
|
||||
last_ref_update_interval = update_interval;
|
||||
@@ -1015,7 +1143,7 @@ REF_SetUnsynchronised(void)
|
||||
schedule_fb_drift(&now);
|
||||
}
|
||||
|
||||
update_leap_status(LEAP_Unsynchronised, 0);
|
||||
update_leap_status(LEAP_Unsynchronised, 0, 0);
|
||||
are_we_synchronised = 0;
|
||||
|
||||
LCL_SetSyncStatus(0, 0.0, 0.0);
|
||||
@@ -1061,7 +1189,7 @@ REF_GetReferenceParams
|
||||
UTI_DiffTimevalsToDouble(&elapsed, local_time, &our_ref_time);
|
||||
extra_dispersion = (our_skew + fabs(our_residual_freq) + LCL_GetMaxClockError()) * elapsed;
|
||||
|
||||
*leap_status = our_leap_status;
|
||||
*leap_status = !leap_in_progress ? our_leap_status : LEAP_Unsynchronised;
|
||||
*ref_id = our_ref_id;
|
||||
*ref_time = our_ref_time;
|
||||
*root_delay = our_root_delay;
|
||||
@@ -1121,6 +1249,14 @@ REF_GetOurStratum(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
double
|
||||
REF_GetSkew(void)
|
||||
{
|
||||
return our_skew;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
REF_ModifyMaxupdateskew(double new_max_update_skew)
|
||||
{
|
||||
|
||||
14
reference.h
14
reference.h
@@ -35,6 +35,14 @@
|
||||
#include "ntp.h"
|
||||
#include "reports.h"
|
||||
|
||||
/* Leap second handling modes */
|
||||
typedef enum {
|
||||
REF_LeapModeSystem,
|
||||
REF_LeapModeSlew,
|
||||
REF_LeapModeStep,
|
||||
REF_LeapModeIgnore,
|
||||
} REF_LeapMode;
|
||||
|
||||
/* Init function */
|
||||
extern void REF_Initialise(void);
|
||||
|
||||
@@ -61,6 +69,9 @@ typedef void (*REF_ModeEndHandler)(int result);
|
||||
/* Set the handler for being notified of mode ending */
|
||||
extern void REF_SetModeEndHandler(REF_ModeEndHandler handler);
|
||||
|
||||
/* Get leap second handling mode */
|
||||
extern REF_LeapMode REF_GetLeapMode(void);
|
||||
|
||||
/* Function which takes a local cooked time and returns the estimated
|
||||
time of the reference. It also returns the other parameters
|
||||
required for forming the outgoing NTP packet.
|
||||
@@ -154,6 +165,9 @@ REF_SetUnsynchronised(void);
|
||||
synchronised */
|
||||
extern int REF_GetOurStratum(void);
|
||||
|
||||
/* Return the current skew */
|
||||
extern double REF_GetSkew(void);
|
||||
|
||||
/* Modify the setting for the maximum skew we are prepared to allow updates on (in ppm). */
|
||||
extern void REF_ModifyMaxupdateskew(double new_max_update_skew);
|
||||
|
||||
|
||||
6
rtc.c
6
rtc.c
@@ -93,9 +93,9 @@ fallback_time_init(void)
|
||||
LCL_ReadCookedTime(&now, NULL);
|
||||
|
||||
if (now.tv_sec < buf.st_mtime) {
|
||||
LCL_ApplyStepOffset(now.tv_sec - buf.st_mtime);
|
||||
LOG(LOGS_INFO, LOGF_Rtc,
|
||||
"System clock set from driftfile %s", drift_file);
|
||||
if (LCL_ApplyStepOffset(now.tv_sec - buf.st_mtime))
|
||||
LOG(LOGS_INFO, LOGF_Rtc, "System clock set from driftfile %s",
|
||||
drift_file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1043,9 +1043,9 @@ RTC_Linux_TimePreInit(void)
|
||||
|
||||
/* Set system time only if the step is larger than 1 second */
|
||||
if (fabs(sys_offset) >= 1.0) {
|
||||
LOG(LOGS_INFO, LOGF_RtcLinux, "Set system time, error in RTC = %f",
|
||||
accumulated_error);
|
||||
LCL_ApplyStepOffset(sys_offset);
|
||||
if (LCL_ApplyStepOffset(sys_offset))
|
||||
LOG(LOGS_INFO, LOGF_RtcLinux, "Set system time, error in RTC = %f",
|
||||
accumulated_error);
|
||||
}
|
||||
} else {
|
||||
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not convert RTC reading to seconds since 1/1/1970");
|
||||
|
||||
267
smooth.c
Normal file
267
smooth.c
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 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.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Routines implementing time smoothing.
|
||||
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "conf.h"
|
||||
#include "local.h"
|
||||
#include "logging.h"
|
||||
#include "reference.h"
|
||||
#include "smooth.h"
|
||||
#include "util.h"
|
||||
|
||||
/*
|
||||
Time smoothing determines an offset that needs to be applied to the cooked
|
||||
time to make it smooth for external observers. Observed offset and frequency
|
||||
change slowly and there are no discontinuities. This can be used on an NTP
|
||||
server to make it easier for the clients to track the time and keep their
|
||||
clocks close together even when large offset or frequency corrections are
|
||||
applied to the server's clock (e.g. after being offline for longer time).
|
||||
|
||||
Accumulated offset and frequency are smoothed out in three stages. In the
|
||||
first stage, the frequency is changed at a constant rate (wander) up to a
|
||||
maximum, in the second stage the frequency stays at the maximum for as long
|
||||
as needed and in the third stage the frequency is brought back to zero.
|
||||
|
||||
|
|
||||
max_freq +-------/--------\-------------
|
||||
| /| |\
|
||||
freq | / | | \
|
||||
| / | | \
|
||||
| / | | \
|
||||
0 +--/----+--------+----\--------
|
||||
| / | | | time
|
||||
|/ | | |
|
||||
|
||||
stage 1 2 3
|
||||
|
||||
Integral of this function is the smoothed out offset. It's a continuous
|
||||
piecewise polynomial with two quadratic parts and one linear.
|
||||
*/
|
||||
|
||||
struct stage {
|
||||
double wander;
|
||||
double length;
|
||||
};
|
||||
|
||||
#define NUM_STAGES 3
|
||||
|
||||
static struct stage stages[NUM_STAGES];
|
||||
|
||||
/* Enabled/disabled smoothing */
|
||||
static int enabled;
|
||||
|
||||
/* Maximum skew/max_wander ratio to start updating offset and frequency */
|
||||
#define UNLOCK_SKEW_WANDER_RATIO 10000
|
||||
|
||||
static int locked;
|
||||
|
||||
/* Maximum wander and frequency offset */
|
||||
static double max_wander;
|
||||
static double max_freq;
|
||||
|
||||
/* Frequency offset, time offset and the time of the last smoothing update */
|
||||
static double smooth_freq;
|
||||
static double smooth_offset;
|
||||
static struct timeval last_update;
|
||||
|
||||
|
||||
static void
|
||||
get_offset_freq(struct timeval *now, double *offset, double *freq)
|
||||
{
|
||||
double elapsed, length;
|
||||
int i;
|
||||
|
||||
UTI_DiffTimevalsToDouble(&elapsed, now, &last_update);
|
||||
|
||||
*offset = smooth_offset;
|
||||
*freq = smooth_freq;
|
||||
|
||||
for (i = 0; i < NUM_STAGES; i++) {
|
||||
if (elapsed <= 0.0)
|
||||
break;
|
||||
|
||||
length = stages[i].length;
|
||||
if (length >= elapsed)
|
||||
length = elapsed;
|
||||
|
||||
*offset -= length * (2.0 * *freq + stages[i].wander * length) / 2.0;
|
||||
*freq += stages[i].wander * length;
|
||||
elapsed -= length;
|
||||
}
|
||||
|
||||
if (elapsed > 0.0)
|
||||
*offset -= elapsed * *freq;
|
||||
}
|
||||
|
||||
static void
|
||||
update_stages(void)
|
||||
{
|
||||
double s1, s2, s, l1, l2, l3, lc, f, f2;
|
||||
int i, dir;
|
||||
|
||||
/* Prepare the three stages so that the integral of the frequency offset
|
||||
is equal to the offset that should be smoothed out */
|
||||
|
||||
s1 = smooth_offset / max_wander;
|
||||
s2 = smooth_freq * smooth_freq / (2.0 * max_wander * max_wander);
|
||||
|
||||
l1 = l2 = l3 = 0.0;
|
||||
|
||||
/* Calculate the lengths of the 1st and 3rd stage assuming there is no
|
||||
frequency limit. If length of the 1st stage comes out negative, switch
|
||||
its direction. */
|
||||
for (dir = -1; dir <= 1; dir += 2) {
|
||||
s = dir * s1 + s2;
|
||||
if (s >= 0.0) {
|
||||
l3 = sqrt(s);
|
||||
l1 = l3 - dir * smooth_freq / max_wander;
|
||||
if (l1 >= 0.0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(dir <= 1 && l1 >= 0.0 && l3 >= 0.0);
|
||||
|
||||
/* If the limit was reached, shorten 1st+3rd stages and set a 2nd stage */
|
||||
f = dir * smooth_freq + l1 * max_wander - max_freq;
|
||||
if (f > 0.0) {
|
||||
lc = f / max_wander;
|
||||
|
||||
/* No 1st stage if the frequency is already above the maximum */
|
||||
if (lc > l1) {
|
||||
lc = l1;
|
||||
f2 = dir * smooth_freq;
|
||||
} else {
|
||||
f2 = max_freq;
|
||||
}
|
||||
|
||||
l2 = lc * (2.0 + f / f2);
|
||||
l1 -= lc;
|
||||
l3 -= lc;
|
||||
}
|
||||
|
||||
stages[0].wander = dir * max_wander;
|
||||
stages[0].length = l1;
|
||||
stages[1].wander = 0.0;
|
||||
stages[1].length = l2;
|
||||
stages[2].wander = -dir * max_wander;
|
||||
stages[2].length = l3;
|
||||
|
||||
for (i = 0; i < NUM_STAGES; i++) {
|
||||
DEBUG_LOG(LOGF_Smooth, "Smooth stage %d wander %e length %f",
|
||||
i + 1, stages[i].wander, stages[i].length);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
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;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
get_offset_freq(now, &smooth_offset, &smooth_freq);
|
||||
smooth_offset += offset;
|
||||
smooth_freq = (smooth_freq - freq) / (1.0 - freq);
|
||||
last_update = *now;
|
||||
|
||||
update_stages();
|
||||
|
||||
DEBUG_LOG(LOGF_Smooth, "Smooth offset %e freq %e", smooth_offset, smooth_freq);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_slew(struct timeval *raw, struct timeval *cooked, double dfreq,
|
||||
double doffset, LCL_ChangeType change_type, void *anything)
|
||||
{
|
||||
double delta;
|
||||
|
||||
if (change_type == LCL_ChangeAdjust)
|
||||
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);
|
||||
if (max_freq <= 0.0 || max_wander <= 0.0) {
|
||||
enabled = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
enabled = 1;
|
||||
locked = 1;
|
||||
|
||||
/* Convert from ppm */
|
||||
max_freq *= 1e-6;
|
||||
max_wander *= 1e-6;
|
||||
|
||||
LCL_AddParameterChangeHandler(handle_slew, NULL);
|
||||
}
|
||||
|
||||
void SMT_Finalise(void)
|
||||
{
|
||||
}
|
||||
|
||||
int SMT_IsEnabled(void)
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
double
|
||||
SMT_GetOffset(struct timeval *now)
|
||||
{
|
||||
double offset, freq;
|
||||
|
||||
if (!enabled)
|
||||
return 0.0;
|
||||
|
||||
get_offset_freq(now, &offset, &freq);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
void
|
||||
SMT_Reset(struct timeval *now)
|
||||
{
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
locked = 1;
|
||||
smooth_offset = 0.0;
|
||||
smooth_freq = 0.0;
|
||||
last_update = *now;
|
||||
}
|
||||
40
smooth.h
Normal file
40
smooth.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 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.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
This module implements time smoothing.
|
||||
*/
|
||||
|
||||
#ifndef GOT_SMOOTH_H
|
||||
#define GOT_SMOOTH_H
|
||||
|
||||
extern void SMT_Initialise(void);
|
||||
|
||||
extern void SMT_Finalise(void);
|
||||
|
||||
extern int SMT_IsEnabled(void);
|
||||
|
||||
extern double SMT_GetOffset(struct timeval *now);
|
||||
|
||||
extern void SMT_Reset(struct timeval *now);
|
||||
|
||||
#endif
|
||||
@@ -634,14 +634,14 @@ SST_SlewSamples(SST_Stats inst, struct timeval *when, double dfreq, double doffs
|
||||
inst->offsets[i] += delta_time;
|
||||
}
|
||||
|
||||
/* Do a half-baked update to the regression estimates */
|
||||
/* Update the regression estimates */
|
||||
prev = inst->offset_time;
|
||||
prev_offset = inst->estimated_offset;
|
||||
prev_freq = inst->estimated_frequency;
|
||||
UTI_AdjustTimeval(&(inst->offset_time), when, &(inst->offset_time),
|
||||
&delta_time, dfreq, doffset);
|
||||
inst->estimated_offset += delta_time;
|
||||
inst->estimated_frequency -= dfreq;
|
||||
inst->estimated_frequency = (inst->estimated_frequency - dfreq) / (1.0 - dfreq);
|
||||
|
||||
DEBUG_LOG(LOGF_SourceStats, "n=%d m=%d old_off_time=%s new=%s old_off=%f new_off=%f old_freq=%.3f new_freq=%.3f",
|
||||
inst->n_samples, inst->runs_samples,
|
||||
|
||||
@@ -53,7 +53,7 @@ typedef struct {
|
||||
#define SRC_DEFAULT_MINPOLL 6
|
||||
#define SRC_DEFAULT_MAXPOLL 10
|
||||
#define SRC_DEFAULT_PRESEND_MINPOLL 0
|
||||
#define SRC_DEFAULT_MAXDELAY 16.0
|
||||
#define SRC_DEFAULT_MAXDELAY 3.0
|
||||
#define SRC_DEFAULT_MAXDELAYRATIO 0.0
|
||||
#define SRC_DEFAULT_MAXDELAYDEVRATIO 10.0
|
||||
#define SRC_DEFAULT_MINSTRATUM 0
|
||||
|
||||
@@ -250,7 +250,7 @@ offset_convert(struct timeval *raw,
|
||||
/* ================================================== */
|
||||
/* Positive means currently fast of true time, i.e. jump backwards */
|
||||
|
||||
static void
|
||||
static int
|
||||
apply_step_offset(double offset)
|
||||
{
|
||||
struct timeval old_time, new_time;
|
||||
@@ -260,13 +260,16 @@ apply_step_offset(double offset)
|
||||
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
|
||||
|
||||
if (settimeofday(&new_time, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_SysGeneric, "settimeofday() failed");
|
||||
DEBUG_LOG(LOGF_SysGeneric, "settimeofday() failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
LCL_ReadRawTime(&old_time);
|
||||
UTI_DiffTimevalsToDouble(&err, &old_time, &new_time);
|
||||
|
||||
lcl_InvokeDispersionNotifyHandlers(fabs(err));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
16
sys_linux.c
16
sys_linux.c
@@ -100,12 +100,15 @@ our_round(double x)
|
||||
/* ================================================== */
|
||||
/* Positive means currently fast of true time, i.e. jump backwards */
|
||||
|
||||
static void
|
||||
static int
|
||||
apply_step_offset(double offset)
|
||||
{
|
||||
if (TMX_ApplyStepOffset(-offset) < 0) {
|
||||
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
|
||||
DEBUG_LOG(LOGF_SysLinux, "adjtimex() failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -174,6 +177,15 @@ read_frequency(void)
|
||||
static void
|
||||
set_leap(int leap)
|
||||
{
|
||||
int current_leap;
|
||||
|
||||
if (TMX_GetLeap(¤t_leap) < 0) {
|
||||
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed in set_leap");
|
||||
}
|
||||
|
||||
if (current_leap == leap)
|
||||
return;
|
||||
|
||||
if (TMX_SetLeap(leap) < 0) {
|
||||
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed in set_leap");
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ accrue_offset(double offset, double corr_rate)
|
||||
/* Positive offset means system clock is fast of true time, therefore
|
||||
step backwards */
|
||||
|
||||
static void
|
||||
static int
|
||||
apply_step_offset(double offset)
|
||||
{
|
||||
struct timeval old_time, new_time, T1;
|
||||
@@ -226,7 +226,8 @@ apply_step_offset(double offset)
|
||||
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
|
||||
|
||||
if (settimeofday(&new_time, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_SysNetBSD, "settimeofday() failed");
|
||||
DEBUG_LOG(LOGF_SysNetBSD, "settimeofday() failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
UTI_AddDoubleToTimeval(&T0, offset, &T1);
|
||||
@@ -234,6 +235,7 @@ apply_step_offset(double offset)
|
||||
|
||||
start_adjust();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -219,7 +219,7 @@ accrue_offset(double offset, double corr_rate)
|
||||
/* Positive offset means system clock is fast of true time, therefore
|
||||
step backwards */
|
||||
|
||||
static void
|
||||
static int
|
||||
apply_step_offset(double offset)
|
||||
{
|
||||
struct timeval old_time, new_time, rounded_new_time, T1;
|
||||
@@ -248,7 +248,8 @@ apply_step_offset(double offset)
|
||||
UTI_DiffTimevalsToDouble(&rounding_error, &rounded_new_time, &new_time);
|
||||
|
||||
if (settimeofday(&new_time, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_SysSolaris, "settimeofday() failed");
|
||||
DEBUG_LOG(LOGF_SysSolaris, "settimeofday() failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
UTI_AddDoubleToTimeval(&T0, offset, &T1);
|
||||
@@ -257,6 +258,8 @@ apply_step_offset(double offset)
|
||||
offset_register += rounding_error;
|
||||
|
||||
start_adjust();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -223,7 +223,7 @@ accrue_offset(double offset, double corr_rate)
|
||||
/* Positive offset means system clock is fast of true time, therefore
|
||||
step backwards */
|
||||
|
||||
static void
|
||||
static int
|
||||
apply_step_offset(double offset)
|
||||
{
|
||||
struct timeval old_time, new_time, T1;
|
||||
@@ -236,7 +236,8 @@ apply_step_offset(double offset)
|
||||
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
|
||||
|
||||
if (settimeofday(&new_time, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_SysSunOS, "settimeofday() failed");
|
||||
DEBUG_LOG(LOGF_SysSunOS, "settimeofday() failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
UTI_AddDoubleToTimeval(&T0, offset, &T1);
|
||||
@@ -244,6 +245,7 @@ apply_step_offset(double offset)
|
||||
|
||||
start_adjust();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -6,6 +6,7 @@ test_start "source selection"
|
||||
|
||||
# Falsetickers should be detected if their number is less than half of all
|
||||
|
||||
base_delay=1e-3
|
||||
servers=5
|
||||
|
||||
for falsetickers in 1 2; do
|
||||
@@ -29,7 +30,7 @@ done
|
||||
|
||||
servers=3
|
||||
falsetickers=0
|
||||
base_delay="(+ $default_base_delay (equal 0.1 to 2) (equal 0.1 to 3))"
|
||||
base_delay="(+ 1e-3 (equal 0.1 to 2) (equal 0.1 to 3))"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
|
||||
@@ -5,12 +5,35 @@ test_start "leap second"
|
||||
|
||||
export CLKNETSIM_START_DATE=$(TZ=UTC date -d 'Dec 30 2008 0:00:00' +'%s')
|
||||
|
||||
leap=$[2 * 24 * 3600]
|
||||
limit=$[4 * 24 * 3600]
|
||||
server_conf="refclock SHM 0 dpoll 10 poll 10
|
||||
leapsectz right/UTC"
|
||||
server_step="(* 1.0 (equal 0.1 (sum 1.0) $[2 * 24 * 3600 + 1]))"
|
||||
client_step="(* 1.0 (equal 0.1 (sum 1.0) $[2 * 24 * 3600 + 1]))"
|
||||
refclock_jitter=1e-9
|
||||
refclock_offset="(* -1.0 (equal 0.1 (max (sum 1.0) $leap) $leap))"
|
||||
|
||||
for leapmode in system step slew; do
|
||||
client_conf="leapsecmode $leapmode"
|
||||
if [ $leapmode = slew ]; then
|
||||
max_sync_time=$[$leap + 12]
|
||||
else
|
||||
max_sync_time=$[$leap]
|
||||
fi
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_packet_interval || test_fail
|
||||
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
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
|
||||
@@ -5,7 +5,7 @@ test_start "presend option"
|
||||
|
||||
min_sync_time=140
|
||||
max_sync_time=260
|
||||
client_server_options="presend 6"
|
||||
client_server_options="presend 6 maxdelay 16"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
|
||||
23
test/simulation/117-fallbackdrift
Executable file
23
test/simulation/117-fallbackdrift
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
. test.common
|
||||
test_start "fallback drift"
|
||||
|
||||
limit=100000
|
||||
wander=0.0
|
||||
jitter=1e-6
|
||||
time_offset=10
|
||||
freq_offset="(* 1e-4 (sine 1000))"
|
||||
base_delay="(* -1.0 (equal 0.1 (min time 4250) 4250))"
|
||||
client_server_options="minpoll 4 maxpoll 4"
|
||||
client_conf="fallbackdrift 6 10"
|
||||
time_max_limit=1e0
|
||||
time_rms_limit=1e0
|
||||
freq_max_limit=5e-4
|
||||
freq_rms_limit=5e-4
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
test_pass
|
||||
28
test/simulation/118-maxdelay
Executable file
28
test/simulation/118-maxdelay
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
|
||||
. test.common
|
||||
test_start "maxdelay options"
|
||||
|
||||
max_sync_time=2000
|
||||
base_delay=1e-5
|
||||
jitter=1e-5
|
||||
wander=0.0
|
||||
freq_offset="(sum 1e-10)"
|
||||
time_rms_limit=2e-4
|
||||
|
||||
client_server_options="maxdelay 3e-5 maxdelayratio 2.0 maxdelaydevratio 2.0"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_packet_interval || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
for client_server_options in "maxdelay 2e-5" \ "maxdelayratio 1.001"; do
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_packet_interval || test_fail
|
||||
check_sync && test_fail
|
||||
done
|
||||
|
||||
test_pass
|
||||
68
test/simulation/119-smoothtime
Executable file
68
test/simulation/119-smoothtime
Executable file
@@ -0,0 +1,68 @@
|
||||
#!/bin/bash
|
||||
|
||||
. test.common
|
||||
test_start "smoothtime option"
|
||||
|
||||
server_strata=2
|
||||
server_conf="smoothtime 400 0.001"
|
||||
min_sync_time=250
|
||||
max_sync_time=1000
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
limit=10000
|
||||
refclock_jitter=1e-4
|
||||
refclock_offset="(* 10.0 (equal 0.1 (max (sum 1.0) 1000) 1000))"
|
||||
server_step="(* -10.0 (equal 0.1 (sum 1.0) 1))"
|
||||
server_strata=1
|
||||
server_conf="refclock SHM 0 dpoll 4 poll 6
|
||||
smoothtime 2000 1"
|
||||
time_offset=-10
|
||||
client_server_options="minpoll 6 maxpoll 6"
|
||||
client_conf="corrtimeratio 100"
|
||||
min_sync_time=8000
|
||||
max_sync_time=8500
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
min_sync_time=$default_min_sync_time
|
||||
max_sync_time=$default_max_sync_time
|
||||
time_max_limit=11
|
||||
time_rms_limit=11
|
||||
freq_max_limit=1e-2
|
||||
freq_rms_limit=2e-3
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
refclock_jitter=1e-9
|
||||
refclock_offset="(* 1e-1 (triangle 1000) (+ -1.0 (pulse 1000 10000)))"
|
||||
server_step=""
|
||||
server_conf="refclock SHM 0 dpoll 4 poll 6 minsamples 4 maxsamples 4
|
||||
smoothtime 1e4 1e-6"
|
||||
client_server_options="minpoll 4 maxpoll 4"
|
||||
time_offset=0.1
|
||||
jitter=1e-6
|
||||
wander=0.0
|
||||
min_sync_time=30
|
||||
max_sync_time=40
|
||||
time_max_limit=1e-5
|
||||
time_rms_limit=5e-6
|
||||
freq_max_limit=1e-6
|
||||
freq_rms_limit=1e-7
|
||||
|
||||
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=565e593b4403d035b459b4f8516dacaeaeeb7739
|
||||
clknetsim_revision=3eb3a8d9acf60c31f5acc66617175fc748ef367e
|
||||
clknetsim_url=https://github.com/mlichvar/clknetsim/archive/$clknetsim_revision.tar.gz
|
||||
|
||||
# Only Linux is supported
|
||||
@@ -49,6 +49,7 @@ default_base_delay=1e-4
|
||||
default_jitter=1e-4
|
||||
default_wander=1e-9
|
||||
default_refclock_jitter=""
|
||||
default_refclock_offset=0.0
|
||||
|
||||
default_update_interval=0
|
||||
default_shift_pll=2
|
||||
@@ -168,7 +169,7 @@ get_delay_expr() {
|
||||
}
|
||||
|
||||
get_refclock_expr() {
|
||||
echo "(* $refclock_jitter (normal))"
|
||||
echo "(+ $refclock_offset (* $refclock_jitter (normal)))"
|
||||
}
|
||||
|
||||
get_chronyd_nodes() {
|
||||
@@ -261,7 +262,7 @@ check_source_selection() {
|
||||
for i in $(seq $[$servers * $server_strata + 1] $(get_chronyd_nodes)); do
|
||||
test_message 3 0 "node $i:"
|
||||
|
||||
! grep -q 'no majority\|no reachable sources' tmp/log.$i && \
|
||||
! grep -q 'no majority\|no selectable sources' tmp/log.$i && \
|
||||
grep -q 'Selected source' tmp/log.$i && \
|
||||
test_ok || test_bad
|
||||
[ $? -eq 0 ] || ret=1
|
||||
|
||||
30
util.c
30
util.c
@@ -606,6 +606,36 @@ UTI_Int64ToTimeval(NTP_int64 *src,
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Maximum offset between two sane times */
|
||||
#define MAX_OFFSET 4294967296.0
|
||||
|
||||
int
|
||||
UTI_IsTimeOffsetSane(struct timeval *tv, double offset)
|
||||
{
|
||||
double t;
|
||||
|
||||
/* Handle nan correctly here */
|
||||
if (!(offset > -MAX_OFFSET && offset < MAX_OFFSET))
|
||||
return 0;
|
||||
|
||||
UTI_TimevalToDouble(tv, &t);
|
||||
t += offset;
|
||||
|
||||
/* Time before 1970 is not considered valid */
|
||||
if (t < 0.0)
|
||||
return 0;
|
||||
|
||||
#ifdef HAVE_LONG_TIME_T
|
||||
/* 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;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
UTI_TimevalNetworkToHost(Timeval *src, struct timeval *dest)
|
||||
{
|
||||
|
||||
3
util.h
3
util.h
@@ -104,6 +104,9 @@ extern void UTI_TimevalToInt64(struct timeval *src, NTP_int64 *dest, uint32_t fu
|
||||
|
||||
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);
|
||||
|
||||
extern void UTI_TimevalNetworkToHost(Timeval *src, struct timeval *dest);
|
||||
extern void UTI_TimevalHostToNetwork(struct timeval *src, Timeval *dest);
|
||||
|
||||
|
||||
@@ -123,6 +123,28 @@ TMX_SetLeap(int leap)
|
||||
return adjtimex(&txc);
|
||||
}
|
||||
|
||||
int
|
||||
TMX_GetLeap(int *leap)
|
||||
{
|
||||
struct timex txc;
|
||||
|
||||
txc.modes = 0;
|
||||
if (adjtimex(&txc) < 0)
|
||||
return -1;
|
||||
|
||||
status &= ~(STA_INS | STA_DEL);
|
||||
status |= txc.status & (STA_INS | STA_DEL);
|
||||
|
||||
if (status & STA_INS)
|
||||
*leap = 1;
|
||||
else if (status & STA_DEL)
|
||||
*leap = -1;
|
||||
else
|
||||
*leap = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TMX_SetSync(int sync, double est_error, double max_error)
|
||||
{
|
||||
struct timex txc;
|
||||
|
||||
@@ -31,6 +31,7 @@ int TMX_ResetOffset(void);
|
||||
int TMX_SetFrequency(double *freq, long tick);
|
||||
int TMX_GetFrequency(double *freq, long *tick);
|
||||
int TMX_SetLeap(int leap);
|
||||
int TMX_GetLeap(int *leap);
|
||||
int TMX_SetSync(int sync, double est_error, double max_error);
|
||||
int TMX_TestStepOffset(void);
|
||||
int TMX_ApplyStepOffset(double offset);
|
||||
|
||||
Reference in New Issue
Block a user