]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
[Bug 2622] Change SHM driver so TOY restricted API is not used any more. (Plus some...
authorJuergen Perlinger <perlinger@ntp.org>
Thu, 7 Aug 2014 19:24:29 +0000 (21:24 +0200)
committerJuergen Perlinger <perlinger@ntp.org>
Thu, 7 Aug 2014 19:24:29 +0000 (21:24 +0200)
bk: 53e3d26dy94ZKDoyQSQVapJM81TCCg

ChangeLog
ntpd/refclock_shm.c

index c4bed5a4fb343777bf42df35c2ec9ec26203e872..e576c14d957871bb8e5288ffb8cda2456213d1a8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,6 @@
+* [Bug 2622] Synchronisation problem using SHM when time difference is
+  more than four hours: Change SHM driver so TOY restricted API is not
+  used any more. (Plus some minor cleanup in logic and flow control)
 (4.2.7p456) 2014/08/07 Released by Harlan Stenn <stenn@ntp.org>
 * CID 739722: Change the way the extention and MAC fields are processed.
 (4.2.7p455) 2014/08/03 Released by Harlan Stenn <stenn@ntp.org>
index 49eed85adfe0bced1d285058d8ba6af768b77bd7..1a5eb8ff1ad1e079e05cd3fb6044b34a05c9acea 100644 (file)
@@ -308,6 +308,18 @@ int shm_peek(
        struct shmunit *up;
        struct shmTime *shm;
 
+       struct timespec tvr;
+       struct timespec tvt;
+       unsigned int c;
+       int ok = 1;
+       unsigned cns_new, rns_new;
+       int cnt;
+
+       /* for formatting 'a_lastcode': */
+       struct calendar cd;
+       time_t tt;
+       vint64 ts;
+
        /*
         * This is the main routine. It snatches the time from the shm
         * board and tacks on a local timestamp.
@@ -325,113 +337,104 @@ int shm_peek(
                refclock_report(peer, CEVNT_FAULT);
                return 0;
        }
-       if (shm->valid) {
-               struct timespec tvr;
-               struct timespec tvt;
-               struct tm *t;
-               char timestr[20];       /* "%Y-%m-%dT%H:%M:%S" + 1 */
-               int c;
-               int ok = 1;
-               unsigned cns_new, rns_new;
-               int cnt;
-
-               tvr.tv_sec = 0;
-               tvr.tv_nsec = 0;
-               tvt.tv_sec = 0;
-               tvt.tv_nsec = 0;
-               switch (shm->mode) {
-                   case 0:
-                       tvr.tv_sec      = shm->receiveTimeStampSec;
-                       tvr.tv_nsec     = shm->receiveTimeStampUSec * 1000;
-                       rns_new         = shm->receiveTimeStampNSec;
-                       tvt.tv_sec      = shm->clockTimeStampSec;
-                       tvt.tv_nsec     = shm->clockTimeStampUSec * 1000;
-                       cns_new         = shm->clockTimeStampNSec;
-
-                       /* Since these comparisons are between unsigned
-                       ** variables they are always well defined, and any
-                       ** (signed) underflow will turn into very large
-                       ** unsigned values, well above the 1000 cutoff
-                       */
-                       if (   ((cns_new - (unsigned)tvt.tv_nsec) < 1000)
-                           && ((rns_new - (unsigned)tvr.tv_nsec) < 1000)) {
-                               tvt.tv_nsec = cns_new;
-                               tvr.tv_nsec = rns_new;
-                       }
-                       // At this point tvr and tvt contains valid ns-level
-                       // timestamps, possibly generated by extending the
-                       // old us-level timestamps
-
-                       break;
-
-                   case 1:
-                       cnt = shm->count;
-
-                       tvr.tv_sec      = shm->receiveTimeStampSec;
-                       tvr.tv_nsec     = shm->receiveTimeStampUSec * 1000;
-                       rns_new         = shm->receiveTimeStampNSec;
-                       tvt.tv_sec      = shm->clockTimeStampSec;
-                       tvt.tv_nsec     = shm->clockTimeStampUSec * 1000;
-                       cns_new         = shm->clockTimeStampNSec;
-                       ok = (cnt == shm->count);
-
-                       /* Since these comparisons are between unsigned
-                       ** variables they are always well defined, and any
-                       ** (signed) underflow will turn into very large
-                       ** unsigned values, well above the 1000 cutoff
-                       */
-                       if (   ((cns_new - (unsigned)tvt.tv_nsec) < 1000)
-                           && ((rns_new - (unsigned)tvr.tv_nsec) < 1000)) {
-                               tvt.tv_nsec = cns_new;
-                               tvr.tv_nsec = rns_new;
-                       }
-                       // At this point tvr and tvt contains valid ns-level
-                       // timestamps, possibly generated by extending the
-                       // old us-level timestamps
-
-                       break;
-
-                   default:
-                       msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d",shm->mode);
-                       return 0;
-               }
-
-               /* XXX NetBSD has incompatible tv_sec */
-               t = gmtime((const time_t *)&tvt.tv_sec);
-
-               /* add ntpq -c cv timecode in ISO 8601 format */
-               strftime(timestr, sizeof(timestr), "%Y-%m-%dT%H:%M:%S", t);
-               c = snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
-                            "%s.%09ldZ", timestr, (long)tvt.tv_nsec);
-               pp->lencode = (c < sizeof(pp->a_lastcode))
-                                ? c
-                                : 0;
-
-               shm->valid = 0;
-               if (ok) {
-                       pp->lastrec = tspec_stamp_to_lfp(tvr);
-                       pp->polls++;
-                       pp->day = t->tm_yday+1;
-                       pp->hour = t->tm_hour;
-                       pp->minute = t->tm_min;
-                       pp->second = t->tm_sec;
-                       pp->nsec = tvt.tv_nsec;
-                       peer->precision = shm->precision;
-                       pp->leap = shm->leap;
-               } else {
-                       refclock_report(peer, CEVNT_FAULT);
-                       msyslog (LOG_NOTICE, "SHM: access clash in shared memory");
-                       up->clash++;
-                       return 0;
-               }
-       } else {
-               refclock_report(peer, CEVNT_TIMEOUT);
+       if ( ! shm->valid) {
                up->notready++;
                return 0;
        }
-       if (!refclock_process(pp)) {
-               refclock_report(peer, CEVNT_BADTIME);
+
+       switch (shm->mode) {
+       case 0:
+               tvr.tv_sec      = shm->receiveTimeStampSec;
+               tvr.tv_nsec     = shm->receiveTimeStampUSec * 1000;
+               rns_new         = shm->receiveTimeStampNSec;
+               tvt.tv_sec      = shm->clockTimeStampSec;
+               tvt.tv_nsec     = shm->clockTimeStampUSec * 1000;
+               cns_new         = shm->clockTimeStampNSec;
+
+               /* Since the following comparisons are between unsigned
+               ** variables they are always well defined, and any
+               ** (signed) underflow will turn into very large unsigned
+               ** values, well above the 1000 cutoff.
+               **
+               ** Note: The usecs *must* be a *truncated*
+               ** representation of the nsecs. This code will fail for
+               ** *rounded* usecs, and the logic to deal with
+               ** wrap-arounds in the presence of rounded values is
+               ** much more convoluted.
+               */
+               if (   ((cns_new - (unsigned)tvt.tv_nsec) < 1000)
+                   && ((rns_new - (unsigned)tvr.tv_nsec) < 1000)) {
+                       tvt.tv_nsec = cns_new;
+                       tvr.tv_nsec = rns_new;
+               }
+               /* At this point tvr and tvt contains valid ns-level
+               ** timestamps, possibly generated by extending the old
+               ** us-level timestamps
+               */
+               break;
+
+       case 1:
+               cnt = shm->count;
+
+               tvr.tv_sec      = shm->receiveTimeStampSec;
+               tvr.tv_nsec     = shm->receiveTimeStampUSec * 1000;
+               rns_new         = shm->receiveTimeStampNSec;
+               tvt.tv_sec      = shm->clockTimeStampSec;
+               tvt.tv_nsec     = shm->clockTimeStampUSec * 1000;
+               cns_new         = shm->clockTimeStampNSec;
+               ok = (cnt == shm->count);
+               
+               /* See the case above for an explanation of the
+               ** following test.
+               */
+               if (   ((cns_new - (unsigned)tvt.tv_nsec) < 1000)
+                   && ((rns_new - (unsigned)tvr.tv_nsec) < 1000)) {
+                       tvt.tv_nsec = cns_new;
+                       tvr.tv_nsec = rns_new;
+               }
+               /* At this point tvr and tvt contains valid ns-level
+               ** timestamps, possibly generated by extending the old
+               ** us-level timestamps
+               */
+               break;
+
+       default:
                up->bad++;
+               msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d",
+                        shm->mode);
+               return 0;
+       }
+
+       /* format the last time code in human-readable form into
+        * 'pp->a_lastcode'. Someone claimed: "NetBSD has incompatible
+        * tv_sec". I can't find a base for this claim, but we can work
+        * around that potential problem. BTW, simply casting a pointer
+        * is a receipe for desaster on some architectures.
+        */
+       tt = (time_t)tvt.tv_sec;
+       ts = time_to_vint64(&tt);
+       ntpcal_time_to_date(&cd, &ts);
+               
+       /* add ntpq -c cv timecode in ISO 8601 format */
+       c = snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
+                    "%04u-%02u-%02uT%02u:%02u:%02u.%09ldZ",
+                    cd.year, cd.month, cd.monthday,
+                    cd.hour, cd.minute, cd.second,
+                    (long)tvt.tv_nsec);
+       pp->lencode = (c < sizeof(pp->a_lastcode)) ? c : 0;
+
+       shm->valid = 0;
+       if (ok) {
+               l_fp tsrcv = tspec_stamp_to_lfp(tvr);
+               l_fp tsref = tspec_stamp_to_lfp(tvt);
+               pp->polls++;
+               pp->leap = shm->leap;
+               peer->precision = shm->precision;
+               refclock_process_offset(pp, tsref, tsrcv, pp->fudgetime1);
+       } else {
+               refclock_report(peer, CEVNT_FAULT);
+               msyslog (LOG_NOTICE, "SHM: access clash in shared memory");
+               up->clash++;
                return 0;
        }
        up->good++;