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);
+ }
}
/* ================================================== */
/* ================================================== */
+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 */
LCL_ReadRawTime(&raw);
LCL_CookTime(&raw, &cooked, NULL);
+ if (!check_offset(&cooked, offset))
+ return;
+
(*drv_accrue_offset)(offset, corr_rate);
/* Dispatch to all handlers */
/* ================================================== */
-void
+int
LCL_ApplyStepOffset(double offset)
{
struct timeval raw, cooked;
LCL_ReadRawTime(&raw);
LCL_CookTime(&raw, &cooked, NULL);
+ if (!check_offset(&raw, offset))
+ return 0;
+
(*drv_apply_step_offset)(offset);
/* Reset smoothing on all clock steps */
/* Dispatch to all handlers */
invoke_parameter_change_handlers(&raw, &cooked, 0.0, offset, LCL_ChangeStep);
+
+ return 1;
}
/* ================================================== */
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
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);
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 */
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);
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);
}
}
/* 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");
/* ================================================== */
+/* 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)
{
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);