diff --git a/reference.c b/reference.c index 10192ea..2aec654 100644 --- a/reference.c +++ b/reference.c @@ -1130,6 +1130,21 @@ REF_SetUnsynchronised(void) /* ================================================== */ +void +REF_UpdateLeapStatus(NTP_Leap leap) +{ + struct timespec raw_now; + + /* Wait for a full reference update if not already synchronised */ + if (!are_we_synchronised) + return; + + SCH_GetLastEventTime(NULL, NULL, &raw_now); + update_leap_status(leap, raw_now.tv_sec, 0); +} + +/* ================================================== */ + void REF_GetReferenceParams ( diff --git a/reference.h b/reference.h index 4f57f0e..4f19af1 100644 --- a/reference.h +++ b/reference.h @@ -162,6 +162,9 @@ extern void REF_SetManualReference extern void REF_SetUnsynchronised(void); +/* Announce a leap second before the full reference update */ +extern void REF_UpdateLeapStatus(NTP_Leap leap); + /* Return the current stratum of this host or 16 if the host is not synchronised */ extern int REF_GetOurStratum(void); diff --git a/sources.c b/sources.c index 6294bbd..bb4e6e3 100644 --- a/sources.c +++ b/sources.c @@ -128,6 +128,9 @@ struct SRC_Instance_Record { /* Latest leap status */ NTP_Leap leap; + + /* Flag indicating the source has a leap second vote */ + int leap_vote; }; /* ================================================== */ @@ -301,6 +304,7 @@ SRC_ResetInstance(SRC_Instance instance) instance->status = SRC_BAD_STATS; instance->sel_score = 1.0; instance->leap = LEAP_Unsynchronised; + instance->leap_vote = 0; SST_ResetInstance(instance->stats); } @@ -326,6 +330,34 @@ SRC_GetSourcestats(SRC_Instance instance) /* ================================================== */ +static NTP_Leap +get_leap_status(void) +{ + int i, leap_votes, leap_ins, leap_del; + + /* Accept a leap second if more than half of the sources with a vote agree */ + + for (i = leap_ins = leap_del = leap_votes = 0; i < n_sources; i++) { + if (!sources[i]->leap_vote) + continue; + + leap_votes++; + if (sources[i]->leap == LEAP_InsertSecond) + leap_ins++; + else if (sources[i]->leap == LEAP_DeleteSecond) + leap_del++; + } + + if (leap_ins > leap_votes / 2) + return LEAP_InsertSecond; + else if (leap_del > leap_votes / 2) + return LEAP_DeleteSecond; + else + return LEAP_Normal; +} + +/* ================================================== */ + void SRC_SetLeapStatus(SRC_Instance inst, NTP_Leap leap) { @@ -333,6 +365,9 @@ SRC_SetLeapStatus(SRC_Instance inst, NTP_Leap leap) return; inst->leap = leap; + + if (inst->leap_vote) + REF_UpdateLeapStatus(get_leap_status()); } /* ================================================== */ @@ -609,7 +644,7 @@ SRC_SelectSource(SRC_Instance updated_inst) int n_badstats_sources, max_sel_reach, max_sel_reach_size, max_badstat_reach; int depth, best_depth, trust_depth, best_trust_depth; int combined, stratum, min_stratum, max_score_index; - int orphan_stratum, orphan_source, leap_votes, leap_ins, leap_del; + int orphan_stratum, orphan_source; double src_offset, src_offset_sd, src_frequency, src_frequency_sd, src_skew; double src_root_delay, src_root_dispersion; double best_lo, best_hi, distance, sel_src_distance, max_score; @@ -692,6 +727,7 @@ SRC_SelectSource(SRC_Instance updated_inst) } sources[i]->status = SRC_OK; /* For now */ + sources[i]->leap_vote = 0; if (sources[i]->reachability && max_reach_sample_ago < first_sample_ago) max_reach_sample_ago = first_sample_ago; @@ -928,26 +964,15 @@ SRC_SelectSource(SRC_Instance updated_inst) return; } - /* Accept leap second status if more than half of selectable (and trusted - if there are any) sources agree */ - for (i = leap_ins = leap_del = leap_votes = 0; i < n_sel_sources; i++) { + /* Enable the selectable sources (and trusted if there are any) to + vote on leap seconds */ + for (i = 0; i < n_sel_sources; i++) { index = sel_sources[i]; if (best_trust_depth && !(sources[index]->sel_options & SRC_SELECT_TRUST)) continue; - leap_votes++; - if (sources[index]->leap == LEAP_InsertSecond) - leap_ins++; - else if (sources[index]->leap == LEAP_DeleteSecond) - leap_del++; + sources[index]->leap_vote = 1; } - if (leap_ins > leap_votes / 2) - leap_status = LEAP_InsertSecond; - else if (leap_del > leap_votes / 2) - leap_status = LEAP_DeleteSecond; - else - leap_status = LEAP_Normal; - /* If there are any sources with prefer option, reduce the list again only to the preferred sources */ for (i = 0; i < n_sel_sources; i++) { @@ -1079,6 +1104,8 @@ SRC_SelectSource(SRC_Instance updated_inst) for (i = 0; i < n_sources; i++) sources[i]->updates = 0; + leap_status = get_leap_status(); + /* Now just use the statistics of the selected source combined with the other selectable sources for trimming the local clock */