]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
util: add support for other NTP eras
authorMiroslav Lichvar <mlichvar@redhat.com>
Thu, 7 Aug 2014 15:08:19 +0000 (17:08 +0200)
committerMiroslav Lichvar <mlichvar@redhat.com>
Fri, 15 Aug 2014 09:18:40 +0000 (11:18 +0200)
NTP timestamps use only 32 bits to count seconds and the current NTP era
ends in 2036. Add support for converting NTP timestamps from other NTP
eras on systems with 64-bit time_t.

The earliest assumed NTP time is set by the configure script (by default
to 50 years before the date of the build) and earlier NTP timestamps
underflow to the following NTP era.

configure
ntp_core.c
util.c

index cde0e17f9fe41821f41af4db53352468ffde3906..e4dab64e730b7d1e091feafdc126caaef5e516cd 100755 (executable)
--- a/configure
+++ b/configure
@@ -114,6 +114,8 @@ For better control, use the options below.
   --disable-linuxcaps    Disable Linux capabilities support
   --disable-asyncdns     Disable asynchronous name resolving
   --disable-forcednsretry Don't retry on permanent DNS error
+  --with-ntp-era=SECONDS Specify earliest assumed NTP time in seconds
+                         since 1970-01-01 [50*365 days ago]
   --with-user=USER       Specify default chronyd user [root]
   --with-sendmail=PATH   Path to sendmail binary [/usr/lib/sendmail]
   --enable-debug         Enable debugging support
@@ -194,6 +196,7 @@ try_setsched=0
 try_lockmem=0
 feat_asyncdns=1
 feat_forcednsretry=1
+ntp_era_split=""
 default_user="root"
 mail_program="/usr/lib/sendmail"
 
@@ -275,6 +278,9 @@ do
     --disable-forcednsretry)
       feat_forcednsretry=0
     ;;
+    --with-ntp-era=* )
+      ntp_era_split=`echo $option | sed -e 's/^.*=//;'`
+    ;;
     --with-user=* )
       default_user=`echo $option | sed -e 's/^.*=//;'`
     ;;
@@ -381,6 +387,33 @@ if test_code '64-bit time_t' 'time.h' '' '' '
   return x[0];'
 then
   add_def HAVE_LONG_TIME_T 1
+
+  if [ "x$ntp_era_split" != "x" ]; then
+    split_seconds=$ntp_era_split
+    split_days=0
+  else
+    split_seconds=`date '+%s'`
+    if [ "x$split_seconds" = "" ]; then
+      echo "Could not get current time, --with-ntp-era option is needed"
+      exit 1
+    fi
+    split_days=$((50 * 365))
+  fi
+
+  add_def NTP_ERA_SPLIT "(${split_seconds}LL - $split_days * 24 * 3600)"
+
+  date_format='+%Y-%m-%dT%H:%M:%SZ'
+
+  # Print the full NTP interval if a suitable date is found
+  if [ "x`date -u -d '1970-01-01 UTC 9 days ago 5 seconds 3 seconds' \
+    $date_format 2> /dev/null`" = "x1969-12-23T00:00:08Z" ]
+  then
+    time1="`date -u -d "1970-01-01 UTC $split_days days ago $split_seconds seconds" \
+      $date_format`"
+    time2="`date -u -d "1970-01-01 UTC $split_days days ago $split_seconds seconds 4294967296 seconds" \
+      $date_format`"
+    echo "NTP time mapped to $time1/$time2"
+  fi
 fi
 
 MATHCODE='return (int) pow(2.0, log(sqrt((double)argc)));'
index c83f1e8b7e4ab61d46f2f6d7319671d3664b8450..278b8049cc997e4ef83c662a54336641887c8c98 100644 (file)
@@ -258,10 +258,35 @@ do_size_checks(void)
 
 /* ================================================== */
 
+static void
+do_time_checks(void)
+{
+#ifdef HAVE_LONG_TIME_T
+  /* Check that time before NTP_ERA_SPLIT underflows correctly */
+
+  struct timeval tv1 = {NTP_ERA_SPLIT, 1}, tv2 = {NTP_ERA_SPLIT - 1, 1};
+  NTP_int64 ntv1, ntv2;
+  int r;
+
+  UTI_TimevalToInt64(&tv1, &ntv1, 0);
+  UTI_TimevalToInt64(&tv2, &ntv2, 0);
+  UTI_Int64ToTimeval(&ntv1, &tv1);
+  UTI_Int64ToTimeval(&ntv2, &tv2);
+
+  r = tv1.tv_sec == NTP_ERA_SPLIT &&
+      tv1.tv_sec + (1ULL << 32) - 1 == tv2.tv_sec;
+
+  assert(r);
+#endif
+}
+
+/* ================================================== */
+
 void
 NCR_Initialise(void)
 {
   do_size_checks();
+  do_time_checks();
 
   logfileid = CNF_GetLogMeasurements() ? LOG_FileOpen("measurements",
       "   Date (UTC) Time     IP Address   L St 1234 abc 5678 LP RP Score Offset     Peer del. Peer disp. Root del.  Root disp.")
diff --git a/util.c b/util.c
index 35bc12bdddf2daa99f1cd3db142489d9df95e0db..e1d314e922be3bae32a6a69006fad535e9efd8bb 100644 (file)
--- a/util.c
+++ b/util.c
@@ -498,16 +498,17 @@ void
 UTI_TimevalToInt64(struct timeval *src,
                    NTP_int64 *dest, uint32_t fuzz)
 {
-  unsigned long usec = src->tv_usec;
-  unsigned long sec = src->tv_sec;
-  uint32_t lo;
+  uint32_t lo, sec, usec;
+
+  sec = (uint32_t)src->tv_sec;
+  usec = (uint32_t)src->tv_usec;
 
   /* Recognize zero as a special case - it always signifies
      an 'unknown' value */
   if (!usec && !sec) {
     dest->hi = dest->lo = 0;
   } else {
-    dest->hi = htonl(src->tv_sec + JAN_1970);
+    dest->hi = htonl(sec + JAN_1970);
 
     /* This formula gives an error of about 0.1us worst case */
     lo = 4295 * usec - (usec>>5) - (usec>>9);
@@ -525,13 +526,23 @@ void
 UTI_Int64ToTimeval(NTP_int64 *src,
                    struct timeval *dest)
 {
+  uint32_t ntp_sec, ntp_frac;
+
   /* As yet, there is no need to check for zero - all processing that
      has to detect that case is in the NTP layer */
 
-  dest->tv_sec = ntohl(src->hi) - JAN_1970;
+  ntp_sec = ntohl(src->hi);
+  ntp_frac = ntohl(src->lo);
+
+#ifdef HAVE_LONG_TIME_T
+  dest->tv_sec = ntp_sec - (uint32_t)(NTP_ERA_SPLIT + JAN_1970) +
+                 (time_t)NTP_ERA_SPLIT;
+#else
+  dest->tv_sec = ntp_sec - JAN_1970;
+#endif
   
   /* Until I invent a slick way to do this, just do it the obvious way */
-  dest->tv_usec = (int)(0.5 + (double)(ntohl(src->lo)) / 4294.967296);
+  dest->tv_usec = (int)(0.5 + (double)(ntp_frac) / 4294.967296);
 }
 
 /* ================================================== */