diff --git a/cmdparse.c b/cmdparse.c index a24324f..37d1581 100644 --- a/cmdparse.c +++ b/cmdparse.c @@ -224,12 +224,13 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src) /* ================================================== */ int -CPS_ParseLocal(char *line, int *stratum) +CPS_ParseLocal(char *line, int *stratum, double *distance) { int n; char *cmd; *stratum = 10; + *distance = 1.0; while (*line) { cmd = line; @@ -238,6 +239,9 @@ CPS_ParseLocal(char *line, int *stratum) if (!strcasecmp(cmd, "stratum")) { if (sscanf(line, "%d%n", stratum, &n) != 1) return 0; + } else if (!strcasecmp(cmd, "distance")) { + if (sscanf(line, "%lf%n", distance, &n) != 1) + return 0; } else { return 0; } diff --git a/cmdparse.h b/cmdparse.h index eb1714d..6944475 100644 --- a/cmdparse.h +++ b/cmdparse.h @@ -60,7 +60,7 @@ typedef struct { extern CPS_Status CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src); /* Parse a command to enable local reference */ -extern int CPS_ParseLocal(char *line, int *stratum); +extern int CPS_ParseLocal(char *line, int *stratum, double *distance); /* Get a string describing error status */ extern void CPS_StatusToString(CPS_Status status, char *dest, int len); diff --git a/conf.c b/conf.c index d989a5e..8c125ff 100644 --- a/conf.c +++ b/conf.c @@ -108,6 +108,7 @@ static char *dumpdir; static int enable_local=0; static int local_stratum; +static double local_distance; /* Threshold (in seconds) - if absolute value of initial error is less than this, slew instead of stepping */ @@ -817,7 +818,7 @@ parse_log(char *line) static void parse_local(char *line) { - if (!CPS_ParseLocal(line, &local_stratum)) + if (!CPS_ParseLocal(line, &local_stratum, &local_distance)) command_parse_error(); enable_local = 1; } @@ -1565,10 +1566,11 @@ CNF_GetCommandPort(void) { /* ================================================== */ int -CNF_AllowLocalReference(int *stratum) +CNF_AllowLocalReference(int *stratum, double *distance) { if (enable_local) { *stratum = local_stratum; + *distance = local_distance; return 1; } else { return 0; diff --git a/conf.h b/conf.h index 34c7e41..6ded8f5 100644 --- a/conf.h +++ b/conf.h @@ -92,7 +92,7 @@ extern double CNF_GetReselectDistance(void); extern double CNF_GetStratumWeight(void); extern double CNF_GetCombineLimit(void); -extern int CNF_AllowLocalReference(int *stratum); +extern int CNF_AllowLocalReference(int *stratum, double *distance); extern void CNF_SetupAccessRestrictions(void); diff --git a/reference.c b/reference.c index f9b4ad4..2b51f01 100644 --- a/reference.c +++ b/reference.c @@ -45,6 +45,7 @@ static int are_we_synchronised; static int enable_local_stratum; static int local_stratum; +static double local_distance; static NTP_Leap our_leap_status; static int our_leap_sec; static int our_stratum; @@ -112,6 +113,11 @@ static char *leap_tzname; static time_t last_tz_leap_check; static NTP_Leap tz_leap; +#define MAX_LOCAL_TIMEOUT (30 * 24 * 3600.0) + +/* Timer for local reference */ +static SCH_TimeoutID local_timeout_id; + /* ================================================== */ static LOG_FileID logfileid; @@ -230,7 +236,8 @@ REF_Initialise(void) correction_time_ratio = CNF_GetCorrectionTimeRatio(); - enable_local_stratum = CNF_AllowLocalReference(&local_stratum); + enable_local_stratum = CNF_AllowLocalReference(&local_stratum, &local_distance); + local_timeout_id = 0; leap_timeout_id = 0; leap_in_progress = 0; @@ -801,6 +808,38 @@ update_leap_status(NTP_Leap leap, time_t now, int reset) /* ================================================== */ +static void +local_timeout(void *arg) +{ + local_timeout_id = 0; + REF_SetUnsynchronised(); +} + +/* ================================================== */ + +static void +update_local_timeout(void) +{ + double delay; + + SCH_RemoveTimeout(local_timeout_id); + local_timeout_id = 0; + + if (!enable_local_stratum || !are_we_synchronised) + return; + + /* Add a timer that will activate the local reference approximately at the + point when our root distance reaches the configured root distance */ + delay = (local_distance - (our_root_delay / 2.0 + our_root_dispersion)) / + (our_skew + fabs(our_residual_freq) + LCL_GetMaxClockError()); + delay = CLAMP(0.0, delay, MAX_LOCAL_TIMEOUT); + local_timeout_id = SCH_AddTimeoutByDelay(delay, local_timeout, NULL); + + DEBUG_LOG(LOGF_Reference, "Local reference timeout %f", delay); +} + +/* ================================================== */ + static void write_log(struct timeval *ref_time, char *ref, int stratum, NTP_Leap leap, double freq, double skew, double offset, int combined_sources, @@ -1063,6 +1102,9 @@ REF_SetReference(int stratum, } } + /* Update timer that activates the local reference */ + update_local_timeout(); + /* Update fallback drifts */ if (fb_drifts) { update_fb_drifts(abs_freq_ppm, update_interval); @@ -1127,6 +1169,7 @@ REF_SetUnsynchronised(void) update_leap_status(LEAP_Unsynchronised, 0, 0); are_we_synchronised = 0; + update_local_timeout(); LCL_SetSyncStatus(0, 0.0, 0.0);