From: Juergen Perlinger Date: Thu, 7 Aug 2014 19:24:29 +0000 (+0200) Subject: [Bug 2622] Change SHM driver so TOY restricted API is not used any more. (Plus some... X-Git-Tag: NTP_4_2_7P457~2^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6a241993a897931e97c5b892ccf6074eed932825;p=thirdparty%2Fntp.git [Bug 2622] Change SHM driver so TOY restricted API is not used any more. (Plus some minor cleanup in logic and flow control) bk: 53e3d26dy94ZKDoyQSQVapJM81TCCg --- diff --git a/ChangeLog b/ChangeLog index c4bed5a4f..e576c14d9 100644 --- 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 * CID 739722: Change the way the extention and MAC fields are processed. (4.2.7p455) 2014/08/03 Released by Harlan Stenn diff --git a/ntpd/refclock_shm.c b/ntpd/refclock_shm.c index 49eed85ad..1a5eb8ff1 100644 --- a/ntpd/refclock_shm.c +++ b/ntpd/refclock_shm.c @@ -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++;