extern void peer_clear (struct peer *, const char *);
extern void process_packet (struct peer *, struct pkt *, u_int);
extern void clock_select (void);
+extern void set_sys_leap (u_char);
extern u_long leapsec; /* seconds to next leap (proximity class) */
extern int leapdif; /* TAI difference step at next leap second*/
extern u_long timer_timereset;
extern u_long timer_overflows;
extern u_long timer_xmtcalls;
+extern struct leap_smear_info leap_smear;
extern int leap_smear_intv;
#ifdef SYS_WINNT
HANDLE WaitableTimerHandle;
case T_Leapsmearinterval:
leap_smear_intv = curr_var->value.i;
+ msyslog(LOG_INFO, "config: leap smear interval %i s", leap_smear_intv);
break;
case T_Pidfile:
#define CS_TIMER_XMTS 87
#define CS_FUZZ 88
#define CS_WANDER_THRESH 89
-#define CS_MAX_NOAUTOKEY CS_WANDER_THRESH
+#define CS_LEAPSMEARINTV 90
+#define CS_LEAPSMEAROFFS 91
+#define CS_MAX_NOAUTOKEY CS_LEAPSMEAROFFS
#ifdef AUTOKEY
#define CS_FLAGS (1 + CS_MAX_NOAUTOKEY)
#define CS_HOST (2 + CS_MAX_NOAUTOKEY)
{ CS_TIMER_XMTS, RO, "timer_xmts" }, /* 87 */
{ CS_FUZZ, RO, "fuzz" }, /* 88 */
{ CS_WANDER_THRESH, RO, "clk_wander_threshold" }, /* 89 */
+ { CS_LEAPSMEARINTV, RO, "leapsmearinterval" }, /* 90 */
+ { CS_LEAPSMEAROFFS, RO, "leapsmearoffset" }, /* 91 */
#ifdef AUTOKEY
{ CS_FLAGS, RO, "flags" }, /* 1 + CS_MAX_NOAUTOKEY */
{ CS_HOST, RO, "host" }, /* 2 + CS_MAX_NOAUTOKEY */
CS_TAI,
CS_LEAPTAB,
CS_LEAPEND,
+ CS_LEAPSMEARINTV,
+ CS_LEAPSMEAROFFS,
#ifdef AUTOKEY
CS_HOST,
CS_IDENT,
break;
}
+ case CS_LEAPSMEARINTV:
+ if (leap_smear_intv > 0)
+ ctl_putuint(sys_var[CS_LEAPSMEARINTV].text, leap_smear_intv);
+ break;
+
+ case CS_LEAPSMEAROFFS:
+ if (leap_smear_intv > 0)
+ ctl_putdbl(sys_var[CS_LEAPSMEAROFFS].text,
+ leap_smear.doffset * 1e3);
+ break;
+
case CS_RATE:
ctl_putuint(sys_var[CS_RATE].text, ntp_minpoll);
break;
int enabled; /* not 0 if smearing is generally enabled */
int in_progress; /* not 0 if smearing is in progress, i.e. the offset has been computed */
int leap_occurred; /* not 0 if the leap second has already occurred, i.e., during the leap second */
+ double doffset; /* the current smear offset as double */
l_fp offset; /* the current smear offset */
uint32_t t_offset; /* the current time for which a smear offset has been computed */
long interval; /* smear interval, in [s], should be at least some hours */
* System variables are declared here. Unless specified otherwise, all
* times are in seconds.
*/
-u_char sys_leap; /* system leap indicator */
+u_char sys_leap; /* system leap indicator, use set_sys_leap() to change this */
+u_char xmt_leap; /* leap indicator sent in client requests, set up by set_sys_leap() */
u_char sys_stratum; /* system stratum */
s_char sys_precision; /* local clock precision (log2 s) */
double sys_rootdelay; /* roundtrip delay to primary source */
struct peer *sys_peer; /* current peer */
struct leap_smear_info leap_smear;
+int leap_sec_in_progress;
/*
* Rate controls. Leaky buckets are used to throttle the packet
const struct addrinfo *);
#endif /* WORKER */
+void
+set_sys_leap(u_char new_sys_leap) {
+ sys_leap = new_sys_leap;
+ xmt_leap = sys_leap;
+
+ /*
+ * Under certain conditions we send faked leap bits to clients, so
+ * eventually change xmt_leap below, but never change LEAP_NOTINSYNC.
+ */
+ if (xmt_leap != LEAP_NOTINSYNC) {
+ if (leap_sec_in_progress) {
+ /* always send "not sync" */
+ xmt_leap = LEAP_NOTINSYNC;
+ }
+ else {
+ /*
+ * If leap smear is enabled in general we must never send a leap second warning
+ * to clients, so make sure we only send "in sync".
+ */
+ if (leap_smear.enabled)
+ xmt_leap = LEAP_NOWARNING;
+ }
+ }
+}
+
/*
* transmit - transmit procedure called by poll timeout
*/
case 2:
clear_all();
- sys_leap = LEAP_NOTINSYNC;
+ set_sys_leap(LEAP_NOTINSYNC);
sys_stratum = STRATUM_UNSPEC;
memcpy(&sys_refid, "STEP", 4);
sys_rootdelay = 0;
* process.
*/
if (sys_leap == LEAP_NOTINSYNC) {
- sys_leap = LEAP_NOWARNING;
+ set_sys_leap(LEAP_NOWARNING);
#ifdef AUTOKEY
if (crypto_flags)
crypto_update();
osys_peer = sys_peer;
sys_survivors = 0;
#ifdef LOCKCLOCK
- sys_leap = LEAP_NOTINSYNC;
+ set_sys_leap(LEAP_NOTINSYNC);
sys_stratum = STRATUM_UNSPEC;
memcpy(&sys_refid, "DOWN", 4);
#endif /* LOCKCLOCK */
/*
* Make copies of the variables which can be affected by smearing.
*/
- int this_leap = sys_leap;
l_fp this_recv_time;
- /*
- * If leap smear is enabled in general we must never send a leap second warning
- * to clients, so make sure we only send "in sync" or "not in sync".
- */
- if (leap_smear.enabled)
- if (this_leap != LEAP_NOTINSYNC)
- this_leap = LEAP_NOWARNING;
/*
* If we are inside the leap smear interval we add the current smear offset to
* the packet receive time, to the packet transmit time, and eventually to the
* reftime to make sure the reftime isn't later than the transmit/receive times.
*/
- xpkt.li_vn_mode = PKT_LI_VN_MODE(this_leap,
+ xpkt.li_vn_mode = PKT_LI_VN_MODE(xmt_leap,
PKT_VERSION(rpkt->li_vn_mode), xmode);
xpkt.stratum = STRATUM_TO_PKT(sys_stratum);
xpkt.ppoll = max(rpkt->ppoll, ntp_minpoll);
* Fill in the sys_* stuff. Default is don't listen to
* broadcasting, require authentication.
*/
- sys_leap = LEAP_NOTINSYNC;
+ set_sys_leap(LEAP_NOTINSYNC);
sys_stratum = STRATUM_UNSPEC;
memcpy(&sys_refid, "INIT", 4);
sys_peer = NULL;
#endif
extern struct leap_smear_info leap_smear;
+extern int leap_sec_in_progress;
static void check_leapsec(u_int32, const time_t*, int/*BOOL*/);
}
+static void
+check_leap_sec_in_progress( const leap_result_t *lsdata ) {
+ int prv_leap_sec_in_progress = leap_sec_in_progress;
+ leap_sec_in_progress = lsdata->tai_diff && (lsdata->ddist < 3);
+
+ /* if changed we may have to update the leap status sent to clients */
+ if (leap_sec_in_progress != prv_leap_sec_in_progress)
+ set_sys_leap(sys_leap);
+}
+
+
static void
check_leapsec(
u_int32 now ,
leapsec_electric(0);
# endif
#endif
- leap_smear.enabled = 1; //##++ TODO this should depend on whether an interval has been specified in the config
+ leap_smear.enabled = leap_smear_intv != 0;
if (reset) {
lsprox = LSPROX_NOWARN;
if (leap_smear.enabled) {
if (lsdata.tai_diff) {
if (leap_smear.interval == 0) {
- leap_smear.interval = 120; // TODO set configured value
+ leap_smear.interval = leap_smear_intv;
leap_smear.intv_end = lsdata.ttime.Q_s;
leap_smear.intv_start = leap_smear.intv_end - leap_smear.interval;
DPRINTF(1, ("*** leapsec_query: setting leap_smear interval %li, begin %.0f, end %.0f\n",
if (leap_smear.interval) {
double dtemp = now;
if (dtemp >= leap_smear.intv_start && dtemp <= leap_smear.intv_end) {
+ double leap_smear_time = dtemp - leap_smear.intv_start;
/*
* For now we just do a linear interpolation over the smear interval
*/
- dtemp = -((dtemp - leap_smear.intv_start) * lsdata.tai_diff / leap_smear.interval);
+#if 0
+ // linear interpolation
+ leap_smear.doffset = -(leap_smear_time * lsdata.tai_diff / leap_smear.interval);
+#else
+ // Google approach: lie(t) = (1.0 - cos(pi * t / w)) / 2.0
+ leap_smear.doffset = -((double) lsdata.tai_diff - cos( M_PI * leap_smear_time / leap_smear.interval)) / 2.0;
+#endif
/*
* TODO see if we're inside an inserted leap second, so we need to compute
- * dtemp = 1.0 - dtemp
+ * leap_smear.doffset = 1.0 - leap_smear.doffset
*/
- DTOLFP(dtemp, &leap_smear.offset);
+ DTOLFP(leap_smear.doffset, &leap_smear.offset);
leap_smear.in_progress = 1;
DPRINTF(1, ("*** leapsec_query: [%.0f:%.0f], now %u, smear offset %.6f\n",
- leap_smear.intv_start, leap_smear.intv_end, now, dtemp));
+ leap_smear.intv_start, leap_smear.intv_end, now, leap_smear.doffset));
+#if 1 //##++++++++++++++
+ msyslog(LOG_NOTICE, "*** leapsec_query: [%.0f:%.0f] (%li), now %u (%.0f), smear offset %.6f\n",
+ leap_smear.intv_start, leap_smear.intv_end, leap_smear.interval,
+ now, leap_smear_time, leap_smear.doffset);
+#endif
+
}
}
}
+ else
+ leap_smear.interval = 0;
if (fired) {
/* Full hit. Eventually step the clock, but always
leapsec = lsprox;
}
- if (leapsec >= LSPROX_SCHEDULE)
- leapdif = lsdata.tai_diff;
- else
- leapdif = 0;
+ if (leapsec >= LSPROX_SCHEDULE)
+ leapdif = lsdata.tai_diff;
+ else
+ leapdif = 0;
+
+ check_leap_sec_in_progress(&lsdata);
+
#ifdef AUTOKEY
if (update_autokey)
crypto_update_taichange();