diff --git a/Makefile.in b/Makefile.in index e11a1d1..64bef03 100644 --- a/Makefile.in +++ b/Makefile.in @@ -42,7 +42,7 @@ OBJS = util.o sched.o regress.o local.o \ sys.o main.o ntp_io.o ntp_core.o ntp_sources.o \ sources.o sourcestats.o reference.o \ logging.o conf.o cmdmon.o keys.o \ - nameserv.o acquire.o manual.o addrfilt.o \ + nameserv.o manual.o addrfilt.o \ cmdparse.o mkdirpp.o rtc.o pktlength.o clientlog.o \ broadcast.o refclock.o refclock_phc.o refclock_pps.o \ refclock_shm.o refclock_sock.o tempcomp.o $(HASH_OBJ) diff --git a/acquire.c b/acquire.c deleted file mode 100644 index 599e702..0000000 --- a/acquire.c +++ /dev/null @@ -1,796 +0,0 @@ -/* - chronyd/chronyc - Programs for keeping computer clocks accurate. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 1997-2003 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - ********************************************************************** - - ======================================================================= - - Processing to perform the equivalent of what ntpdate does. That is, - make a rapid-fire set of measurements to a designated set of - sources, and step or slew the local clock to bring it into line with - the result. - - This is kept completely separate of the main chronyd processing, by - using a separate socket for sending/receiving the measurement - packets. That way, ntp_core.c can be kept completely independent of - this functionality. - - A few of the finer points of how to construct valid RFC1305 packets - and validate responses for this case have been cribbed from the - ntpdate source. - - */ - -#include "config.h" - -#include "sysincl.h" - -#include "acquire.h" -#include "memory.h" -#include "sched.h" -#include "local.h" -#include "logging.h" -#include "ntp.h" -#include "util.h" -#include "main.h" -#include "conf.h" - -/* ================================================== */ - -/* Interval between firing off the first sample to successive sources */ -#define INTER_SOURCE_START (0.2) - -#define MAX_SAMPLES 8 - -#define MAX_DEAD_PROBES 4 -#define N_GOOD_SAMPLES 4 - -#define RETRANSMISSION_TIMEOUT (1.0) - -#define NTP_VERSION 3 -#define NTP_MAX_COMPAT_VERSION 4 -#define NTP_MIN_COMPAT_VERSION 2 - -typedef struct { - IPAddr ip_addr; /* Address of the server */ - int sanity; /* Flag indicating whether source - looks sane or not */ - int n_dead_probes; /* Number of probes sent to the server - since a good one */ - int n_samples; /* Number of samples accumulated */ - int n_total_samples; /* Total number of samples received - including useless ones */ - double offsets[MAX_SAMPLES]; /* In seconds, positive means local - clock is fast of reference */ - double root_distances[MAX_SAMPLES]; /* in seconds */ - double inter_lo; /* Low end of estimated range of offset */ - double inter_hi; /* High end of estimated range of offset */ - - NTP_int64 last_tx; /* Transmit timestamp in last packet - transmitted to source. */ - - int timer_running; - SCH_TimeoutID timeout_id; -} SourceRecord; - -static SourceRecord *sources; -static int n_sources; -static int n_started_sources; -static int n_completed_sources; - -static double init_slew_threshold; - -union sockaddr_in46 { - struct sockaddr_in in4; -#ifdef HAVE_IPV6 - struct sockaddr_in6 in6; -#endif - struct sockaddr u; -}; - -static int sock_fd4 = -1; -#ifdef HAVE_IPV6 -static int sock_fd6 = -1; -#endif - -/* ================================================== */ - -static void (*saved_after_hook)(void *) = NULL; -static void *saved_after_hook_anything = NULL; - -/* ================================================== */ - -typedef struct { - double offset; - enum {LO, HIGH} type; - int index; -} Endpoint; - -typedef struct { - double lo; - double hi; -} Interval; - -/* ================================================== */ - -static void read_from_socket(void *anything); -static void transmit_timeout(void *x); -static void wind_up_acquisition(void); -static void start_source_timeout_handler(void *not_used); - -/* ================================================== */ - -static SCH_TimeoutID source_start_timeout_id; - -/* ================================================== */ - -void -ACQ_Initialise(void) -{ -} - - -/* ================================================== */ - -void -ACQ_Finalise(void) -{ -} - -/* ================================================== */ - -static int -prepare_socket(int family) -{ - unsigned short port_number = CNF_GetAcquisitionPort(); - int sock_fd; - socklen_t addrlen; - - sock_fd = socket(family, SOCK_DGRAM, 0); - - if (sock_fd < 0) { - LOG_FATAL(LOGF_Acquire, "Could not open socket : %s", strerror(errno)); - } - - /* Close on exec */ - UTI_FdSetCloexec(sock_fd); - - if (port_number == 0 || port_number == CNF_GetNTPPort()) { - /* Don't bother binding this socket - we're not fussed what port - number it gets */ - } else { - union sockaddr_in46 my_addr; - - memset(&my_addr, 0, sizeof (my_addr)); - - switch (family) { - case AF_INET: - my_addr.in4.sin_family = family; - my_addr.in4.sin_port = htons(port_number); - my_addr.in4.sin_addr.s_addr = htonl(INADDR_ANY); - addrlen = sizeof (my_addr.in4); - break; -#ifdef HAVE_IPV6 - case AF_INET6: - my_addr.in6.sin6_family = family; - my_addr.in6.sin6_port = htons(port_number); - my_addr.in6.sin6_addr = in6addr_any; - addrlen = sizeof (my_addr.in6); - break; -#endif - default: - assert(0); - } - - if (bind(sock_fd, &my_addr.u, addrlen) < 0) { - LOG(LOGS_ERR, LOGF_Acquire, "Could not bind socket : %s", strerror(errno)); - /* but keep running */ - } - } - - SCH_AddInputFileHandler(sock_fd, read_from_socket, (void *)(long)sock_fd); - - return sock_fd; -} -/* ================================================== */ - -static void -initialise_io(int family) -{ - if (family == IPADDR_INET4 || family == IPADDR_UNSPEC) - sock_fd4 = prepare_socket(AF_INET); -#ifdef HAVE_IPV6 - if (family == IPADDR_INET6 || family == IPADDR_UNSPEC) - sock_fd6 = prepare_socket(AF_INET6); -#endif -} - -/* ================================================== */ - -static void -finalise_io(void) -{ - if (sock_fd4 >= 0) { - SCH_RemoveInputFileHandler(sock_fd4); - close(sock_fd4); - } - sock_fd4 = -1; -#ifdef HAVE_IPV6 - if (sock_fd6 >= 0) { - SCH_RemoveInputFileHandler(sock_fd6); - close(sock_fd6); - } - sock_fd6 = -1; -#endif -} - -/* ================================================== */ - -static void -probe_source(SourceRecord *src) -{ - NTP_Packet pkt; - int version = NTP_VERSION; - NTP_Mode my_mode = MODE_CLIENT; - struct timeval cooked; - union sockaddr_in46 his_addr; - int sock_fd; - socklen_t addrlen; - uint32_t ts_fuzz; - -#if 0 - printf("Sending probe to %s sent=%d samples=%d\n", UTI_IPToString(&src->ip_addr), src->n_probes_sent, src->n_samples); -#endif - - pkt.lvm = (((LEAP_Unsynchronised << 6) & 0xc0) | - ((version << 3) & 0x38) | - ((my_mode) & 0x7)); - - pkt.stratum = 0; - pkt.poll = 4; - pkt.precision = -6; /* as ntpdate */ - pkt.root_delay = UTI_DoubleToInt32(1.0); /* 1 second */ - pkt.root_dispersion = UTI_DoubleToInt32(1.0); /* likewise */ - pkt.reference_id = 0; - pkt.reference_ts.hi = 0; /* Set to 0 */ - pkt.reference_ts.lo = 0; /* Set to 0 */ - pkt.originate_ts.hi = 0; /* Set to 0 */ - pkt.originate_ts.lo = 0; /* Set to 0 */ - pkt.receive_ts.hi = 0; /* Set to 0 */ - pkt.receive_ts.lo = 0; /* Set to 0 */ - - /* And do transmission */ - - memset(&his_addr, 0, sizeof (his_addr)); - switch (src->ip_addr.family) { - case IPADDR_INET4: - his_addr.in4.sin_addr.s_addr = htonl(src->ip_addr.addr.in4); - his_addr.in4.sin_port = htons(123); /* Fixed for now */ - his_addr.in4.sin_family = AF_INET; - addrlen = sizeof (his_addr.in4); - sock_fd = sock_fd4; - break; -#ifdef HAVE_IPV6 - case IPADDR_INET6: - memcpy(&his_addr.in6.sin6_addr.s6_addr, &src->ip_addr.addr.in6, - sizeof (his_addr.in6.sin6_addr.s6_addr)); - his_addr.in6.sin6_port = htons(123); /* Fixed for now */ - his_addr.in6.sin6_family = AF_INET6; - addrlen = sizeof (his_addr.in6); - sock_fd = sock_fd6; - break; -#endif - default: - assert(0); - } - - - ts_fuzz = UTI_GetNTPTsFuzz(LCL_GetSysPrecisionAsLog()); - LCL_ReadCookedTime(&cooked, NULL); - UTI_TimevalToInt64(&cooked, &pkt.transmit_ts, ts_fuzz); - - if (sendto(sock_fd, (void *) &pkt, NTP_NORMAL_PACKET_SIZE, - 0, - &his_addr.u, addrlen) < 0) { - LOG(LOGS_WARN, LOGF_Acquire, "Could not send to %s : %s", - UTI_IPToString(&src->ip_addr), - strerror(errno)); - } - - src->last_tx = pkt.transmit_ts; - - ++(src->n_dead_probes); - src->timer_running = 1; - src->timeout_id = SCH_AddTimeoutByDelay(RETRANSMISSION_TIMEOUT, transmit_timeout, (void *) src); -} - -/* ================================================== */ - -static void -transmit_timeout(void *x) -{ - SourceRecord *src = (SourceRecord *) x; - - src->timer_running = 0; - -#if 0 - printf("Timeout expired for server %s\n", UTI_IPToString(&src->ip_addr)); -#endif - - if (src->n_dead_probes < MAX_DEAD_PROBES) { - probe_source(src); - } else { - /* Source has croaked or is taking too long to respond */ - ++n_completed_sources; - if (n_completed_sources == n_sources) { - wind_up_acquisition(); - } - } -} - -/* ================================================== */ - -#define MAX_STRATUM 15 - -static void -process_receive(NTP_Packet *msg, SourceRecord *src, struct timeval *now) -{ - - unsigned long lvm; - int leap, version, mode; - double root_delay, root_dispersion; - double total_root_delay, total_root_dispersion, total_root_distance; - - struct timeval local_orig, local_average, remote_rx, remote_tx, remote_average; - double remote_interval, local_interval; - double delta, theta, epsilon; - int n; - - /* Most of the checks are from ntpdate */ - - /* Need to do something about authentication */ - - lvm = msg->lvm; - leap = (lvm >> 6) & 0x3; - version = (lvm >> 3) & 0x7; - mode = lvm & 0x7; - - if ((leap == LEAP_Unsynchronised) || - (version < NTP_MIN_COMPAT_VERSION || version > NTP_MAX_COMPAT_VERSION) || - (mode != MODE_SERVER && mode != MODE_PASSIVE)) { - return; - } - - if (msg->stratum > MAX_STRATUM) { - return; - } - - /* Check whether server is responding to our last request */ - if ((msg->originate_ts.hi != src->last_tx.hi) || - (msg->originate_ts.lo != src->last_tx.lo)) { - return; - } - - /* Check that the server is sane */ - if (((msg->originate_ts.hi == 0) && (msg->originate_ts.lo == 0)) || - ((msg->receive_ts.hi == 0) && (msg->receive_ts.lo) == 0)) { - return; - } - - root_delay = UTI_Int32ToDouble(msg->root_delay); - root_dispersion = UTI_Int32ToDouble(msg->root_dispersion); - - UTI_Int64ToTimeval(&src->last_tx, &local_orig); - UTI_Int64ToTimeval(&msg->receive_ts, &remote_rx); - UTI_Int64ToTimeval(&msg->transmit_ts, &remote_tx); - UTI_AverageDiffTimevals(&remote_rx, &remote_tx, &remote_average, &remote_interval); - UTI_AverageDiffTimevals(&local_orig, now, &local_average, &local_interval); - - delta = local_interval - remote_interval; - - /* Defined as positive if we are fast. Note this sign convention is - opposite to that used in ntp_core.c */ - - UTI_DiffTimevalsToDouble(&theta, &local_average, &remote_average); - - /* Could work out epsilon - leave till later */ - epsilon = 0.0; - - total_root_delay = fabs(delta) + root_delay; - total_root_dispersion = epsilon + root_dispersion; - total_root_distance = 0.5 * fabs(total_root_delay) + total_root_dispersion; - - n = src->n_samples; -#if 0 - printf("Sample %d theta=%.6f delta=%.6f root_del=%.6f root_disp=%.6f root_dist=%.6f\n", - n, theta, delta, total_root_delay, total_root_dispersion, total_root_distance); -#endif - src->offsets[n] = theta; - src->root_distances[n] = total_root_distance; - ++(src->n_samples); - -} - -/* ================================================== */ - -static void -read_from_socket(void *anything) -{ - int status; - ReceiveBuffer msg; - union sockaddr_in46 his_addr; - int sock_fd; - socklen_t his_addr_len; - int flags; - int message_length; - IPAddr remote_ip; - int i, ok; - struct timeval now; - SourceRecord *src; - - flags = 0; - message_length = sizeof(msg); - his_addr_len = sizeof(his_addr); - - /* Get timestamp */ - SCH_GetLastEventTime(&now, NULL, NULL); - - sock_fd = (long)anything; - status = recvfrom (sock_fd, (char *)&msg, message_length, flags, - &his_addr.u, &his_addr_len); - - if (status < 0) { - LOG(LOGS_WARN, LOGF_Acquire, "Error reading from socket, %s", strerror(errno)); - return; - } - - switch (his_addr.u.sa_family) { - case AF_INET: - remote_ip.family = IPADDR_INET4; - remote_ip.addr.in4 = ntohl(his_addr.in4.sin_addr.s_addr); - break; -#ifdef HAVE_IPV6 - case AF_INET6: - remote_ip.family = IPADDR_INET6; - memcpy(&remote_ip.addr.in6, his_addr.in6.sin6_addr.s6_addr, - sizeof (remote_ip.addr.in6)); - break; -#endif - default: - assert(0); - } - -#if 0 - printf("Got message from %s\n", UTI_IPToString(&remote_ip)); -#endif - - /* Find matching host */ - ok = 0; - for (i=0; in_total_samples; - - src->n_dead_probes = 0; /* reset this when we actually receive something */ - - /* If we got into this function, we know the retransmission timeout has not - expired for the source */ - if (src->timer_running) { - SCH_RemoveTimeout(src->timeout_id); - src->timer_running = 0; - } - - process_receive(&msg.ntp_pkt, src, &now); - - /* Check if server done and requeue timeout */ - if ((src->n_samples >= N_GOOD_SAMPLES) || - (src->n_total_samples >= MAX_SAMPLES)) { - ++n_completed_sources; -#if 0 - printf("Source %s completed\n", UTI_IPToString(&src->ip_addr)); -#endif - if (n_completed_sources == n_sources) { - wind_up_acquisition(); - } - } else { - - /* Send the next probe */ - probe_source(src); - - } - } - -} - -/* ================================================== */ - -static void -start_next_source(void) -{ - probe_source(sources + n_started_sources); -#if 0 - printf("Trying to start source %s\n", UTI_IPToString(&sources[n_started_sources].ip_addr)); -#endif - n_started_sources++; - - if (n_started_sources < n_sources) { - source_start_timeout_id = SCH_AddTimeoutByDelay(INTER_SOURCE_START, start_source_timeout_handler, NULL); - } -} - -/* ================================================== */ - -static int -endpoint_compare(const void *a, const void *b) -{ - const Endpoint *aa = (const Endpoint *) a; - const Endpoint *bb = (const Endpoint *) b; - - if (aa->offset < bb->offset) { - return -1; - } else if (aa->offset > bb->offset) { - return +1; - } else { - return 0; - } -} - -/* ================================================== */ - -static void -process_measurements(void) -{ - - SourceRecord *s; - Endpoint *eps; - int i, j; - int n_sane_sources; - double lo, hi; - double inter_lo, inter_hi; - - int depth; - int best_depth; - int n_at_best_depth; - Interval *intervals; - double estimated_offset; - int index1, index2; - - n_sane_sources = 0; - - /* First, get a consistent interval for each source. Those for - which this is not possible are considered to be insane. */ - - for (i=0; in_samples == 0) { - s->sanity = 0; - } else { - s->sanity = 1; /* so far ... */ - lo = s->offsets[0] - s->root_distances[0]; - hi = s->offsets[0] + s->root_distances[0]; - inter_lo = lo; - inter_hi = hi; - for (j=1; jn_samples; j++) { - lo = s->offsets[j] - s->root_distances[j]; - hi = s->offsets[j] + s->root_distances[j]; - if ((inter_hi <= lo) || (inter_lo >= hi)) { - /* Oh dear, we won't get an interval for this source */ - s->sanity = 0; - break; - } else { - inter_lo = (lo < inter_lo) ? inter_lo : lo; - inter_hi = (hi > inter_hi) ? inter_hi : hi; - } - } - if (s->sanity) { - s->inter_lo = inter_lo; - s->inter_hi = inter_hi; - } - } - - if (s->sanity) { - ++n_sane_sources; - } - - } - - /* Now build the endpoint list, similar to the RFC1305 clock - selection algorithm. */ - eps = MallocArray(Endpoint, 2*n_sane_sources); - intervals = MallocArray(Interval, n_sane_sources); - - j = 0; - for (i=0; isanity) { - eps[j].offset = s->inter_lo; - eps[j].type = LO; - eps[j].index = i; - eps[j+1].offset = s->inter_hi; - eps[j+1].type = HIGH; - eps[j+1].index = i; - j += 2; - } - } - - qsort(eps, 2*n_sane_sources, sizeof(Endpoint), endpoint_compare); - - /* Now do depth searching algorithm */ - n_at_best_depth = best_depth = depth = 0; - for (i=0; i<2*n_sane_sources; i++) { - -#if 0 - fprintf(stderr, "Endpoint type %s source index %d [ip=%s] offset=%.6f\n", - (eps[i].type == LO) ? "LO" : "HIGH", - eps[i].index, - UTI_IPToString(&sources[eps[i].index].ip_addr), - eps[i].offset); -#endif - - switch (eps[i].type) { - case LO: - depth++; - if (depth > best_depth) { - best_depth = depth; - n_at_best_depth = 0; - intervals[0].lo = eps[i].offset; - } else if (depth == best_depth) { - intervals[n_at_best_depth].lo = eps[i].offset; - } else { - /* Nothing to do */ - } - - break; - - case HIGH: - if (depth == best_depth) { - intervals[n_at_best_depth].hi = eps[i].offset; - n_at_best_depth++; - } - - depth--; - - break; - - } - } - - if (best_depth > 0) { - if ((n_at_best_depth % 2) == 1) { - index1 = (n_at_best_depth - 1) / 2; - estimated_offset = 0.5 * (intervals[index1].lo + intervals[index1].hi); - } else { - index2 = (n_at_best_depth / 2); - index1 = index2 - 1; - estimated_offset = 0.5 * (intervals[index1].lo + intervals[index2].hi); - } - - - /* Apply a step change to the system clock. As per sign - convention in local.c and its children, a positive offset means - the system clock is fast of the reference, i.e. it needs to be - stepped backwards. */ - - if (fabs(estimated_offset) > init_slew_threshold) { - LOG(LOGS_INFO, LOGF_Acquire, "System's initial offset : %.6f seconds %s of true (step)", - fabs(estimated_offset), - (estimated_offset >= 0) ? "fast" : "slow"); - LCL_ApplyStepOffset(estimated_offset); - } else { - LOG(LOGS_INFO, LOGF_Acquire, "System's initial offset : %.6f seconds %s of true (slew)", - fabs(estimated_offset), - (estimated_offset >= 0) ? "fast" : "slow"); - LCL_AccumulateOffset(estimated_offset, 0.0); - } - - } else { - LOG(LOGS_WARN, LOGF_Acquire, "No intersecting endpoints found"); - } - - Free(intervals); - Free(eps); - -} - -/* ================================================== */ - -static void -wind_up_acquisition(void) -{ - - /* Now process measurements */ - process_measurements(); - - Free(sources); - - finalise_io(); - - if (saved_after_hook) { - (saved_after_hook)(saved_after_hook_anything); - } - -} - -/* ================================================== */ - -static void -start_source_timeout_handler(void *not_used) -{ - - start_next_source(); -} - -/* ================================================== */ - -void -ACQ_StartAcquisition(int n, IPAddr *ip_addrs, double threshold, void (*after_hook)(void *), void *anything) -{ - - int i, ip4, ip6; - int k, duplicate_ip; - - saved_after_hook = after_hook; - saved_after_hook_anything = anything; - - init_slew_threshold = threshold; - - n_started_sources = 0; - n_completed_sources = 0; - n_sources = 0; - sources = MallocArray(SourceRecord, n); - - for (i = ip4 = ip6 = 0; i < n; i++) { - /* check for duplicate IP addresses and ignore them */ - duplicate_ip = 0; - for (k = 0; k < i; k++) { - duplicate_ip |= UTI_CompareIPs(&(sources[k].ip_addr), - &ip_addrs[i], - NULL) == 0; - } - if (!duplicate_ip) { - sources[n_sources].ip_addr = ip_addrs[i]; - sources[n_sources].n_samples = 0; - sources[n_sources].n_total_samples = 0; - sources[n_sources].n_dead_probes = 0; - if (ip_addrs[i].family == IPADDR_INET4) - ip4++; - else if (ip_addrs[i].family == IPADDR_INET6) - ip6++; - n_sources++; - } else { - LOG(LOGS_WARN, LOGF_Acquire, "Ignoring duplicate source: %s", - UTI_IPToString(&ip_addrs[i])); - } - } - - initialise_io((ip4 && ip6) ? IPADDR_UNSPEC : (ip4 ? IPADDR_INET4 : IPADDR_INET6)); - - /* Start sampling first source */ - start_next_source(); -} - -/* ================================================== */ diff --git a/acquire.h b/acquire.h deleted file mode 100644 index cd15cce..0000000 --- a/acquire.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - chronyd/chronyc - Programs for keeping computer clocks accurate. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 1997-2002 - * - * 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 acquisition module - */ - -#ifndef GOT_ACQUIRE_H -#define GOT_ACQUIRE_H - -#include "addressing.h" - -typedef struct ACQ_SourceRecord *ACQ_Source; - -extern void ACQ_Initialise(void); - -extern void ACQ_Finalise(void); - -extern void ACQ_StartAcquisition(int n, IPAddr *ip_addrs, double init_slew_threshold, - void (*after_hook)(void *), void *anything); - -extern void ACQ_AccumulateSample(ACQ_Source acq_source, double offset, double root_distance); - -extern void ACQ_MissedSample(ACQ_Source acq_source); - -#endif /* GOT_ACQUIRE_H */ diff --git a/conf.c b/conf.c index 0b63ae9..5af18d3 100644 --- a/conf.c +++ b/conf.c @@ -38,7 +38,6 @@ #include "logging.h" #include "nameserv.h" #include "memory.h" -#include "acquire.h" #include "cmdparse.h" #include "broadcast.h" #include "util.h" @@ -110,7 +109,6 @@ static char *dumpdir = "."; static int enable_local=0; static int local_stratum; -static int do_init_stepslew = 0; static int n_init_srcs; /* Threshold (in seconds) - if absolute value of initial error is less @@ -787,9 +785,6 @@ parse_initstepslew(char *line) } } } - if (n_init_srcs > 0) { - do_init_stepslew = 1; - } } /* ================================================== */ @@ -1155,12 +1150,24 @@ parse_include(char *line) /* ================================================== */ void -CNF_ProcessInitStepSlew(void (*after_hook)(void *), void *anything) +CNF_AddInitSources(void) { - if (do_init_stepslew) { - ACQ_StartAcquisition(n_init_srcs, init_srcs_ip, init_slew_threshold, after_hook, anything); - } else { - (after_hook)(anything); + CPS_NTP_Source cps_source; + NTP_Remote_Address ntp_addr; + char dummy_hostname[2] = "H"; + int i; + + for (i = 0; i < n_init_srcs; i++) { + /* Get the default NTP params */ + CPS_ParseNTPSourceAdd(dummy_hostname, &cps_source); + + /* Add the address as an offline iburst server */ + ntp_addr.ip_addr = init_srcs_ip[i]; + ntp_addr.port = cps_source.port; + cps_source.params.iburst = 1; + cps_source.params.online = 0; + + NSR_AddSource(&ntp_addr, NTP_SERVER, &cps_source.params); } } @@ -1671,3 +1678,19 @@ CNF_GetHwclockFile(void) { return hwclock_file; } + +/* ================================================== */ + +int +CNF_GetInitSources(void) +{ + return n_init_srcs; +} + +/* ================================================== */ + +double +CNF_GetInitStepThreshold(void) +{ + return init_slew_threshold; +} diff --git a/conf.h b/conf.h index bdc3e7b..70feee1 100644 --- a/conf.h +++ b/conf.h @@ -35,12 +35,11 @@ extern char *CNF_GetRtcDevice(void); extern void CNF_ReadFile(const char *filename); +extern void CNF_AddInitSources(void); extern void CNF_AddSources(void); extern void CNF_AddBroadcasts(void); extern void CNF_AddRefclocks(void); -extern void CNF_ProcessInitStepSlew(void (*after_hook)(void *), void *anything); - extern unsigned short CNF_GetAcquisitionPort(void); extern unsigned short CNF_GetNTPPort(void); extern char *CNF_GetDriftFile(void); @@ -103,4 +102,7 @@ extern int CNF_GetMinSamples(void); extern double CNF_GetRtcAutotrim(void); extern char *CNF_GetHwclockFile(void); +extern int CNF_GetInitSources(void); +extern double CNF_GetInitStepThreshold(void); + #endif /* GOT_CONF_H */ diff --git a/main.c b/main.c index 207011f..7eaf63a 100644 --- a/main.c +++ b/main.c @@ -44,7 +44,6 @@ #include "conf.h" #include "cmdmon.h" #include "keys.h" -#include "acquire.h" #include "manual.h" #include "rtc.h" #include "refclock.h" @@ -64,6 +63,8 @@ static int initialised = 0; static int reload = 0; +static REF_Mode ref_mode; + /* ================================================== */ static void @@ -87,7 +88,6 @@ MAI_CleanupAndExit(void) TMC_Finalise(); MNL_Finalise(); - ACQ_Finalise(); CLG_Finalise(); NSR_Finalise(); NCR_Finalise(); @@ -123,8 +123,15 @@ signal_cleanup(int x) /* ================================================== */ static void -post_acquire_hook(void *anything) +post_init_ntp_hook(void *anything) { + if (ref_mode == REF_ModeInitStepSlew) { + /* Remove the initstepslew sources and set normal mode */ + NSR_RemoveAllSources(); + ref_mode = REF_ModeNormal; + REF_SetMode(ref_mode); + } + /* Close the pipe to the foreground process so it can exit */ LOG_CloseParentFd(); @@ -145,10 +152,34 @@ post_acquire_hook(void *anything) /* ================================================== */ +static void +reference_mode_end(int result) +{ + switch (ref_mode) { + case REF_ModeNormal: + break; + case REF_ModeInitStepSlew: + /* post_init_ntp_hook removes sources and a source call is + on the stack here, so it can't be called directly */ + SCH_AddTimeoutByDelay(0.0, post_init_ntp_hook, NULL); + break; + default: + assert(0); + } +} + +/* ================================================== */ + static void post_init_rtc_hook(void *anything) { - CNF_ProcessInitStepSlew(post_acquire_hook, NULL); + if (CNF_GetInitSources() > 0) { + CNF_AddInitSources(); + assert(REF_GetMode() != REF_ModeNormal); + /* Wait for mode end notification */ + } else { + (post_init_ntp_hook)(NULL); + } } /* ================================================== */ @@ -416,13 +447,19 @@ int main NCR_Initialise(); NSR_Initialise(); CLG_Initialise(); - ACQ_Initialise(); MNL_Initialise(); TMC_Initialise(); /* From now on, it is safe to do finalisation on exit */ initialised = 1; + if (CNF_GetInitSources() > 0) { + ref_mode = REF_ModeInitStepSlew; + } + + REF_SetModeEndHandler(reference_mode_end); + REF_SetMode(ref_mode); + if (do_init_rtc) { RTC_TimeInit(post_init_rtc_hook, NULL); } else { diff --git a/ntp_sources.c b/ntp_sources.c index 1108592..735ee0a 100644 --- a/ntp_sources.c +++ b/ntp_sources.c @@ -339,6 +339,21 @@ NSR_RemoveSource(NTP_Remote_Address *remote_addr) /* ================================================== */ +void +NSR_RemoveAllSources(void) +{ + int i; + + for (i = 0; i < N_RECORDS; i++) { + if (!records[i].remote_addr) + continue; + NCR_DestroyInstance(records[i].data); + records[i].remote_addr = NULL; + } +} + +/* ================================================== */ + /* This routine is called by ntp_io when a new packet arrives off the network, possibly with an authentication tail */ void diff --git a/ntp_sources.h b/ntp_sources.h index 596c040..43a1cc8 100644 --- a/ntp_sources.h +++ b/ntp_sources.h @@ -60,6 +60,9 @@ extern void NSR_ResolveSources(void); /* Procedure to remove a source */ extern NSR_Status NSR_RemoveSource(NTP_Remote_Address *remote_addr); +/* Procedure to remove all sources */ +extern void NSR_RemoveAllSources(void); + /* This routine is called by ntp_io when a new packet arrives off the network */ extern void NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length); diff --git a/reference.c b/reference.c index 3a3af1e..3a721b9 100644 --- a/reference.c +++ b/reference.c @@ -67,6 +67,9 @@ static double correction_time_ratio; /* Flag indicating that we are initialised */ static int initialised = 0; +/* Current operating mode */ +static REF_Mode mode; + /* Threshold and update limit for stepping clock */ static int make_step_limit; static double make_step_threshold; @@ -86,6 +89,9 @@ static int do_mail_change; static double mail_change_threshold; static char *mail_change_user; +/* Handler for mode ending */ +static REF_ModeEndHandler mode_end_handler = NULL; + /* Filename of the drift file. */ static char *drift_file=NULL; static double drift_file_age; @@ -155,6 +161,7 @@ REF_Initialise(void) double file_freq_ppm, file_skew_ppm; double our_frequency_ppm; + mode = REF_ModeIgnore; are_we_synchronised = 0; our_leap_status = LEAP_Unsynchronised; our_leap_sec = 0; @@ -266,6 +273,29 @@ REF_Finalise(void) /* ================================================== */ +void REF_SetMode(REF_Mode new_mode) +{ + mode = new_mode; +} + +/* ================================================== */ + +REF_Mode +REF_GetMode(void) +{ + return mode; +} + +/* ================================================== */ + +void +REF_SetModeEndHandler(REF_ModeEndHandler handler) +{ + mode_end_handler = handler; +} + +/* ================================================== */ + static double Sqr(double x) { @@ -456,6 +486,18 @@ schedule_fb_drift(struct timeval *now) /* ================================================== */ +static void +end_ref_mode(int result) +{ + mode = REF_ModeIgnore; + + /* Dispatch the handler */ + if (mode_end_handler) + (mode_end_handler)(result); +} + +/* ================================================== */ + #define BUFLEN 255 #define S_MAX_USER_LEN "128" @@ -664,6 +706,43 @@ write_log(struct timeval *ref_time, char *ref, int stratum, NTP_Leap leap, /* ================================================== */ +static void +special_mode_sync(int valid, double offset) +{ + int step; + + switch (mode) { + case REF_ModeInitStepSlew: + if (!valid) { + LOG(LOGS_WARN, LOGF_Reference, "No suitable source for initstepslew"); + end_ref_mode(0); + break; + } + + step = fabs(offset) >= CNF_GetInitStepThreshold(); + + LOG(LOGS_INFO, LOGF_Reference, + "System's initial offset : %.6f seconds %s of true (%s)", + fabs(offset), offset >= 0 ? "fast" : "slow", step ? "step" : "slew"); + + if (step) + LCL_ApplyStepOffset(offset); + else + LCL_AccumulateOffset(offset, 0.0); + + end_ref_mode(1); + + break; + case REF_ModeIgnore: + /* Do nothing until the mode is changed */ + break; + default: + assert(0); + } +} + +/* ================================================== */ + void REF_SetReference(int stratum, NTP_Leap leap, @@ -695,6 +774,12 @@ REF_SetReference(int stratum, assert(initialised); + /* Special modes are implemented elsewhere */ + if (mode != REF_ModeNormal) { + special_mode_sync(1, offset); + return; + } + /* Guard against dividing by zero */ if (skew < MIN_SKEW) skew = MIN_SKEW; @@ -886,6 +971,12 @@ REF_SetUnsynchronised(void) assert(initialised); + /* Special modes are implemented elsewhere */ + if (mode != REF_ModeNormal) { + special_mode_sync(0, 0.0); + return; + } + /* This is cheaper than calling LCL_CookTime */ SCH_GetLastEventTime(&now, NULL, &now_raw); UTI_DiffTimevalsToDouble(&uncorrected_offset, &now, &now_raw); @@ -1086,5 +1177,3 @@ REF_GetTrackingReport(RPT_TrackingReport *rep) } } - -/* ================================================== */ diff --git a/reference.h b/reference.h index 9fe595f..babbd6a 100644 --- a/reference.h +++ b/reference.h @@ -40,6 +40,24 @@ extern void REF_Initialise(void); /* Fini function */ extern void REF_Finalise(void); +typedef enum { + REF_ModeNormal, + REF_ModeInitStepSlew, + REF_ModeIgnore, +} REF_Mode; + +/* Set reference update mode */ +extern void REF_SetMode(REF_Mode mode); + +/* Get reference update mode */ +extern REF_Mode REF_GetMode(void); + +/* Function type for handlers to be called back when mode ends */ +typedef void (*REF_ModeEndHandler)(int result); + +/* Set the handler for being notified of mode ending */ +extern void REF_SetModeEndHandler(REF_ModeEndHandler handler); + /* Function which takes a local cooked time and returns the estimated time of the reference. It also returns the other parameters required for forming the outgoing NTP packet. diff --git a/sources.c b/sources.c index e95fa8a..77245ca 100644 --- a/sources.c +++ b/sources.c @@ -363,6 +363,12 @@ SRC_UpdateReachability(SRC_Instance inst, int reachable) /* Try to select a better source */ SRC_SelectSource(NULL); } + + /* End special reference mode on last reachability update from iburst */ + if (REF_GetMode() != REF_ModeNormal && + inst->reachability_size >= REACH_BITS - 1) { + REF_SetUnsynchronised(); + } } /* ================================================== */ diff --git a/test/simulation/103-initstepslew b/test/simulation/103-initstepslew index 0d0352b..163efc3 100755 --- a/test/simulation/103-initstepslew +++ b/test/simulation/103-initstepslew @@ -5,12 +5,13 @@ test_start "initstepslew directive" freq_offset=0.0 wander=0.0 +time_rms_limit=1e-3 limit=100 client_conf="initstepslew 5 192.168.123.1" -min_sync_time=15 -max_sync_time=30 +min_sync_time=20 +max_sync_time=35 for time_offset in -2.0 -0.2 0.2 2.0; do run_test || test_fail @@ -18,8 +19,8 @@ for time_offset in -2.0 -0.2 0.2 2.0; do check_sync || test_fail done -min_sync_time=1 -max_sync_time=1 +min_sync_time=5 +max_sync_time=5 for time_offset in -1e8 -1e2 1e2 1e8; do run_test || test_fail