// ---------------------------------------------------------------------- // add dynamic leap second (like from peer/clock) void test_addDynamic(void) { int rc; leap_result_t qr; static const uint32_t insns[] = { 2982009600u, // 29 # 1 Jul 1994 3029443200u, // 30 # 1 Jan 1996 3076704000u, // 31 # 1 Jul 1997 3124137600u, // 32 # 1 Jan 1999 3345062400u, // 33 # 1 Jan 2006 3439756800u, // 34 # 1 Jan 2009 3550089600u, // 35 # 1 Jul 2012 0 // sentinel }; rc = setup_load_table(leap2, FALSE); TEST_ASSERT_EQUAL(1, rc); leap_table_t * pt = leapsec_get_table(0); int idx; for (idx=1; insns[idx]; ++idx) { rc = leapsec_add_dyn(TRUE, insns[idx] - 20*SECSPERDAY - 100, NULL); TEST_ASSERT_EQUAL(TRUE, rc); } // try to slip in a previous entry rc = leapsec_add_dyn(TRUE, insns[0] - 20*SECSPERDAY - 100, NULL); TEST_ASSERT_EQUAL(FALSE, rc); //leapsec_dump(pt, (leapsec_dumper)fprintf, stdout); }
/* ------------------------------------------------------------------ */ int/*BOOL*/ leapsec_add_fix( int total, uint32_t ttime, uint32_t etime, const time_t * pivot) { time_t tpiv; leap_table_t * pt; vint64 tt64, et64; if (pivot == NULL) { time(&tpiv); pivot = &tpiv; } et64 = ntpcal_ntp_to_ntp(etime, pivot); tt64 = ntpcal_ntp_to_ntp(ttime, pivot); pt = leapsec_get_table(TRUE); if ( ucmpv64(&et64, &pt->head.expire) <= 0 || !leapsec_raw(pt, &tt64, total, FALSE) ) return FALSE; pt->lsig.etime = etime; pt->lsig.ttime = ttime; pt->lsig.taiof = (int16_t)total; pt->head.expire = et64; return leapsec_set_table(pt); }
/* ------------------------------------------------------------------ */ bool leapsec_add_fix( int total, uint32_t ttime, uint32_t etime, const time_t * pivot) { time_t tpiv; leap_table_t * pt; time64_t tt64, et64; if (pivot == NULL) { time(&tpiv); pivot = &tpiv; } et64 = ntpcal_ntp_to_ntp(etime, pivot); tt64 = ntpcal_ntp_to_ntp(ttime, pivot); pt = leapsec_get_table(true); if ((et64 <= pt->head.expire) || !leapsec_raw(pt, tt64, total, false) ) return false; pt->lsig.etime = etime; pt->lsig.ttime = ttime; pt->lsig.taiof = (int16_t)total; pt->head.expire = et64; return leapsec_set_table(pt); }
// ---------------------------------------------------------------------- // load file & check time-to-live TEST(leapsec, loadFileTTL) { const char *cp = leap1; int rc; leap_table_t * pt = leapsec_get_table(0); time_t pivot = 0x70000000; const uint32_t limit = 3610569600u; rc = leapsec_load(pt, stringreader, &cp, false) && leapsec_set_table(pt); TEST_ASSERT_EQUAL(1, rc); // exactly 1 day to live rc = leapsec_daystolive(limit - 86400, &pivot); TEST_ASSERT_EQUAL( 1, rc); // less than 1 day to live rc = leapsec_daystolive(limit - 86399, &pivot); TEST_ASSERT_EQUAL( 0, rc); // hit expiration exactly rc = leapsec_daystolive(limit, &pivot); TEST_ASSERT_EQUAL( 0, rc); // expired since 1 sec rc = leapsec_daystolive(limit + 1, &pivot); TEST_ASSERT_EQUAL(-1, rc); }
/* ------------------------------------------------------------------ */ void leapsec_getsig( leap_signature_t * psig) { const leap_table_t * pt; pt = leapsec_get_table(FALSE); memcpy(psig, &pt->lsig, sizeof(leap_signature_t)); }
static int/*BOOL*/ setup_clear_table(void) { int rc; leap_table_t * pt = leapsec_get_table(0); if (pt) leapsec_clear(pt); rc = leapsec_set_table(pt); return rc; }
static bool setup_clear_table(void) { bool rc; leap_table_t * pt = leapsec_get_table(0); if (pt) leapsec_clear(pt); rc = leapsec_set_table(pt); return rc; }
static int/*BOOL*/ setup_load_table( const char * cp, int blim) { int rc; leap_table_t * pt = leapsec_get_table(0); rc = (pt != NULL) && leapsec_load(pt, stringreader, &cp, blim); rc = rc && leapsec_set_table(pt); return rc; }
static bool setup_load_table( const char * cp, bool blim) { bool rc; leap_table_t * pt = leapsec_get_table(0); rc = (pt != NULL) && leapsec_load(pt, stringreader, &cp, blim); rc = rc && leapsec_set_table(pt); return rc; }
/* ------------------------------------------------------------------ */ int/*BOOL*/ leapsec_expired( uint32_t when, const time_t * tpiv) { const leap_table_t * pt; vint64 limit; pt = leapsec_get_table(FALSE); limit = ntpcal_ntp_to_ntp(when, tpiv); return ucmpv64(&limit, &pt->head.expire) >= 0; }
/* ------------------------------------------------------------------ */ bool leapsec_expired( uint32_t when, const time_t * tpiv) { const leap_table_t * pt; time64_t limit; pt = leapsec_get_table(false); limit = ntpcal_ntp_to_ntp(when, tpiv); return (limit >= pt->head.expire); }
/* ------------------------------------------------------------------ */ int32_t leapsec_daystolive( uint32_t when, const time_t * tpiv) { const leap_table_t * pt; vint64 limit; pt = leapsec_get_table(FALSE); limit = ntpcal_ntp_to_ntp(when, tpiv); limit = subv64(&pt->head.expire, &limit); return ntpcal_daysplit(&limit).hi; }
void test_loadFileExpire(void) { const char *cp = leap1; int rc; leap_table_t * pt = leapsec_get_table(0); rc = leapsec_load(pt, stringreader, &cp, FALSE) && leapsec_set_table(pt); TEST_ASSERT_EQUAL_MESSAGE(1, rc,"first"); rc = leapsec_expired(3439756800u, NULL); TEST_ASSERT_EQUAL(0, rc); rc = leapsec_expired(3610569601u, NULL); TEST_ASSERT_EQUAL(1, rc); }
// ---------------------------------------------------------------------- // load file & check expiration TEST(leapsec, loadFileExpire) { const char *cp = leap1; int rc; leap_table_t * pt = leapsec_get_table(0); rc = leapsec_load(pt, stringreader, &cp, false) && leapsec_set_table(pt); TEST_ASSERT_EQUAL(1, rc); rc = leapsec_expired(3439756800u, NULL); TEST_ASSERT_EQUAL(0, rc); rc = leapsec_expired(3610569601u, NULL); TEST_ASSERT_EQUAL(1, rc); }
/* ------------------------------------------------------------------ */ int32_t leapsec_daystolive( uint32_t when, const time_t * tpiv) { const leap_table_t * pt; time64_t limit; pt = leapsec_get_table(false); limit = ntpcal_ntp_to_ntp(when, tpiv); limit = pt->head.expire - limit; return ntpcal_daysplit(limit).hi; }
/* ------------------------------------------------------------------ */ int/*BOOL*/ leapsec_add_dyn( int insert, uint32_t ntpnow, const time_t * pivot ) { leap_table_t * pt; vint64 now64; pt = leapsec_get_table(TRUE); now64 = ntpcal_ntp_to_ntp(ntpnow, pivot); return ( leapsec_add(pt, &now64, (insert != 0)) && leapsec_set_table(pt)); }
/* ------------------------------------------------------------------ */ int/*BOOL*/ leapsec_query_era( leap_era_t * qr , uint32_t ntpts, const time_t * pivot) { const leap_table_t * pt; vint64 ts64; pt = leapsec_get_table(FALSE); ts64 = ntpcal_ntp_to_ntp(ntpts, pivot); fetch_leap_era(qr, pt, &ts64); return TRUE; }
/* ------------------------------------------------------------------ */ bool leapsec_add_dyn( bool insert, uint32_t ntpnow, const time_t * pivot ) { leap_table_t * pt; time64_t now64; pt = leapsec_get_table(true); now64 = ntpcal_ntp_to_ntp(ntpnow, pivot); return ( leapsec_add(pt, now64, insert) && leapsec_set_table(pt)); }
//#include "ntpdtest.h" #include "config.h" #include "ntp.h" #include "ntp_calendar.h" #include "ntp_stdlib.h" #include "ntp_leapsec.h" #include "unity.h" #include <string.h> #include "test-libntp.h" static const char leap1 [] = "#\n" "#@ 3610569600\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" " \t \n" "2571782400 20 # 1 Jul 1981\n" "2603318400 21 # 1 Jul 1982\n" "2634854400 22 # 1 Jul 1983\n" "2698012800 23 # 1 Jul 1985\n" "2776982400 24 # 1 Jan 1988\n" "2840140800 25 # 1 Jan 1990\n" "2871676800 26 # 1 Jan 1991\n" "2918937600 27 # 1 Jul 1992\n" "2950473600 28 # 1 Jul 1993\n" "2982009600 29 # 1 Jul 1994\n" "3029443200 30 # 1 Jan 1996\n" "3076704000 31 # 1 Jul 1997\n" "3124137600 32 # 1 Jan 1999\n" "3345062400 33 # 1 Jan 2006\n" "3439756800 34 # 1 Jan 2009\n" "3550089600 35 # 1 Jul 2012\n" "#\n" "#h dc2e6b0b 5aade95d a0587abd 4e0dacb4 e4d5049e\n" "#\n"; static const char leap2 [] = "#\n" "#@ 2950473700\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" "2571782400 20 # 1 Jul 1981\n" "2603318400 21 # 1 Jul 1982\n" "2634854400 22 # 1 Jul 1983\n" "2698012800 23 # 1 Jul 1985\n" "2776982400 24 # 1 Jan 1988\n" "2840140800 25 # 1 Jan 1990\n" "2871676800 26 # 1 Jan 1991\n" "2918937600 27 # 1 Jul 1992\n" "2950473600 28 # 1 Jul 1993\n" "#\n"; // Faked table with a leap second removal at 2009 static const char leap3 [] = "#\n" "#@ 3610569600\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" "2571782400 20 # 1 Jul 1981\n" "2603318400 21 # 1 Jul 1982\n" "2634854400 22 # 1 Jul 1983\n" "2698012800 23 # 1 Jul 1985\n" "2776982400 24 # 1 Jan 1988\n" "2840140800 25 # 1 Jan 1990\n" "2871676800 26 # 1 Jan 1991\n" "2918937600 27 # 1 Jul 1992\n" "2950473600 28 # 1 Jul 1993\n" "2982009600 29 # 1 Jul 1994\n" "3029443200 30 # 1 Jan 1996\n" "3076704000 31 # 1 Jul 1997\n" "3124137600 32 # 1 Jan 1999\n" "3345062400 33 # 1 Jan 2006\n" "3439756800 32 # 1 Jan 2009\n" "3550089600 33 # 1 Jul 2012\n" "#\n"; // short table with good hash static const char leap_ghash [] = "#\n" "#@ 3610569600\n" "#$ 3610566000\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" "#\n" "#h 4b304e10 95642b3f c10b91f9 90791725 25f280d0\n" "#\n"; // short table with bad hash static const char leap_bhash [] = "#\n" "#@ 3610569600\n" "#$ 3610566000\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" "#\n" "#h dc2e6b0b 5aade95d a0587abd 4e0dacb4 e4d5049e\n" "#\n"; // short table with malformed hash static const char leap_mhash [] = "#\n" "#@ 3610569600\n" "#$ 3610566000\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" "#\n" "#h f2349a02 788b9534 a8f2e141 f2029Q6d 4064a7ee\n" "#\n"; // short table with only 4 hash groups static const char leap_shash [] = "#\n" "#@ 3610569600\n" "#$ 3610566000\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" "#\n" "#h f2349a02 788b9534 a8f2e141 f2029Q6d\n" "#\n"; // table with good hash and truncated/missing leading zeros static const char leap_gthash [] = { "#\n" "#$ 3535228800\n" "#\n" "# Updated through IERS Bulletin C46\n" "# File expires on: 28 June 2014\n" "#\n" "#@ 3612902400\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" "2571782400 20 # 1 Jul 1981\n" "2603318400 21 # 1 Jul 1982\n" "2634854400 22 # 1 Jul 1983\n" "2698012800 23 # 1 Jul 1985\n" "2776982400 24 # 1 Jan 1988\n" "2840140800 25 # 1 Jan 1990\n" "2871676800 26 # 1 Jan 1991\n" "2918937600 27 # 1 Jul 1992\n" "2950473600 28 # 1 Jul 1993\n" "2982009600 29 # 1 Jul 1994\n" "3029443200 30 # 1 Jan 1996\n" "3076704000 31 # 1 Jul 1997\n" "3124137600 32 # 1 Jan 1999\n" "3345062400 33 # 1 Jan 2006\n" "3439756800 34 # 1 Jan 2009\n" "3550089600 35 # 1 Jul 2012\n" "#\n" "#h 1151a8f e85a5069 9000fcdb 3d5e5365 1d505b37" }; static const uint32_t lsec2006 = 3345062400u; // +33, 1 Jan 2006, 00:00:00 utc static const uint32_t lsec2009 = 3439756800u; // +34, 1 Jan 2009, 00:00:00 utc static const uint32_t lsec2012 = 3550089600u; // +35, 1 Jul 2012, 00:00:00 utc static const uint32_t lsec2015 = 3644697600u; // +36, 1 Jul 2015, 00:00:00 utc int stringreader(void* farg) { const char ** cpp = (const char**)farg; if (**cpp) return *(*cpp)++; else return EOF; } static int/*BOOL*/ setup_load_table( const char * cp, int blim) { int rc; leap_table_t * pt = leapsec_get_table(0); rc = (pt != NULL) && leapsec_load(pt, stringreader, &cp, blim); rc = rc && leapsec_set_table(pt); return rc; } static int/*BOOL*/ setup_clear_table(void) { int rc; leap_table_t * pt = leapsec_get_table(0); if (pt) leapsec_clear(pt); rc = leapsec_set_table(pt); return rc; } char * CalendarToString(const struct calendar cal) { char * ss = malloc (sizeof (char) * 100); char buffer[100] =""; sprintf(buffer, "%u", cal.year); strcat(ss,buffer); strcat(ss,"-"); sprintf(buffer, "%u", (u_int)cal.month); strcat(ss,buffer); strcat(ss,"-"); sprintf(buffer, "%u", (u_int)cal.monthday); strcat(ss,buffer); strcat(ss," ("); sprintf(buffer, "%u", (u_int) cal.yearday); strcat(ss,buffer); strcat(ss,") "); sprintf(buffer, "%u", (u_int)cal.hour); strcat(ss,buffer); strcat(ss,":"); sprintf(buffer, "%u", (u_int)cal.minute); strcat(ss,buffer); strcat(ss,":"); sprintf(buffer, "%u", (u_int)cal.second); strcat(ss,buffer); //ss << cal.year << "-" << (u_int)cal.month << "-" << (u_int)cal.monthday << " (" << cal.yearday << ") " << (u_int)cal.hour << ":" << (u_int)cal.minute << ":" << (u_int)cal.second; return ss; } int IsEqual(const struct calendar expected, const struct calendar actual) { if (expected.year == actual.year && (expected.yearday == actual.yearday || (expected.month == actual.month && expected.monthday == actual.monthday)) && expected.hour == actual.hour && expected.minute == actual.minute && expected.second == actual.second) { return TRUE; } else { printf("expected: %s but was %s", CalendarToString(expected) ,CalendarToString(actual)); return FALSE; } } //------------------------- void setUp(void) { ntpcal_set_timefunc(timefunc); settime(1970, 1, 1, 0, 0, 0); leapsec_ut_pristine(); } void tearDown(void) { ntpcal_set_timefunc(NULL); } // ===================================================================== // VALIDATION TESTS // ===================================================================== // ---------------------------------------------------------------------- void test_ValidateGood(void) { const char *cp = leap_ghash; int rc = leapsec_validate(stringreader, &cp); TEST_ASSERT_EQUAL(LSVALID_GOODHASH, rc); } // ---------------------------------------------------------------------- void test_ValidateNoHash(void) { const char *cp = leap2; int rc = leapsec_validate(stringreader, &cp); TEST_ASSERT_EQUAL(LSVALID_NOHASH, rc); } // ---------------------------------------------------------------------- void test_ValidateBad(void) { const char *cp = leap_bhash; int rc = leapsec_validate(stringreader, &cp); TEST_ASSERT_EQUAL(LSVALID_BADHASH, rc); } // ---------------------------------------------------------------------- void test_ValidateMalformed(void) { const char *cp = leap_mhash; int rc = leapsec_validate(stringreader, &cp); TEST_ASSERT_EQUAL(LSVALID_BADFORMAT, rc); } // ---------------------------------------------------------------------- void test_ValidateMalformedShort(void) { const char *cp = leap_shash; int rc = leapsec_validate(stringreader, &cp); TEST_ASSERT_EQUAL(LSVALID_BADFORMAT, rc); } // ---------------------------------------------------------------------- void test_ValidateNoLeadZero(void) { const char *cp = leap_gthash; int rc = leapsec_validate(stringreader, &cp); TEST_ASSERT_EQUAL(LSVALID_GOODHASH, rc); } // ===================================================================== // BASIC FUNCTIONS // ===================================================================== // ---------------------------------------------------------------------- // test table selection void test_tableSelect(void) { leap_table_t *pt1, *pt2, *pt3, *pt4; pt1 = leapsec_get_table(0); pt2 = leapsec_get_table(0); TEST_ASSERT_EQUAL_MESSAGE(pt1, pt2,"first"); pt1 = leapsec_get_table(1); pt2 = leapsec_get_table(1); TEST_ASSERT_EQUAL_MESSAGE(pt1, pt2,"second"); pt1 = leapsec_get_table(1); pt2 = leapsec_get_table(0); TEST_ASSERT_NOT_EQUAL(pt1, pt2); pt1 = leapsec_get_table(0); pt2 = leapsec_get_table(1); TEST_ASSERT_NOT_EQUAL(pt1, pt2); leapsec_set_table(pt1); pt2 = leapsec_get_table(0); pt3 = leapsec_get_table(1); TEST_ASSERT_EQUAL(pt1, pt2); TEST_ASSERT_NOT_EQUAL(pt2, pt3); pt1 = pt3; leapsec_set_table(pt1); pt2 = leapsec_get_table(0); pt3 = leapsec_get_table(1); TEST_ASSERT_EQUAL(pt1, pt2); TEST_ASSERT_NOT_EQUAL(pt2, pt3); } // ---------------------------------------------------------------------- // load file & check expiration void test_loadFileExpire(void) { const char *cp = leap1; int rc; leap_table_t * pt = leapsec_get_table(0); rc = leapsec_load(pt, stringreader, &cp, FALSE) && leapsec_set_table(pt); TEST_ASSERT_EQUAL_MESSAGE(1, rc,"first"); rc = leapsec_expired(3439756800u, NULL); TEST_ASSERT_EQUAL(0, rc); rc = leapsec_expired(3610569601u, NULL); TEST_ASSERT_EQUAL(1, rc); } // ---------------------------------------------------------------------- // load file & check time-to-live void test_loadFileTTL(void) { const char *cp = leap1; int rc; leap_table_t * pt = leapsec_get_table(0); time_t pivot = 0x70000000u; const uint32_t limit = 3610569600u; rc = leapsec_load(pt, stringreader, &cp, FALSE) && leapsec_set_table(pt); TEST_ASSERT_EQUAL(1, rc); // // exactly 1 day to live rc = leapsec_daystolive(limit - 86400, &pivot); TEST_ASSERT_EQUAL( 1, rc); // less than 1 day to live rc = leapsec_daystolive(limit - 86399, &pivot); TEST_ASSERT_EQUAL( 0, rc); // hit expiration exactly rc = leapsec_daystolive(limit, &pivot); TEST_ASSERT_EQUAL( 0, rc); // expired since 1 sec rc = leapsec_daystolive(limit + 1, &pivot); TEST_ASSERT_EQUAL(-1, rc); } // ===================================================================== // RANDOM QUERY TESTS // ===================================================================== // ---------------------------------------------------------------------- // test query in pristine state (bug#2745 misbehaviour) void test_lsQueryPristineState(void) { int rc; leap_result_t qr; rc = leapsec_query(&qr, lsec2012, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_EQUAL(0, qr.warped ); TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity); } // ---------------------------------------------------------------------- // ad-hoc jump: leap second at 2009.01.01 -60days void test_ls2009faraway(void) { int rc; leap_result_t qr; rc = setup_load_table(leap1,FALSE); TEST_ASSERT_EQUAL(1, rc); // test 60 days before leap. Nothing scheduled or indicated. rc = leapsec_query(&qr, lsec2009 - 60*SECSPERDAY, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_EQUAL(33, qr.tai_offs); TEST_ASSERT_EQUAL(0, qr.tai_diff); TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity); } // ---------------------------------------------------------------------- // ad-hoc jump: leap second at 2009.01.01 -1week void test_ls2009weekaway(void) { int rc; leap_result_t qr; rc = setup_load_table(leap1,FALSE); TEST_ASSERT_EQUAL(1, rc); // test 7 days before leap. Leap scheduled, but not yet indicated. rc = leapsec_query(&qr, lsec2009 - 7*SECSPERDAY, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_EQUAL(33, qr.tai_offs); TEST_ASSERT_EQUAL(1, qr.tai_diff); TEST_ASSERT_EQUAL(LSPROX_SCHEDULE, qr.proximity); } // ---------------------------------------------------------------------- // ad-hoc jump: leap second at 2009.01.01 -1hr void test_ls2009houraway(void) { int rc; leap_result_t qr; rc = setup_load_table(leap1,FALSE); TEST_ASSERT_EQUAL(1, rc); // test 1 hour before leap. 61 true seconds to go. rc = leapsec_query(&qr, lsec2009 - SECSPERHR, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_EQUAL(33, qr.tai_offs); TEST_ASSERT_EQUAL(1, qr.tai_diff); TEST_ASSERT_EQUAL(LSPROX_ANNOUNCE, qr.proximity); } // ---------------------------------------------------------------------- // ad-hoc jump: leap second at 2009.01.01 -1sec void test_ls2009secaway(void) { int rc; leap_result_t qr; rc = setup_load_table(leap1,FALSE); TEST_ASSERT_EQUAL(1, rc); // test 1 second before leap (last boundary...) 2 true seconds to go. rc = leapsec_query(&qr, lsec2009 - 1, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_EQUAL(33, qr.tai_offs); TEST_ASSERT_EQUAL(1, qr.tai_diff); TEST_ASSERT_EQUAL(LSPROX_ALERT, qr.proximity); } // ---------------------------------------------------------------------- // ad-hoc jump to leap second at 2009.01.01 void test_ls2009onspot(void) { int rc; leap_result_t qr; rc = setup_load_table(leap1,FALSE); TEST_ASSERT_EQUAL(1, rc); // test on-spot: treat leap second as already gone. rc = leapsec_query(&qr, lsec2009, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_EQUAL(34, qr.tai_offs); TEST_ASSERT_EQUAL(0, qr.tai_diff); TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity); } // ---------------------------------------------------------------------- // test handling of the leap second at 2009.01.01 without table void test_ls2009nodata(void) { int rc; leap_result_t qr; rc = setup_clear_table(); TEST_ASSERT_EQUAL(1, rc); // test on-spot with empty table rc = leapsec_query(&qr, lsec2009, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_EQUAL(0, qr.tai_offs); TEST_ASSERT_EQUAL(0, qr.tai_diff); TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity); } // ---------------------------------------------------------------------- // test handling of the leap second at 2009.01.01 with culled data void test_ls2009limdata(void) { int rc; leap_result_t qr; rc = setup_load_table(leap1, TRUE); TEST_ASSERT_EQUAL(1, rc); // test on-spot with limited table - this is tricky. // The table used ends 2012; depending on the build date, the 2009 entry // might be included or culled. The resulting TAI offset must be either // 34 or 35 seconds, depending on the build date of the test. rc = leapsec_query(&qr, lsec2009, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_TRUE(34 <= qr.tai_offs); TEST_ASSERT_TRUE(35 >= qr.tai_offs); TEST_ASSERT_EQUAL(0, qr.tai_diff); TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity); } // ---------------------------------------------------------------------- // Far-distance forward jump into a transiton window. void test_qryJumpFarAhead(void) { int rc; leap_result_t qr; int last, idx; int mode; for (mode=0; mode < 2; ++mode) { leapsec_ut_pristine(); rc = setup_load_table(leap1, FALSE); TEST_ASSERT_EQUAL(1, rc); leapsec_electric(mode); rc = leapsec_query(&qr, lsec2006, NULL); TEST_ASSERT_EQUAL(FALSE, rc); rc = leapsec_query(&qr, lsec2012, NULL); TEST_ASSERT_EQUAL(FALSE, rc); } } // ---------------------------------------------------------------------- // Forward jump into the next transition window void test_qryJumpAheadToTransition(void) { int rc; leap_result_t qr; int last, idx; int mode; for (mode=0; mode < 2; ++mode) { leapsec_ut_pristine(); rc = setup_load_table(leap1, FALSE); TEST_ASSERT_EQUAL(1, rc); leapsec_electric(mode); rc = leapsec_query(&qr, lsec2009-SECSPERDAY, NULL); TEST_ASSERT_EQUAL(FALSE, rc); rc = leapsec_query(&qr, lsec2009+1, NULL); TEST_ASSERT_EQUAL(TRUE, rc); } } // ---------------------------------------------------------------------- // Forward jump over the next transition window void test_qryJumpAheadOverTransition(void) { int rc; leap_result_t qr; int last, idx; int mode; for (mode=0; mode < 2; ++mode) { leapsec_ut_pristine(); rc = setup_load_table(leap1, FALSE); TEST_ASSERT_EQUAL(1, rc); leapsec_electric(mode); rc = leapsec_query(&qr, lsec2009-SECSPERDAY, NULL); TEST_ASSERT_EQUAL(FALSE, rc); rc = leapsec_query(&qr, lsec2009+5, NULL); TEST_ASSERT_EQUAL(FALSE, rc); } } // ===================================================================== // TABLE MODIFICATION AT RUNTIME // ===================================================================== // ---------------------------------------------------------------------- // add dynamic leap second (like from peer/clock) void test_addDynamic(void) { int rc; leap_result_t qr; static const uint32_t insns[] = { 2982009600u, // 29 # 1 Jul 1994 3029443200u, // 30 # 1 Jan 1996 3076704000u, // 31 # 1 Jul 1997 3124137600u, // 32 # 1 Jan 1999 3345062400u, // 33 # 1 Jan 2006 3439756800u, // 34 # 1 Jan 2009 3550089600u, // 35 # 1 Jul 2012 0 // sentinel }; rc = setup_load_table(leap2, FALSE); TEST_ASSERT_EQUAL(1, rc); leap_table_t * pt = leapsec_get_table(0); int idx; for (idx=1; insns[idx]; ++idx) { rc = leapsec_add_dyn(TRUE, insns[idx] - 20*SECSPERDAY - 100, NULL); TEST_ASSERT_EQUAL(TRUE, rc); } // try to slip in a previous entry rc = leapsec_add_dyn(TRUE, insns[0] - 20*SECSPERDAY - 100, NULL); TEST_ASSERT_EQUAL(FALSE, rc); //leapsec_dump(pt, (leapsec_dumper)fprintf, stdout); } // ---------------------------------------------------------------------- // add fixed leap seconds (like from network packet) #if 0 /* currently unused -- possibly revived later */ void FAILtest_addFixed(void) { int rc; leap_result_t qr; static const struct { uint32_t tt; int of; } insns[] = { {2982009600u, 29},// # 1 Jul 1994 {3029443200u, 30},// # 1 Jan 1996 {3076704000u, 31},// # 1 Jul 1997 {3124137600u, 32},// # 1 Jan 1999 {3345062400u, 33},// # 1 Jan 2006 {3439756800u, 34},// # 1 Jan 2009 {3550089600u, 35},// # 1 Jul 2012 {0,0} // sentinel }; rc = setup_load_table(leap2, FALSE); TEST_ASSERT_EQUAL(1, rc); int idx; leap_table_t * pt = leapsec_get_table(0); // try to get in BAD time stamps... for (idx=0; insns[idx].tt; ++idx) { rc = leapsec_add_fix( insns[idx].of, insns[idx].tt - 20*SECSPERDAY - 100, insns[idx].tt + SECSPERDAY, NULL); TEST_ASSERT_EQUAL(FALSE, rc); } // now do it right for (idx=0; insns[idx].tt; ++idx) { rc = leapsec_add_fix( insns[idx].of, insns[idx].tt, insns[idx].tt + SECSPERDAY, NULL); TEST_ASSERT_EQUAL(TRUE, rc); } // try to slip in a previous entry rc = leapsec_add_fix( insns[0].of, insns[0].tt, insns[0].tt + SECSPERDAY, NULL); TEST_ASSERT_EQUAL(FALSE, rc); //leapsec_dump(pt, (leapsec_dumper)fprintf, stdout); }
/* ------------------------------------------------------------------ */ int/*BOOL*/ leapsec_frame( leap_result_t *qr) { const leap_table_t * pt; memset(qr, 0, sizeof(leap_result_t)); pt = leapsec_get_table(FALSE); qr->tai_offs = pt->head.this_tai; qr->tai_diff = pt->head.next_tai - pt->head.this_tai; qr->ebase = pt->head.ebase; qr->ttime = pt->head.ttime; qr->dynamic = pt->head.dynls; return ucmpv64(&pt->head.ttime, &pt->head.stime) >= 0; }
/* ------------------------------------------------------------------ */ bool leapsec_frame( leap_result_t *qr) { const leap_table_t * pt; memset(qr, 0, sizeof(leap_result_t)); pt = leapsec_get_table(false); if (pt->head.ttime <= pt->head.stime) return false; qr->tai_offs = pt->head.this_tai; qr->tai_diff = pt->head.next_tai - pt->head.this_tai; qr->ttime = pt->head.ttime; qr->dynamic = pt->head.dynls; return true; }
//#include "ntpdtest.h" #include "config.h" #include "ntp.h" #include "ntp_calendar.h" #include "ntp_stdlib.h" #include "ntp_leapsec.h" #include "unity.h" #include <string.h> #include "test-libntp.h" static const char leap1 [] = "#\n" "#@ 3610569600\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" " \t \n" "2571782400 20 # 1 Jul 1981\n" "2603318400 21 # 1 Jul 1982\n" "2634854400 22 # 1 Jul 1983\n" "2698012800 23 # 1 Jul 1985\n" "2776982400 24 # 1 Jan 1988\n" "2840140800 25 # 1 Jan 1990\n" "2871676800 26 # 1 Jan 1991\n" "2918937600 27 # 1 Jul 1992\n" "2950473600 28 # 1 Jul 1993\n" "2982009600 29 # 1 Jul 1994\n" "3029443200 30 # 1 Jan 1996\n" "3076704000 31 # 1 Jul 1997\n" "3124137600 32 # 1 Jan 1999\n" "3345062400 33 # 1 Jan 2006\n" "3439756800 34 # 1 Jan 2009\n" "3550089600 35 # 1 Jul 2012\n" "#\n" "#h dc2e6b0b 5aade95d a0587abd 4e0dacb4 e4d5049e\n" "#\n"; static const char leap2 [] = "#\n" "#@ 2950473700\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" "2571782400 20 # 1 Jul 1981\n" "2603318400 21 # 1 Jul 1982\n" "2634854400 22 # 1 Jul 1983\n" "2698012800 23 # 1 Jul 1985\n" "2776982400 24 # 1 Jan 1988\n" "2840140800 25 # 1 Jan 1990\n" "2871676800 26 # 1 Jan 1991\n" "2918937600 27 # 1 Jul 1992\n" "2950473600 28 # 1 Jul 1993\n" "#\n"; // Faked table with a leap second removal at 2009 static const char leap3 [] = "#\n" "#@ 3610569600\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" "2571782400 20 # 1 Jul 1981\n" "2603318400 21 # 1 Jul 1982\n" "2634854400 22 # 1 Jul 1983\n" "2698012800 23 # 1 Jul 1985\n" "2776982400 24 # 1 Jan 1988\n" "2840140800 25 # 1 Jan 1990\n" "2871676800 26 # 1 Jan 1991\n" "2918937600 27 # 1 Jul 1992\n" "2950473600 28 # 1 Jul 1993\n" "2982009600 29 # 1 Jul 1994\n" "3029443200 30 # 1 Jan 1996\n" "3076704000 31 # 1 Jul 1997\n" "3124137600 32 # 1 Jan 1999\n" "3345062400 33 # 1 Jan 2006\n" "3439756800 32 # 1 Jan 2009\n" "3550089600 33 # 1 Jul 2012\n" "#\n"; // short table with good hash static const char leap_ghash [] = "#\n" "#@ 3610569600\n" "#$ 3610566000\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" "#\n" "#h 4b304e10 95642b3f c10b91f9 90791725 25f280d0\n" "#\n"; // short table with bad hash static const char leap_bhash [] = "#\n" "#@ 3610569600\n" "#$ 3610566000\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" "#\n" "#h dc2e6b0b 5aade95d a0587abd 4e0dacb4 e4d5049e\n" "#\n"; // short table with malformed hash static const char leap_mhash [] = "#\n" "#@ 3610569600\n" "#$ 3610566000\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" "#\n" "#h f2349a02 788b9534 a8f2e141 f2029Q6d 4064a7ee\n" "#\n"; // short table with only 4 hash groups static const char leap_shash [] = "#\n" "#@ 3610569600\n" "#$ 3610566000\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" "#\n" "#h f2349a02 788b9534 a8f2e141 f2029Q6d\n" "#\n"; // table with good hash and truncated/missing leading zeros static const char leap_gthash [] = { "#\n" "#$ 3535228800\n" "#\n" "# Updated through IERS Bulletin C46\n" "# File expires on: 28 June 2014\n" "#\n" "#@ 3612902400\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" "2571782400 20 # 1 Jul 1981\n" "2603318400 21 # 1 Jul 1982\n" "2634854400 22 # 1 Jul 1983\n" "2698012800 23 # 1 Jul 1985\n" "2776982400 24 # 1 Jan 1988\n" "2840140800 25 # 1 Jan 1990\n" "2871676800 26 # 1 Jan 1991\n" "2918937600 27 # 1 Jul 1992\n" "2950473600 28 # 1 Jul 1993\n" "2982009600 29 # 1 Jul 1994\n" "3029443200 30 # 1 Jan 1996\n" "3076704000 31 # 1 Jul 1997\n" "3124137600 32 # 1 Jan 1999\n" "3345062400 33 # 1 Jan 2006\n" "3439756800 34 # 1 Jan 2009\n" "3550089600 35 # 1 Jul 2012\n" "#\n" "#h 1151a8f e85a5069 9000fcdb 3d5e5365 1d505b37" }; static const uint32_t lsec2006 = 3345062400u; // +33, 1 Jan 2006, 00:00:00 utc static const uint32_t lsec2009 = 3439756800u; // +34, 1 Jan 2009, 00:00:00 utc static const uint32_t lsec2012 = 3550089600u; // +35, 1 Jul 2012, 00:00:00 utc static const uint32_t lsec2015 = 3644697600u; // +36, 1 Jul 2015, 00:00:00 utc int stringreader(void* farg) { const char ** cpp = (const char**)farg; if (**cpp) return *(*cpp)++; else return EOF; } static int/*BOOL*/ setup_load_table( const char * cp, int blim) { int rc; leap_table_t * pt = leapsec_get_table(0); rc = (pt != NULL) && leapsec_load(pt, stringreader, &cp, blim); rc = rc && leapsec_set_table(pt); return rc; } static int/*BOOL*/ setup_clear_table(void) { int rc; leap_table_t * pt = leapsec_get_table(0); if (pt) leapsec_clear(pt); rc = leapsec_set_table(pt); return rc; } char * CalendarToString(const struct calendar cal) { char * ss = malloc (sizeof (char) * 100); char buffer[100] =""; sprintf(buffer, "%u", cal.year); strcat(ss,buffer); strcat(ss,"-"); sprintf(buffer, "%u", (u_int)cal.month); strcat(ss,buffer); strcat(ss,"-"); sprintf(buffer, "%u", (u_int)cal.monthday); strcat(ss,buffer); strcat(ss," ("); sprintf(buffer, "%u", (u_int) cal.yearday); strcat(ss,buffer); strcat(ss,") "); sprintf(buffer, "%u", (u_int)cal.hour); strcat(ss,buffer); strcat(ss,":"); sprintf(buffer, "%u", (u_int)cal.minute); strcat(ss,buffer); strcat(ss,":"); sprintf(buffer, "%u", (u_int)cal.second); strcat(ss,buffer); //ss << cal.year << "-" << (u_int)cal.month << "-" << (u_int)cal.monthday << " (" << cal.yearday << ") " << (u_int)cal.hour << ":" << (u_int)cal.minute << ":" << (u_int)cal.second; return ss; } int IsEqual(const struct calendar expected, const struct calendar actual) { if (expected.year == actual.year && (expected.yearday == actual.yearday || (expected.month == actual.month && expected.monthday == actual.monthday)) && expected.hour == actual.hour && expected.minute == actual.minute && expected.second == actual.second) { return TRUE; } else { printf("expected: %s but was %s", CalendarToString(expected) ,CalendarToString(actual)); return FALSE; } } //------------------------- void setUp(void) { ntpcal_set_timefunc(timefunc); settime(1970, 1, 1, 0, 0, 0); leapsec_ut_pristine(); } void tearDown(void) { ntpcal_set_timefunc(NULL); } // ===================================================================== // VALIDATION TESTS // ===================================================================== // ---------------------------------------------------------------------- void test_ValidateGood(void) { const char *cp = leap_ghash; int rc = leapsec_validate(stringreader, &cp); TEST_ASSERT_EQUAL(LSVALID_GOODHASH, rc); } // ---------------------------------------------------------------------- void test_ValidateNoHash(void) { const char *cp = leap2; int rc = leapsec_validate(stringreader, &cp); TEST_ASSERT_EQUAL(LSVALID_NOHASH, rc); } // ---------------------------------------------------------------------- void test_ValidateBad(void) { const char *cp = leap_bhash; int rc = leapsec_validate(stringreader, &cp); TEST_ASSERT_EQUAL(LSVALID_BADHASH, rc); } // ---------------------------------------------------------------------- void test_ValidateMalformed(void) { const char *cp = leap_mhash; int rc = leapsec_validate(stringreader, &cp); TEST_ASSERT_EQUAL(LSVALID_BADFORMAT, rc); } // ---------------------------------------------------------------------- void test_ValidateMalformedShort(void) { const char *cp = leap_shash; int rc = leapsec_validate(stringreader, &cp); TEST_ASSERT_EQUAL(LSVALID_BADFORMAT, rc); } // ---------------------------------------------------------------------- void test_ValidateNoLeadZero(void) { const char *cp = leap_gthash; int rc = leapsec_validate(stringreader, &cp); TEST_ASSERT_EQUAL(LSVALID_GOODHASH, rc); } // ===================================================================== // BASIC FUNCTIONS // ===================================================================== // ---------------------------------------------------------------------- // test table selection void test_tableSelect(void) { leap_table_t *pt1, *pt2, *pt3, *pt4; pt1 = leapsec_get_table(0); pt2 = leapsec_get_table(0); TEST_ASSERT_EQUAL_MESSAGE(pt1, pt2,"first"); pt1 = leapsec_get_table(1); pt2 = leapsec_get_table(1); TEST_ASSERT_EQUAL_MESSAGE(pt1, pt2,"second"); pt1 = leapsec_get_table(1); pt2 = leapsec_get_table(0); TEST_ASSERT_NOT_EQUAL(pt1, pt2); pt1 = leapsec_get_table(0); pt2 = leapsec_get_table(1); TEST_ASSERT_NOT_EQUAL(pt1, pt2); leapsec_set_table(pt1); pt2 = leapsec_get_table(0); pt3 = leapsec_get_table(1); TEST_ASSERT_EQUAL(pt1, pt2); TEST_ASSERT_NOT_EQUAL(pt2, pt3); pt1 = pt3; leapsec_set_table(pt1); pt2 = leapsec_get_table(0); pt3 = leapsec_get_table(1); TEST_ASSERT_EQUAL(pt1, pt2); TEST_ASSERT_NOT_EQUAL(pt2, pt3); } // ---------------------------------------------------------------------- // load file & check expiration void test_loadFileExpire(void) { const char *cp = leap1; int rc; leap_table_t * pt = leapsec_get_table(0); rc = leapsec_load(pt, stringreader, &cp, FALSE) && leapsec_set_table(pt); TEST_ASSERT_EQUAL_MESSAGE(1, rc,"first"); rc = leapsec_expired(3439756800u, NULL); TEST_ASSERT_EQUAL(0, rc); rc = leapsec_expired(3610569601u, NULL); TEST_ASSERT_EQUAL(1, rc); } // ---------------------------------------------------------------------- // load file & check time-to-live void test_loadFileTTL(void) { const char *cp = leap1; int rc; leap_table_t * pt = leapsec_get_table(0); time_t pivot = 0x70000000u; const uint32_t limit = 3610569600u; rc = leapsec_load(pt, stringreader, &cp, FALSE) && leapsec_set_table(pt); TEST_ASSERT_EQUAL(1, rc); // // exactly 1 day to live rc = leapsec_daystolive(limit - 86400, &pivot); TEST_ASSERT_EQUAL( 1, rc); // less than 1 day to live rc = leapsec_daystolive(limit - 86399, &pivot); TEST_ASSERT_EQUAL( 0, rc); // hit expiration exactly rc = leapsec_daystolive(limit, &pivot); TEST_ASSERT_EQUAL( 0, rc); // expired since 1 sec rc = leapsec_daystolive(limit + 1, &pivot); TEST_ASSERT_EQUAL(-1, rc); } // ===================================================================== // RANDOM QUERY TESTS // ===================================================================== // ---------------------------------------------------------------------- // test query in pristine state (bug#2745 misbehaviour) void test_lsQueryPristineState(void) { int rc; leap_result_t qr; rc = leapsec_query(&qr, lsec2012, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_EQUAL(0, qr.warped ); TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity); } // ---------------------------------------------------------------------- // ad-hoc jump: leap second at 2009.01.01 -60days void test_ls2009faraway(void) { int rc; leap_result_t qr; rc = setup_load_table(leap1,FALSE); TEST_ASSERT_EQUAL(1, rc); // test 60 days before leap. Nothing scheduled or indicated. rc = leapsec_query(&qr, lsec2009 - 60*SECSPERDAY, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_EQUAL(33, qr.tai_offs); TEST_ASSERT_EQUAL(0, qr.tai_diff); TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity); } // ---------------------------------------------------------------------- // ad-hoc jump: leap second at 2009.01.01 -1week void test_ls2009weekaway(void) { int rc; leap_result_t qr; rc = setup_load_table(leap1,FALSE); TEST_ASSERT_EQUAL(1, rc); // test 7 days before leap. Leap scheduled, but not yet indicated. rc = leapsec_query(&qr, lsec2009 - 7*SECSPERDAY, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_EQUAL(33, qr.tai_offs); TEST_ASSERT_EQUAL(1, qr.tai_diff); TEST_ASSERT_EQUAL(LSPROX_SCHEDULE, qr.proximity); } // ---------------------------------------------------------------------- // ad-hoc jump: leap second at 2009.01.01 -1hr void test_ls2009houraway(void) { int rc; leap_result_t qr; rc = setup_load_table(leap1,FALSE); TEST_ASSERT_EQUAL(1, rc); // test 1 hour before leap. 61 true seconds to go. rc = leapsec_query(&qr, lsec2009 - SECSPERHR, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_EQUAL(33, qr.tai_offs); TEST_ASSERT_EQUAL(1, qr.tai_diff); TEST_ASSERT_EQUAL(LSPROX_ANNOUNCE, qr.proximity); } // ---------------------------------------------------------------------- // ad-hoc jump: leap second at 2009.01.01 -1sec void test_ls2009secaway(void) { int rc; leap_result_t qr; rc = setup_load_table(leap1,FALSE); TEST_ASSERT_EQUAL(1, rc); // test 1 second before leap (last boundary...) 2 true seconds to go. rc = leapsec_query(&qr, lsec2009 - 1, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_EQUAL(33, qr.tai_offs); TEST_ASSERT_EQUAL(1, qr.tai_diff); TEST_ASSERT_EQUAL(LSPROX_ALERT, qr.proximity); } // ---------------------------------------------------------------------- // ad-hoc jump to leap second at 2009.01.01 void test_ls2009onspot(void) { int rc; leap_result_t qr; rc = setup_load_table(leap1,FALSE); TEST_ASSERT_EQUAL(1, rc); // test on-spot: treat leap second as already gone. rc = leapsec_query(&qr, lsec2009, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_EQUAL(34, qr.tai_offs); TEST_ASSERT_EQUAL(0, qr.tai_diff); TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity); } // ---------------------------------------------------------------------- // test handling of the leap second at 2009.01.01 without table void test_ls2009nodata(void) { int rc; leap_result_t qr; rc = setup_clear_table(); TEST_ASSERT_EQUAL(1, rc); // test on-spot with empty table rc = leapsec_query(&qr, lsec2009, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_EQUAL(0, qr.tai_offs); TEST_ASSERT_EQUAL(0, qr.tai_diff); TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity); } // ---------------------------------------------------------------------- // test handling of the leap second at 2009.01.01 with culled data void test_ls2009limdata(void) { int rc; leap_result_t qr; rc = setup_load_table(leap1, TRUE); TEST_ASSERT_EQUAL(1, rc); // test on-spot with limited table - this is tricky. // The table used ends 2012; depending on the build date, the 2009 entry // might be included or culled. The resulting TAI offset must be either // 34 or 35 seconds, depending on the build date of the test. rc = leapsec_query(&qr, lsec2009, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_TRUE(34 <= qr.tai_offs); TEST_ASSERT_TRUE(35 >= qr.tai_offs); TEST_ASSERT_EQUAL(0, qr.tai_diff); TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity); } // ---------------------------------------------------------------------- // Far-distance forward jump into a transiton window. void test_qryJumpFarAhead(void) { int rc; leap_result_t qr; int last, idx; int mode; for (mode=0; mode < 2; ++mode) { leapsec_ut_pristine(); rc = setup_load_table(leap1, FALSE); TEST_ASSERT_EQUAL(1, rc); leapsec_electric(mode); rc = leapsec_query(&qr, lsec2006, NULL); TEST_ASSERT_EQUAL(FALSE, rc); rc = leapsec_query(&qr, lsec2012, NULL); TEST_ASSERT_EQUAL(FALSE, rc); } } // ---------------------------------------------------------------------- // Forward jump into the next transition window void test_qryJumpAheadToTransition(void) { int rc; leap_result_t qr; int last, idx; int mode; for (mode=0; mode < 2; ++mode) { leapsec_ut_pristine(); rc = setup_load_table(leap1, FALSE); TEST_ASSERT_EQUAL(1, rc); leapsec_electric(mode); rc = leapsec_query(&qr, lsec2009-SECSPERDAY, NULL); TEST_ASSERT_EQUAL(FALSE, rc); rc = leapsec_query(&qr, lsec2009+1, NULL); TEST_ASSERT_EQUAL(TRUE, rc); } } // ---------------------------------------------------------------------- // Forward jump over the next transition window void test_qryJumpAheadOverTransition(void) { int rc; leap_result_t qr; int last, idx; int mode; for (mode=0; mode < 2; ++mode) { leapsec_ut_pristine(); rc = setup_load_table(leap1, FALSE); TEST_ASSERT_EQUAL(1, rc); leapsec_electric(mode); rc = leapsec_query(&qr, lsec2009-SECSPERDAY, NULL); TEST_ASSERT_EQUAL(FALSE, rc); rc = leapsec_query(&qr, lsec2009+5, NULL); TEST_ASSERT_EQUAL(FALSE, rc); } } // ===================================================================== // TABLE MODIFICATION AT RUNTIME // ===================================================================== // ---------------------------------------------------------------------- // add dynamic leap second (like from peer/clock) void test_addDynamic(void) { int rc; leap_result_t qr; static const uint32_t insns[] = { 2982009600u, // 29 # 1 Jul 1994 3029443200u, // 30 # 1 Jan 1996 3076704000u, // 31 # 1 Jul 1997 3124137600u, // 32 # 1 Jan 1999 3345062400u, // 33 # 1 Jan 2006 3439756800u, // 34 # 1 Jan 2009 3550089600u, // 35 # 1 Jul 2012 0 // sentinel }; rc = setup_load_table(leap2, FALSE); TEST_ASSERT_EQUAL(1, rc); leap_table_t * pt = leapsec_get_table(0); int idx; for (idx=1; insns[idx]; ++idx) { rc = leapsec_add_dyn(TRUE, insns[idx] - 20*SECSPERDAY - 100, NULL); TEST_ASSERT_EQUAL(TRUE, rc); } // try to slip in a previous entry rc = leapsec_add_dyn(TRUE, insns[0] - 20*SECSPERDAY - 100, NULL); TEST_ASSERT_EQUAL(FALSE, rc); //leapsec_dump(pt, (leapsec_dumper)fprintf, stdout); } // ---------------------------------------------------------------------- // add fixed leap seconds (like from network packet) #if 0 /* currently unused -- possibly revived later */ void FAILtest_addFixed(void) { int rc; leap_result_t qr; static const struct { uint32_t tt; int of; } insns[] = { {2982009600u, 29},// # 1 Jul 1994 {3029443200u, 30},// # 1 Jan 1996 {3076704000u, 31},// # 1 Jul 1997 {3124137600u, 32},// # 1 Jan 1999 {3345062400u, 33},// # 1 Jan 2006 {3439756800u, 34},// # 1 Jan 2009 {3550089600u, 35},// # 1 Jul 2012 {0,0} // sentinel }; rc = setup_load_table(leap2, FALSE); TEST_ASSERT_EQUAL(1, rc); int idx; leap_table_t * pt = leapsec_get_table(0); // try to get in BAD time stamps... for (idx=0; insns[idx].tt; ++idx) { rc = leapsec_add_fix( insns[idx].of, insns[idx].tt - 20*SECSPERDAY - 100, insns[idx].tt + SECSPERDAY, NULL); TEST_ASSERT_EQUAL(FALSE, rc); } // now do it right for (idx=0; insns[idx].tt; ++idx) { rc = leapsec_add_fix( insns[idx].of, insns[idx].tt, insns[idx].tt + SECSPERDAY, NULL); TEST_ASSERT_EQUAL(TRUE, rc); } // try to slip in a previous entry rc = leapsec_add_fix( insns[0].of, insns[0].tt, insns[0].tt + SECSPERDAY, NULL); TEST_ASSERT_EQUAL(FALSE, rc); //leapsec_dump(pt, (leapsec_dumper)fprintf, stdout); } #endif // ---------------------------------------------------------------------- // add fixed leap seconds (like from network packet) #if 0 /* currently unused -- possibly revived later */ void FAILtest_addFixedExtend(void) { int rc; leap_result_t qr; int last, idx; static const struct { uint32_t tt; int of; } insns[] = { {2982009600u, 29},// # 1 Jul 1994 {3029443200u, 30},// # 1 Jan 1996 {0,0} // sentinel }; rc = setup_load_table(leap2, FALSE); TEST_ASSERT_EQUAL(1, rc); leap_table_t * pt = leapsec_get_table(FALSE); for (last=idx=0; insns[idx].tt; ++idx) { last = idx; rc = leapsec_add_fix( insns[idx].of, insns[idx].tt, insns[idx].tt + SECSPERDAY, NULL); TEST_ASSERT_EQUAL(TRUE, rc); } // try to extend the expiration of the last entry rc = leapsec_add_fix( insns[last].of, insns[last].tt, insns[last].tt + 128*SECSPERDAY, NULL); TEST_ASSERT_EQUAL(TRUE, rc); // try to extend the expiration of the last entry with wrong offset rc = leapsec_add_fix( insns[last].of+1, insns[last].tt, insns[last].tt + 129*SECSPERDAY, NULL); TEST_ASSERT_EQUAL(FALSE, rc); //leapsec_dump(pt, (leapsec_dumper)fprintf, stdout); }
//#include "ntpdtest.h" #include "config.h" #include "ntp.h" #include "ntp_calendar.h" #include "ntp_stdlib.h" #include "ntp_leapsec.h" #include "unity.h" #include <string.h> #include "test-libntp.h" static const char leap1 [] = "#\n" "#@ 3610569600\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" " \t \n" "2571782400 20 # 1 Jul 1981\n" "2603318400 21 # 1 Jul 1982\n" "2634854400 22 # 1 Jul 1983\n" "2698012800 23 # 1 Jul 1985\n" "2776982400 24 # 1 Jan 1988\n" "2840140800 25 # 1 Jan 1990\n" "2871676800 26 # 1 Jan 1991\n" "2918937600 27 # 1 Jul 1992\n" "2950473600 28 # 1 Jul 1993\n" "2982009600 29 # 1 Jul 1994\n" "3029443200 30 # 1 Jan 1996\n" "3076704000 31 # 1 Jul 1997\n" "3124137600 32 # 1 Jan 1999\n" "3345062400 33 # 1 Jan 2006\n" "3439756800 34 # 1 Jan 2009\n" "3550089600 35 # 1 Jul 2012\n" "#\n" "#h dc2e6b0b 5aade95d a0587abd 4e0dacb4 e4d5049e\n" "#\n"; static const char leap2 [] = "#\n" "#@ 2950473700\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" "2571782400 20 # 1 Jul 1981\n" "2603318400 21 # 1 Jul 1982\n" "2634854400 22 # 1 Jul 1983\n" "2698012800 23 # 1 Jul 1985\n" "2776982400 24 # 1 Jan 1988\n" "2840140800 25 # 1 Jan 1990\n" "2871676800 26 # 1 Jan 1991\n" "2918937600 27 # 1 Jul 1992\n" "2950473600 28 # 1 Jul 1993\n" "#\n"; // Faked table with a leap second removal at 2009 static const char leap3 [] = "#\n" "#@ 3610569600\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" "2571782400 20 # 1 Jul 1981\n" "2603318400 21 # 1 Jul 1982\n" "2634854400 22 # 1 Jul 1983\n" "2698012800 23 # 1 Jul 1985\n" "2776982400 24 # 1 Jan 1988\n" "2840140800 25 # 1 Jan 1990\n" "2871676800 26 # 1 Jan 1991\n" "2918937600 27 # 1 Jul 1992\n" "2950473600 28 # 1 Jul 1993\n" "2982009600 29 # 1 Jul 1994\n" "3029443200 30 # 1 Jan 1996\n" "3076704000 31 # 1 Jul 1997\n" "3124137600 32 # 1 Jan 1999\n" "3345062400 33 # 1 Jan 2006\n" "3439756800 32 # 1 Jan 2009\n" "3550089600 33 # 1 Jul 2012\n" "#\n"; // short table with good hash static const char leap_ghash [] = "#\n" "#@ 3610569600\n" "#$ 3610566000\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" "#\n" "#h 4b304e10 95642b3f c10b91f9 90791725 25f280d0\n" "#\n"; // short table with bad hash static const char leap_bhash [] = "#\n" "#@ 3610569600\n" "#$ 3610566000\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" "#\n" "#h dc2e6b0b 5aade95d a0587abd 4e0dacb4 e4d5049e\n" "#\n"; // short table with malformed hash static const char leap_mhash [] = "#\n" "#@ 3610569600\n" "#$ 3610566000\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" "#\n" "#h f2349a02 788b9534 a8f2e141 f2029Q6d 4064a7ee\n" "#\n"; // short table with only 4 hash groups static const char leap_shash [] = "#\n" "#@ 3610569600\n" "#$ 3610566000\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" "#\n" "#h f2349a02 788b9534 a8f2e141 f2029Q6d\n" "#\n"; // table with good hash and truncated/missing leading zeros static const char leap_gthash [] = { "#\n" "#$ 3535228800\n" "#\n" "# Updated through IERS Bulletin C46\n" "# File expires on: 28 June 2014\n" "#\n" "#@ 3612902400\n" "#\n" "2272060800 10 # 1 Jan 1972\n" "2287785600 11 # 1 Jul 1972\n" "2303683200 12 # 1 Jan 1973\n" "2335219200 13 # 1 Jan 1974\n" "2366755200 14 # 1 Jan 1975\n" "2398291200 15 # 1 Jan 1976\n" "2429913600 16 # 1 Jan 1977\n" "2461449600 17 # 1 Jan 1978\n" "2492985600 18 # 1 Jan 1979\n" "2524521600 19 # 1 Jan 1980\n" "2571782400 20 # 1 Jul 1981\n" "2603318400 21 # 1 Jul 1982\n" "2634854400 22 # 1 Jul 1983\n" "2698012800 23 # 1 Jul 1985\n" "2776982400 24 # 1 Jan 1988\n" "2840140800 25 # 1 Jan 1990\n" "2871676800 26 # 1 Jan 1991\n" "2918937600 27 # 1 Jul 1992\n" "2950473600 28 # 1 Jul 1993\n" "2982009600 29 # 1 Jul 1994\n" "3029443200 30 # 1 Jan 1996\n" "3076704000 31 # 1 Jul 1997\n" "3124137600 32 # 1 Jan 1999\n" "3345062400 33 # 1 Jan 2006\n" "3439756800 34 # 1 Jan 2009\n" "3550089600 35 # 1 Jul 2012\n" "#\n" "#h 1151a8f e85a5069 9000fcdb 3d5e5365 1d505b37" }; static const uint32_t lsec2006 = 3345062400u; // +33, 1 Jan 2006, 00:00:00 utc static const uint32_t lsec2009 = 3439756800u; // +34, 1 Jan 2009, 00:00:00 utc static const uint32_t lsec2012 = 3550089600u; // +35, 1 Jul 2012, 00:00:00 utc static const uint32_t lsec2015 = 3644697600u; // +36, 1 Jul 2015, 00:00:00 utc int stringreader(void* farg) { const char ** cpp = (const char**)farg; if (**cpp) return *(*cpp)++; else return EOF; } static int/*BOOL*/ setup_load_table( const char * cp, int blim) { int rc; leap_table_t * pt = leapsec_get_table(0); rc = (pt != NULL) && leapsec_load(pt, stringreader, &cp, blim); rc = rc && leapsec_set_table(pt); return rc; } static int/*BOOL*/ setup_clear_table(void) { int rc; leap_table_t * pt = leapsec_get_table(0); if (pt) leapsec_clear(pt); rc = leapsec_set_table(pt); return rc; } char * CalendarToString(const struct calendar cal) { char * ss = malloc (sizeof (char) * 100); char buffer[100] =""; sprintf(buffer, "%u", cal.year); strcat(ss,buffer); strcat(ss,"-"); sprintf(buffer, "%u", (u_int)cal.month); strcat(ss,buffer); strcat(ss,"-"); sprintf(buffer, "%u", (u_int)cal.monthday); strcat(ss,buffer); strcat(ss," ("); sprintf(buffer, "%u", (u_int) cal.yearday); strcat(ss,buffer); strcat(ss,") "); sprintf(buffer, "%u", (u_int)cal.hour); strcat(ss,buffer); strcat(ss,":"); sprintf(buffer, "%u", (u_int)cal.minute); strcat(ss,buffer); strcat(ss,":"); sprintf(buffer, "%u", (u_int)cal.second); strcat(ss,buffer); //ss << cal.year << "-" << (u_int)cal.month << "-" << (u_int)cal.monthday << " (" << cal.yearday << ") " << (u_int)cal.hour << ":" << (u_int)cal.minute << ":" << (u_int)cal.second; return ss; } int IsEqual(const struct calendar expected, const struct calendar actual) { if (expected.year == actual.year && (expected.yearday == actual.yearday || (expected.month == actual.month && expected.monthday == actual.monthday)) && expected.hour == actual.hour && expected.minute == actual.minute && expected.second == actual.second) { return TRUE; } else { printf("expected: %s but was %s", CalendarToString(expected) ,CalendarToString(actual)); return FALSE; } } //------------------------- void setUp(void) { ntpcal_set_timefunc(timefunc); settime(1970, 1, 1, 0, 0, 0); leapsec_ut_pristine(); } void tearDown(void) { ntpcal_set_timefunc(NULL); } // ===================================================================== // VALIDATION TESTS // ===================================================================== // ---------------------------------------------------------------------- void test_ValidateGood(void) { const char *cp = leap_ghash; int rc = leapsec_validate(stringreader, &cp); TEST_ASSERT_EQUAL(LSVALID_GOODHASH, rc); } // ---------------------------------------------------------------------- void test_ValidateNoHash(void) { const char *cp = leap2; int rc = leapsec_validate(stringreader, &cp); TEST_ASSERT_EQUAL(LSVALID_NOHASH, rc); } // ---------------------------------------------------------------------- void test_ValidateBad(void) { const char *cp = leap_bhash; int rc = leapsec_validate(stringreader, &cp); TEST_ASSERT_EQUAL(LSVALID_BADHASH, rc); } // ---------------------------------------------------------------------- void test_ValidateMalformed(void) { const char *cp = leap_mhash; int rc = leapsec_validate(stringreader, &cp); TEST_ASSERT_EQUAL(LSVALID_BADFORMAT, rc); } // ---------------------------------------------------------------------- void test_ValidateMalformedShort(void) { const char *cp = leap_shash; int rc = leapsec_validate(stringreader, &cp); TEST_ASSERT_EQUAL(LSVALID_BADFORMAT, rc); } // ---------------------------------------------------------------------- void test_ValidateNoLeadZero(void) { const char *cp = leap_gthash; int rc = leapsec_validate(stringreader, &cp); TEST_ASSERT_EQUAL(LSVALID_GOODHASH, rc); } // ===================================================================== // BASIC FUNCTIONS // ===================================================================== // ---------------------------------------------------------------------- // test table selection void test_tableSelect(void) { leap_table_t *pt1, *pt2, *pt3, *pt4; pt1 = leapsec_get_table(0); pt2 = leapsec_get_table(0); TEST_ASSERT_EQUAL_MESSAGE(pt1, pt2,"first"); pt1 = leapsec_get_table(1); pt2 = leapsec_get_table(1); TEST_ASSERT_EQUAL_MESSAGE(pt1, pt2,"second"); pt1 = leapsec_get_table(1); pt2 = leapsec_get_table(0); TEST_ASSERT_NOT_EQUAL(pt1, pt2); pt1 = leapsec_get_table(0); pt2 = leapsec_get_table(1); TEST_ASSERT_NOT_EQUAL(pt1, pt2); leapsec_set_table(pt1); pt2 = leapsec_get_table(0); pt3 = leapsec_get_table(1); TEST_ASSERT_EQUAL(pt1, pt2); TEST_ASSERT_NOT_EQUAL(pt2, pt3); pt1 = pt3; leapsec_set_table(pt1); pt2 = leapsec_get_table(0); pt3 = leapsec_get_table(1); TEST_ASSERT_EQUAL(pt1, pt2); TEST_ASSERT_NOT_EQUAL(pt2, pt3); } // ---------------------------------------------------------------------- // load file & check expiration void test_loadFileExpire(void) { const char *cp = leap1; int rc; leap_table_t * pt = leapsec_get_table(0); rc = leapsec_load(pt, stringreader, &cp, FALSE) && leapsec_set_table(pt); TEST_ASSERT_EQUAL_MESSAGE(1, rc,"first"); rc = leapsec_expired(3439756800u, NULL); TEST_ASSERT_EQUAL(0, rc); rc = leapsec_expired(3610569601u, NULL); TEST_ASSERT_EQUAL(1, rc); } // ---------------------------------------------------------------------- // load file & check time-to-live void test_loadFileTTL(void) { const char *cp = leap1; int rc; leap_table_t * pt = leapsec_get_table(0); time_t pivot = 0x70000000u; const uint32_t limit = 3610569600u; rc = leapsec_load(pt, stringreader, &cp, FALSE) && leapsec_set_table(pt); TEST_ASSERT_EQUAL(1, rc); // // exactly 1 day to live rc = leapsec_daystolive(limit - 86400, &pivot); TEST_ASSERT_EQUAL( 1, rc); // less than 1 day to live rc = leapsec_daystolive(limit - 86399, &pivot); TEST_ASSERT_EQUAL( 0, rc); // hit expiration exactly rc = leapsec_daystolive(limit, &pivot); TEST_ASSERT_EQUAL( 0, rc); // expired since 1 sec rc = leapsec_daystolive(limit + 1, &pivot); TEST_ASSERT_EQUAL(-1, rc); } // ===================================================================== // RANDOM QUERY TESTS // ===================================================================== // ---------------------------------------------------------------------- // test query in pristine state (bug#2745 misbehaviour) void test_lsQueryPristineState(void) { int rc; leap_result_t qr; rc = leapsec_query(&qr, lsec2012, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_EQUAL(0, qr.warped ); TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity); } // ---------------------------------------------------------------------- // ad-hoc jump: leap second at 2009.01.01 -60days void test_ls2009faraway(void) { int rc; leap_result_t qr; rc = setup_load_table(leap1,FALSE); TEST_ASSERT_EQUAL(1, rc); // test 60 days before leap. Nothing scheduled or indicated. rc = leapsec_query(&qr, lsec2009 - 60*SECSPERDAY, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_EQUAL(33, qr.tai_offs); TEST_ASSERT_EQUAL(0, qr.tai_diff); TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity); } // ---------------------------------------------------------------------- // ad-hoc jump: leap second at 2009.01.01 -1week void test_ls2009weekaway(void) { int rc; leap_result_t qr; rc = setup_load_table(leap1,FALSE); TEST_ASSERT_EQUAL(1, rc); // test 7 days before leap. Leap scheduled, but not yet indicated. rc = leapsec_query(&qr, lsec2009 - 7*SECSPERDAY, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_EQUAL(33, qr.tai_offs); TEST_ASSERT_EQUAL(1, qr.tai_diff); TEST_ASSERT_EQUAL(LSPROX_SCHEDULE, qr.proximity); } // ---------------------------------------------------------------------- // ad-hoc jump: leap second at 2009.01.01 -1hr void test_ls2009houraway(void) { int rc; leap_result_t qr; rc = setup_load_table(leap1,FALSE); TEST_ASSERT_EQUAL(1, rc); // test 1 hour before leap. 61 true seconds to go. rc = leapsec_query(&qr, lsec2009 - SECSPERHR, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_EQUAL(33, qr.tai_offs); TEST_ASSERT_EQUAL(1, qr.tai_diff); TEST_ASSERT_EQUAL(LSPROX_ANNOUNCE, qr.proximity); } // ---------------------------------------------------------------------- // ad-hoc jump: leap second at 2009.01.01 -1sec void test_ls2009secaway(void) { int rc; leap_result_t qr; rc = setup_load_table(leap1,FALSE); TEST_ASSERT_EQUAL(1, rc); // test 1 second before leap (last boundary...) 2 true seconds to go. rc = leapsec_query(&qr, lsec2009 - 1, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_EQUAL(33, qr.tai_offs); TEST_ASSERT_EQUAL(1, qr.tai_diff); TEST_ASSERT_EQUAL(LSPROX_ALERT, qr.proximity); } // ---------------------------------------------------------------------- // ad-hoc jump to leap second at 2009.01.01 void test_ls2009onspot(void) { int rc; leap_result_t qr; rc = setup_load_table(leap1,FALSE); TEST_ASSERT_EQUAL(1, rc); // test on-spot: treat leap second as already gone. rc = leapsec_query(&qr, lsec2009, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_EQUAL(34, qr.tai_offs); TEST_ASSERT_EQUAL(0, qr.tai_diff); TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity); } // ---------------------------------------------------------------------- // test handling of the leap second at 2009.01.01 without table void test_ls2009nodata(void) { int rc; leap_result_t qr; rc = setup_clear_table(); TEST_ASSERT_EQUAL(1, rc); // test on-spot with empty table rc = leapsec_query(&qr, lsec2009, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_EQUAL(0, qr.tai_offs); TEST_ASSERT_EQUAL(0, qr.tai_diff); TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity); } // ---------------------------------------------------------------------- // test handling of the leap second at 2009.01.01 with culled data void test_ls2009limdata(void) { int rc; leap_result_t qr; rc = setup_load_table(leap1, TRUE); TEST_ASSERT_EQUAL(1, rc); // test on-spot with limited table - this is tricky. // The table used ends 2012; depending on the build date, the 2009 entry // might be included or culled. The resulting TAI offset must be either // 34 or 35 seconds, depending on the build date of the test. rc = leapsec_query(&qr, lsec2009, NULL); TEST_ASSERT_EQUAL(FALSE, rc); TEST_ASSERT_TRUE(34 <= qr.tai_offs); TEST_ASSERT_TRUE(35 >= qr.tai_offs); TEST_ASSERT_EQUAL(0, qr.tai_diff); TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity); } // ---------------------------------------------------------------------- // Far-distance forward jump into a transiton window. void test_qryJumpFarAhead(void) { int rc; leap_result_t qr; int last, idx; int mode; for (mode=0; mode < 2; ++mode) { leapsec_ut_pristine(); rc = setup_load_table(leap1, FALSE); TEST_ASSERT_EQUAL(1, rc); leapsec_electric(mode); rc = leapsec_query(&qr, lsec2006, NULL); TEST_ASSERT_EQUAL(FALSE, rc); rc = leapsec_query(&qr, lsec2012, NULL); TEST_ASSERT_EQUAL(FALSE, rc); } } // ---------------------------------------------------------------------- // Forward jump into the next transition window void test_qryJumpAheadToTransition(void) { int rc; leap_result_t qr; int last, idx; int mode; for (mode=0; mode < 2; ++mode) { leapsec_ut_pristine(); rc = setup_load_table(leap1, FALSE); TEST_ASSERT_EQUAL(1, rc); leapsec_electric(mode); rc = leapsec_query(&qr, lsec2009-SECSPERDAY, NULL); TEST_ASSERT_EQUAL(FALSE, rc); rc = leapsec_query(&qr, lsec2009+1, NULL); TEST_ASSERT_EQUAL(TRUE, rc); } } // ---------------------------------------------------------------------- // Forward jump over the next transition window void test_qryJumpAheadOverTransition(void) { int rc; leap_result_t qr; int last, idx; int mode; for (mode=0; mode < 2; ++mode) { leapsec_ut_pristine(); rc = setup_load_table(leap1, FALSE); TEST_ASSERT_EQUAL(1, rc); leapsec_electric(mode); rc = leapsec_query(&qr, lsec2009-SECSPERDAY, NULL); TEST_ASSERT_EQUAL(FALSE, rc); rc = leapsec_query(&qr, lsec2009+5, NULL); TEST_ASSERT_EQUAL(FALSE, rc); } } // ===================================================================== // TABLE MODIFICATION AT RUNTIME // ===================================================================== // ---------------------------------------------------------------------- // add dynamic leap second (like from peer/clock) void test_addDynamic(void) { int rc; leap_result_t qr; static const uint32_t insns[] = { 2982009600u, // 29 # 1 Jul 1994 3029443200u, // 30 # 1 Jan 1996 3076704000u, // 31 # 1 Jul 1997 3124137600u, // 32 # 1 Jan 1999 3345062400u, // 33 # 1 Jan 2006 3439756800u, // 34 # 1 Jan 2009 3550089600u, // 35 # 1 Jul 2012 0 // sentinel }; rc = setup_load_table(leap2, FALSE); TEST_ASSERT_EQUAL(1, rc); leap_table_t * pt = leapsec_get_table(0); int idx; for (idx=1; insns[idx]; ++idx) { rc = leapsec_add_dyn(TRUE, insns[idx] - 20*SECSPERDAY - 100, NULL); TEST_ASSERT_EQUAL(TRUE, rc); } // try to slip in a previous entry rc = leapsec_add_dyn(TRUE, insns[0] - 20*SECSPERDAY - 100, NULL); TEST_ASSERT_EQUAL(FALSE, rc); //leapsec_dump(pt, (leapsec_dumper)fprintf, stdout); } // ---------------------------------------------------------------------- // add fixed leap seconds (like from network packet) #if 0 /* currently unused -- possibly revived later */ void FAILtest_addFixed(void) { int rc; leap_result_t qr; static const struct { uint32_t tt; int of; } insns[] = { {2982009600u, 29},// # 1 Jul 1994 {3029443200u, 30},// # 1 Jan 1996 {3076704000u, 31},// # 1 Jul 1997 {3124137600u, 32},// # 1 Jan 1999 {3345062400u, 33},// # 1 Jan 2006 {3439756800u, 34},// # 1 Jan 2009 {3550089600u, 35},// # 1 Jul 2012 {0,0} // sentinel }; rc = setup_load_table(leap2, FALSE); TEST_ASSERT_EQUAL(1, rc); int idx; leap_table_t * pt = leapsec_get_table(0); // try to get in BAD time stamps... for (idx=0; insns[idx].tt; ++idx) { rc = leapsec_add_fix( insns[idx].of, insns[idx].tt - 20*SECSPERDAY - 100, insns[idx].tt + SECSPERDAY, NULL); TEST_ASSERT_EQUAL(FALSE, rc); } // now do it right for (idx=0; insns[idx].tt; ++idx) { rc = leapsec_add_fix( insns[idx].of, insns[idx].tt, insns[idx].tt + SECSPERDAY, NULL); TEST_ASSERT_EQUAL(TRUE, rc); } // try to slip in a previous entry rc = leapsec_add_fix( insns[0].of, insns[0].tt, insns[0].tt + SECSPERDAY, NULL); TEST_ASSERT_EQUAL(FALSE, rc); //leapsec_dump(pt, (leapsec_dumper)fprintf, stdout); } #endif // ---------------------------------------------------------------------- // add fixed leap seconds (like from network packet) #if 0 /* currently unused -- possibly revived later */ void FAILtest_addFixedExtend(void) { int rc; leap_result_t qr; int last, idx; static const struct { uint32_t tt; int of; } insns[] = { {2982009600u, 29},// # 1 Jul 1994 {3029443200u, 30},// # 1 Jan 1996 {0,0} // sentinel }; rc = setup_load_table(leap2, FALSE); TEST_ASSERT_EQUAL(1, rc); leap_table_t * pt = leapsec_get_table(FALSE); for (last=idx=0; insns[idx].tt; ++idx) { last = idx; rc = leapsec_add_fix( insns[idx].of, insns[idx].tt, insns[idx].tt + SECSPERDAY, NULL); TEST_ASSERT_EQUAL(TRUE, rc); } // try to extend the expiration of the last entry rc = leapsec_add_fix( insns[last].of, insns[last].tt, insns[last].tt + 128*SECSPERDAY, NULL); TEST_ASSERT_EQUAL(TRUE, rc); // try to extend the expiration of the last entry with wrong offset rc = leapsec_add_fix( insns[last].of+1, insns[last].tt, insns[last].tt + 129*SECSPERDAY, NULL); TEST_ASSERT_EQUAL(FALSE, rc); //leapsec_dump(pt, (leapsec_dumper)fprintf, stdout); } #endif // ---------------------------------------------------------------------- // add fixed leap seconds (like from network packet) in an otherwise // empty table and test queries before / between /after the tabulated // values. #if 0 /* currently unused -- possibly revived later */ void FAILtest_setFixedExtend(void) { int rc; leap_result_t qr; int last, idx; static const struct { uint32_t tt; int of; } insns[] = { {2982009600u, 29},// # 1 Jul 1994 {3029443200u, 30},// # 1 Jan 1996 {0,0} // sentinel }; leap_table_t * pt = leapsec_get_table(0); for (last=idx=0; insns[idx].tt; ++idx) { last = idx; rc = leapsec_add_fix( insns[idx].of, insns[idx].tt, insns[idx].tt + 128*SECSPERDAY, NULL); TEST_ASSERT_EQUAL(TRUE, rc); } rc = leapsec_query(&qr, insns[0].tt - 86400, NULL); TEST_ASSERT_EQUAL(28, qr.tai_offs); rc = leapsec_query(&qr, insns[0].tt + 86400, NULL); TEST_ASSERT_EQUAL(29, qr.tai_offs); rc = leapsec_query(&qr, insns[1].tt - 86400, NULL); TEST_ASSERT_EQUAL(29, qr.tai_offs); rc = leapsec_query(&qr, insns[1].tt + 86400, NULL); TEST_ASSERT_EQUAL(30, qr.tai_offs); //leapsec_dump(pt, (leapsec_dumper)fprintf, stdout); }
/* load a file from a FILE pointer. Note: If hcheck is true, load * only after successful signature check. The stream must be seekable * or this will fail. */ int/*BOOL*/ leapsec_load_stream( FILE * ifp , const char * fname, int/*BOOL*/ logall) { leap_table_t *pt; int rcheck; if (NULL == fname) fname = "<unknown>"; rcheck = leapsec_validate((leapsec_reader)getc, ifp); if (logall) switch (rcheck) { case LSVALID_GOODHASH: msyslog(LOG_NOTICE, "%s ('%s'): good hash signature", logPrefix, fname); break; case LSVALID_NOHASH: msyslog(LOG_ERR, "%s ('%s'): no hash signature", logPrefix, fname); break; case LSVALID_BADHASH: msyslog(LOG_ERR, "%s ('%s'): signature mismatch", logPrefix, fname); break; case LSVALID_BADFORMAT: msyslog(LOG_ERR, "%s ('%s'): malformed hash signature", logPrefix, fname); break; default: msyslog(LOG_ERR, "%s ('%s'): unknown error code %d", logPrefix, fname, rcheck); break; } if (rcheck < 0) return FALSE; rewind(ifp); pt = leapsec_get_table(TRUE); if (!leapsec_load(pt, (leapsec_reader)getc, ifp, TRUE)) { switch (errno) { case EINVAL: msyslog(LOG_ERR, "%s ('%s'): bad transition time", logPrefix, fname); break; case ERANGE: msyslog(LOG_ERR, "%s ('%s'): times not ascending", logPrefix, fname); break; default: msyslog(LOG_ERR, "%s ('%s'): parsing error", logPrefix, fname); break; } return FALSE; } if (pt->head.size) msyslog(LOG_NOTICE, "%s ('%s'): loaded, expire=%s last=%s ofs=%d", logPrefix, fname, lstostr(&pt->head.expire), lstostr(&pt->info[0].ttime), pt->info[0].taiof); else msyslog(LOG_NOTICE, "%s ('%s'): loaded, expire=%s ofs=%d (no entries after build date)", logPrefix, fname, lstostr(&pt->head.expire), pt->head.base_tai); return leapsec_set_table(pt); }
// ---------------------------------------------------------------------- // test table selection TEST(leapsec, tableSelect) { leap_table_t *pt1, *pt2, *pt3; pt1 = leapsec_get_table(0); pt2 = leapsec_get_table(0); TEST_ASSERT_EQUAL(pt1, pt2); pt1 = leapsec_get_table(1); pt2 = leapsec_get_table(1); TEST_ASSERT_EQUAL(pt1, pt2); pt1 = leapsec_get_table(1); pt2 = leapsec_get_table(0); TEST_ASSERT_NOT_EQUAL(pt1, pt2); pt1 = leapsec_get_table(0); pt2 = leapsec_get_table(1); TEST_ASSERT_NOT_EQUAL(pt1, pt2); leapsec_set_table(pt1); pt2 = leapsec_get_table(0); pt3 = leapsec_get_table(1); TEST_ASSERT_EQUAL(pt1, pt2); TEST_ASSERT_NOT_EQUAL(pt2, pt3); pt1 = pt3; leapsec_set_table(pt1); pt2 = leapsec_get_table(0); pt3 = leapsec_get_table(1); TEST_ASSERT_EQUAL(pt1, pt2); TEST_ASSERT_NOT_EQUAL(pt2, pt3); }
// ---------------------------------------------------------------------- // test table selection void test_tableSelect(void) { leap_table_t *pt1, *pt2, *pt3, *pt4; pt1 = leapsec_get_table(0); pt2 = leapsec_get_table(0); TEST_ASSERT_EQUAL_MESSAGE(pt1, pt2,"first"); pt1 = leapsec_get_table(1); pt2 = leapsec_get_table(1); TEST_ASSERT_EQUAL_MESSAGE(pt1, pt2,"second"); pt1 = leapsec_get_table(1); pt2 = leapsec_get_table(0); TEST_ASSERT_NOT_EQUAL(pt1, pt2); pt1 = leapsec_get_table(0); pt2 = leapsec_get_table(1); TEST_ASSERT_NOT_EQUAL(pt1, pt2); leapsec_set_table(pt1); pt2 = leapsec_get_table(0); pt3 = leapsec_get_table(1); TEST_ASSERT_EQUAL(pt1, pt2); TEST_ASSERT_NOT_EQUAL(pt2, pt3); pt1 = pt3; leapsec_set_table(pt1); pt2 = leapsec_get_table(0); pt3 = leapsec_get_table(1); TEST_ASSERT_EQUAL(pt1, pt2); TEST_ASSERT_NOT_EQUAL(pt2, pt3); }
/* ------------------------------------------------------------------ */ 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; }
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; }
/* Reset the current leap frame */ void leapsec_reset_frame(void) { reset_times(leapsec_get_table(FALSE)); }
/* Reset the current leap frame */ void leapsec_reset_frame(void) { reset_times(leapsec_get_table(false)); }