/* [internal] reload the table limits around the given time stamp. This * is where the real work is done when it comes to table lookup and * evaluation. Some care has been taken to have correct code for dealing * with boundary conditions and empty tables. * * In electric mode, transition and trip time are the same. In dumb * mode, the difference of the TAI offsets must be taken into account * and trip time and transition time become different. The difference * becomes the warping distance when the trip time is reached. */ static void reload_limits( leap_table_t * pt, const vint64 * ts) { int idx; /* Get full time and search the true lower bound. Use a * simple loop here, since the number of entries does * not warrant a binary search. This also works for an empty * table, so there is no shortcut for that case. */ for (idx = 0; idx != pt->head.size; idx++) if (ucmpv64(ts, &pt->info[idx].ttime) >= 0) break; /* get time limits with proper bound conditions. Note that the * bounds of the table will be observed even if the table is * empty -- no undefined condition must arise from this code. */ if (idx >= pt->head.size) { memset(&pt->head.ebase, 0x00, sizeof(vint64)); pt->head.this_tai = pt->head.base_tai; } else { pt->head.ebase = pt->info[idx].ttime; pt->head.this_tai = pt->info[idx].taiof; } if (--idx >= 0) { pt->head.next_tai = pt->info[idx].taiof; pt->head.dynls = pt->info[idx].dynls; pt->head.ttime = pt->info[idx].ttime; if (_electric) pt->head.dtime = pt->head.ttime; else pt->head.dtime = addv64i32( &pt->head.ttime, pt->head.next_tai - pt->head.this_tai); pt->head.stime = subv64u32( &pt->head.ttime, pt->info[idx].stime); } else { memset(&pt->head.ttime, 0xFF, sizeof(vint64)); pt->head.stime = pt->head.ttime; pt->head.dtime = pt->head.ttime; pt->head.next_tai = pt->head.this_tai; pt->head.dynls = 0; } }
int/*BOOL*/ leapsec_query( leap_result_t * qr , uint32_t ts32 , const time_t * pivot) { leap_table_t * pt; vint64 ts64, last, next; uint32_t due32; int fired; /* preset things we use later on... */ fired = FALSE; ts64 = ntpcal_ntp_to_ntp(ts32, pivot); pt = leapsec_get_table(FALSE); memset(qr, 0, sizeof(leap_result_t)); if (ucmpv64(&ts64, &pt->head.ebase) < 0) { /* Most likely after leap frame reset. Could also be a * backstep of the system clock. Anyway, get the new * leap era frame. */ reload_limits(pt, &ts64); } else if (ucmpv64(&ts64, &pt->head.dtime) >= 0) { /* Boundary crossed in forward direction. This might * indicate a leap transition, so we prepare for that * case. * * Some operations below are actually NOPs in electric * mode, but having only one code path that works for * both modes is easier to maintain. */ last = pt->head.ttime; qr->warped = (int16_t)(last.D_s.lo - pt->head.dtime.D_s.lo); next = addv64i32(&ts64, qr->warped); reload_limits(pt, &next); fired = ucmpv64(&pt->head.ebase, &last) == 0; if (fired) { ts64 = next; ts32 = next.D_s.lo; } else { qr->warped = 0; } } qr->tai_offs = pt->head.this_tai; /* If before the next scheduling alert, we're done. */ if (ucmpv64(&ts64, &pt->head.stime) < 0) return fired; /* now start to collect the remaing data */ due32 = pt->head.dtime.D_s.lo; qr->tai_diff = pt->head.next_tai - pt->head.this_tai; qr->ttime = pt->head.ttime; qr->ddist = due32 - ts32; qr->dynamic = pt->head.dynls; qr->proximity = LSPROX_SCHEDULE; /* if not in the last day before transition, we're done. */ if (!betweenu32(due32 - SECSPERDAY, ts32, due32)) return fired; qr->proximity = LSPROX_ANNOUNCE; if (!betweenu32(due32 - 10, ts32, due32)) return fired; /* The last 10s before the transition. Prepare for action! */ qr->proximity = LSPROX_ALERT; return fired; }
/* ------------------------------------------------------------------ */ int/*BOOL*/ leapsec_autokey_tai( int tai_offset, uint32_t ntpnow , const time_t * pivot ) { leap_table_t * pt; leap_era_t era; vint64 now64; int idx; (void)tai_offset; pt = leapsec_get_table(FALSE); /* Bail out if the basic offset is not zero and the putative * offset is bigger than 10s. That was in 1972 -- we don't want * to go back that far! */ if (pt->head.base_tai != 0 || tai_offset < 10) return FALSE; /* If there's already data in the table, check if an update is * possible. Update is impossible if there are static entries * (since this indicates a valid leapsecond file) or if we're * too close to a leapsecond transition: We do not know on what * side the transition the sender might have been, so we use a * dead zone around the transition. */ /* Check for static entries */ for (idx = 0; idx != pt->head.size; idx++) if ( ! pt->info[idx].dynls) return FALSE; /* get the fulll time stamp and leap era for it */ now64 = ntpcal_ntp_to_ntp(ntpnow, pivot); fetch_leap_era(&era, pt, &now64); /* check the limits with 20s dead band */ era.ebase = addv64i32(&era.ebase, 20); if (ucmpv64(&now64, &era.ebase) < 0) return FALSE; era.ttime = addv64i32(&era.ttime, -20); if (ucmpv64(&now64, &era.ttime) > 0) return FALSE; /* Here we can proceed. Calculate the delta update. */ tai_offset -= era.taiof; /* Shift the header info offsets. */ pt->head.base_tai += tai_offset; pt->head.this_tai += tai_offset; pt->head.next_tai += tai_offset; /* Shift table entry offsets (if any) */ for (idx = 0; idx != pt->head.size; idx++) pt->info[idx].taiof += tai_offset; /* claim success... */ return TRUE; }