]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
Fix for NTP Epoch rollover
authorTerje Mathisen <terje@tmsw.no>
Tue, 6 Jan 2004 20:19:51 +0000 (21:19 +0100)
committerTerje Mathisen <terje@tmsw.no>
Tue, 6 Jan 2004 20:19:51 +0000 (21:19 +0100)
bk: 3ffb1867ckgqpJownT__I9NtajFayw

libntp/caljulian.c
libntp/humandate.c
libntp/prettydate.c

index c3b5e671fc5409213de79dc3964312934650c174..b8db27c2bf312bb432b3d76f932a424fd9a02b07 100644 (file)
@@ -24,6 +24,7 @@ static u_short calmonthtab[11] = {
        NOV
 };
 
+#if 0
 void
 caljulian(
        u_long                          ntptime,
@@ -113,3 +114,34 @@ caljulian(
        jt->monthday = (u_char) monthday;
        }
 }
+#else
+
+/* Updated 2003-12-30 TMa
+
+   Uses common code with the *prettydate functions to convert an ntp
+   seconds count into a calendar date.
+   Will handle ntp epoch wraparound as long as the underlying os/library 
+   does so for the unix epoch, i.e. works after 2038.
+*/
+
+struct tm * ntp2unix_tm(u_long ntp, int local);
+
+void
+caljulian(
+       u_long                          ntptime,
+       register struct calendar        *jt
+       )
+{
+       struct tm *tm;
+
+       tm = ntp2unix_tm(ntptime, 0);
+
+       jt->hour = (u_char) tm->tm_hour;
+       jt->minute = (u_char) tm->tm_min;
+       jt->month = (u_char) (tm->tm_mon + 1);
+       jt->monthday = (u_char) tm->tm_mday;
+       jt->second = (u_char) tm->tm_sec;
+       jt->year = (u_short) (tm->tm_year + 1900);
+       jt->yearday = (u_short) (tm->tm_yday + 1);  /* Assumes tm_yday starts with day 0! */
+}
+#endif
index 52f5af1661a9e1ac5d45c491d7dffa827c607029..2478fcc733f73d2d50d0543bcfa002db728b52ae 100644 (file)
@@ -15,6 +15,8 @@ static const char *days[] = {
        "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
 };
 
+struct tm * ntp2unix_tm(u_long ntp, int local);
+
 char *
 humandate(
        u_long ntptime
@@ -22,10 +24,8 @@ humandate(
 {
        char *bp;
        struct tm *tm;
-       time_t sec;
 
-       sec = ntptime - JAN_1970;
-       tm = localtime(&sec);
+       tm = ntp2unix_tm(ntptime, 1);
 
        if (!tm)
                return "--- --- -- ---- --:--:--";
@@ -48,8 +48,9 @@ humanlogtime(void)
 {
        char *bp;
        time_t cursec = time((time_t *) 0);
-       struct tm *tm = localtime(&cursec);
+       struct tm *tm;
        
+       tm = localtime(&cursec);
        if (!tm)
                return "-- --- --:--:--";
 
index 9710c84be173456c411cf3659662101dfebd6f45..ca96426768a78eb584915cff25fe66deca50e0b3 100644 (file)
@@ -17,6 +17,51 @@ static const char *days[] = {
   "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
 };
 
+/* Helper function to handle possible wraparound of the ntp epoch.
+
+   Works by assuming that the localtime/gmtime library functions 
+   have been updated so that they work
+*/
+
+#define MAX_EPOCH_NR 1000
+
+struct tm *
+ntp2unix_tm(
+       u_long ntp, int local
+       )
+{
+       time_t t, curr;
+       struct tm *tm;
+       int curr_year, epoch_nr;
+
+       /* First get the current year: */
+       curr = time(NULL);
+       tm = local ? localtime(&curr) : gmtime(&curr);
+       if (!tm) return NULL;
+
+       curr_year = 1900 + tm->tm_year;
+
+       /* Convert the ntp timestamp to a unix utc seconds count: */
+       t = (time_t) ntp - JAN_1970;
+
+       /* Check that the ntp timestamp is not before a 136 year window centered
+          around the current year:
+
+          Failsafe in case of an infinite loop:
+       Allow up to 1000 epochs of 136 years each!
+       */
+    for (epoch_nr = 0; epoch_nr < MAX_EPOCH_NR; epoch_nr++) {
+               tm = local ? localtime(&t) : gmtime(&t);
+
+               /* Check that the resulting year is in the correct epoch: */
+               if (1900 + tm->tm_year > curr_year - 68) break;
+
+               /* Epoch wraparound: Add 2^32 seconds! */
+               t += (time_t) 65536 << 16;
+       }
+       return tm;
+}
+
 char *
 prettydate(
        l_fp *ts
@@ -29,15 +74,20 @@ prettydate(
 
        LIB_GETBUF(bp);
        
-       sec = ts->l_ui - JAN_1970;
+       sec = ts->l_ui;
        msec = ts->l_uf / 4294967;      /* fract / (2 ** 32 / 1000) */
 
-       tm = localtime(&sec);
-
-       (void) sprintf(bp, "%08lx.%08lx  %s, %s %2d %4d %2d:%02d:%02d.%03lu",
+       tm = ntp2unix_tm(sec, 1);
+       if (!tm) {
+               (void) sprintf(bp, "%08lx.%08lx  --- --- -- ---- --:--:--",
+                      (u_long)ts->l_ui, (u_long)ts->l_uf);
+       }
+       else {
+               (void) sprintf(bp, "%08lx.%08lx  %s, %s %2d %4d %2d:%02d:%02d.%03lu",
                       (u_long)ts->l_ui, (u_long)ts->l_uf, days[tm->tm_wday],
                       months[tm->tm_mon], tm->tm_mday, 1900 + tm->tm_year,
                       tm->tm_hour,tm->tm_min, tm->tm_sec, msec);
+       }
        
        return bp;
 }
@@ -54,15 +104,20 @@ gmprettydate(
 
        LIB_GETBUF(bp);
        
-       sec = ts->l_ui - JAN_1970;
+       sec = ts->l_ui;
        msec = ts->l_uf / 4294967;      /* fract / (2 ** 32 / 1000) */
 
-       tm = gmtime(&sec);
-
-       (void) sprintf(bp, "%08lx.%08lx  %s, %s %2d %4d %2d:%02d:%02d.%03lu UTC",
+       tm = ntp2unix_tm(sec, 0);
+       if (!tm) {
+               (void) sprintf(bp, "%08lx.%08lx  --- --- -- ---- --:--:--",
+                      (u_long)ts->l_ui, (u_long)ts->l_uf);
+       }
+       else {
+               (void) sprintf(bp, "%08lx.%08lx  %s, %s %2d %4d %2d:%02d:%02d.%03lu",
                       (u_long)ts->l_ui, (u_long)ts->l_uf, days[tm->tm_wday],
                       months[tm->tm_mon], tm->tm_mday, 1900 + tm->tm_year,
                       tm->tm_hour,tm->tm_min, tm->tm_sec, msec);
-       
+       }
+
        return bp;
 }