1 /* $NetBSD: ntp_leapsec.h,v 1.1.1.1 2013/12/27 23:30:54 christos Exp $ */ 2 3 /* 4 * ntp_leapsec.h - leap second processing for NTPD 5 * 6 * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project. 7 * The contents of 'html/copyright.html' apply. 8 * ---------------------------------------------------------------------- 9 * This is an attempt to get the leap second handling into a dedicated 10 * module to make the somewhat convoluted logic testable. 11 */ 12 13 #ifndef NTP_LEAPSEC_H 14 #define NTP_LEAPSEC_H 15 16 /* these should probably go to libntp... */ 17 extern vint64 strtouv64(const char * src, char ** endp, int base); 18 extern int icmpv64(const vint64 * lhs, const vint64 * rhs); 19 extern int ucmpv64(const vint64 * lhs, const vint64 * rhs); 20 21 /* function pointer types. Note that 'fprintf' and 'getc' can be casted 22 * to the dumper resp. reader type, provided the auxiliary argument is a 23 * valid FILE pointer in hat case. 24 */ 25 typedef void (*leapsec_dumper)(void*, const char *fmt, ...); 26 typedef int (*leapsec_reader)(void*); 27 28 struct leap_table; 29 typedef struct leap_table leap_table_t; 30 31 /* Set/get electric mode 32 * Electric mode is defined as the operation mode where the system clock 33 * automagically manages the leap second, so we don't have to care about 34 * stepping the clock. (This should be the case with most systems, 35 * including the current implementation of the Win32 timekeeping.) 36 * 37 * The consequence of electric mode is that we do not 'see' the leap 38 * second, and no client actions are needed when crossing the leap era 39 * boundary. In manual (aka non-electric) mode the clock will simply 40 * step forward untill *we* (that is, this module) tells the client app 41 * to step at the right time. This needs a slightly different type of 42 * processing, so switching between those two modes should not be done 43 * too close to a leap second. The transition might be lost in that 44 * case. (The limit is actual 2 sec before transition.) 45 * 46 * OTOH, this is a system characteristic, so it's expected to be set 47 * properly somewhere after system start and retain the value. 48 * 49 * Simply querying the state or setting it to the same value as before 50 * does not have any unwanted side effects. You can query by giving a 51 * negative value for the switch. 52 */ 53 extern int/*BOOL*/ leapsec_electric(int/*BOOL*/ on); 54 55 56 /* Query result for a leap second schedule 57 * 'ttime' is the transition point in full time scale, but only if 58 * 'tai_diff' is not zero. Nominal UTC time when the next leap 59 * era starts. 60 * 'ddist' is the distance to the transition, in clock seconds. 61 * This is the distance to the due time, which is different 62 * from the transition time if the mode is non-electric. 63 * Only valid if 'tai_diff' is not zero. 64 * 'tai_offs' is the CURRENT distance from clock (UTC) to TAI. Always valid. 65 * 'tai_diff' is the change in TAI offset after the next leap 66 * transition. Zero if nothing is pending or too far ahead. 67 * 'warped' is set only once, when the the leap second occurred between 68 * two queries. Always zero in electric mode. If non-zero, 69 * immediately step the clock. 70 * 'proximity' is a proximity warning. See definitions below. This is 71 * more useful than an absolute difference to the leap second. 72 * 'dynamic' != 0 if entry was requested by clock/peer 73 */ 74 struct leap_result { 75 vint64 ttime; 76 uint32_t ddist; 77 int16_t tai_offs; 78 int16_t tai_diff; 79 int16_t warped; 80 uint8_t proximity; 81 uint8_t dynamic; 82 }; 83 typedef struct leap_result leap_result_t; 84 85 struct leap_signature { 86 uint32_t etime; /* expiration time */ 87 uint32_t ttime; /* transition time */ 88 int16_t taiof; /* total offset to TAI */ 89 }; 90 typedef struct leap_signature leap_signature_t; 91 92 93 #define LSPROX_NOWARN 0 /* clear radar screen */ 94 #define LSPROX_SCHEDULE 1 /* less than 1 month to target*/ 95 #define LSPROX_ANNOUNCE 2 /* less than 1 day to target */ 96 #define LSPROX_ALERT 3 /* less than 10 sec to target */ 97 98 /* Get the current or alternate table pointer. Getting the alternate 99 * pointer will automatically copy the primary table, so it can be 100 * subsequently modified. 101 */ 102 extern leap_table_t *leapsec_get_table(int alternate); 103 104 /* Set the current leap table. Accepts only return values from 105 * 'leapsec_get_table()', so it's hard to do something wrong. Returns 106 * TRUE if the current table is the requested one. 107 */ 108 extern int/*BOOL*/ leapsec_set_table(leap_table_t *); 109 110 /* Clear all leap second data. Use it for init & cleanup */ 111 extern void leapsec_clear(leap_table_t*); 112 113 /* Load a leap second file. If 'blimit' is set, do not store (but 114 * register with their TAI offset) leap entries before the build date. 115 * Update the leap signature data on the fly. 116 */ 117 extern int/*BOOL*/ leapsec_load(leap_table_t*, leapsec_reader, 118 void*, int blimit); 119 120 /* Dump the current leap table in readable format, using the provided 121 * dump formatter function. 122 */ 123 extern void leapsec_dump(const leap_table_t*, leapsec_dumper func, void *farg); 124 125 /* Read a leap second file. This is a convenience wrapper around the 126 * generic load function, 'leapsec_load()'. 127 */ 128 extern int/*BOOL*/ leapsec_load_file(FILE * fp, int blimit); 129 130 /* Get the current leap data signature. This consists of the last 131 * ransition, the table expiration, and the total TAI difference at the 132 * last transition. This is valid even if the leap transition itself was 133 * culled due to the build date limit. 134 */ 135 extern void leapsec_getsig(leap_signature_t * psig); 136 137 /* Check if the leap table is expired at the given time. 138 */ 139 extern int/*BOOL*/ leapsec_expired(uint32_t when, const time_t * pivot); 140 141 /* Get the distance to expiration in days. 142 * Returns negative values if expired, zero if there are less than 24hrs 143 * left, and positive numbers otherwise. 144 */ 145 extern int32_t leapsec_daystolive(uint32_t when, const time_t * pivot); 146 147 /* Reset the current leap frame, so the next query will do proper table 148 * lookup from fresh. Suppresses a possible leap era transition detection 149 * for the next query. 150 */ 151 extern void leapsec_reset_frame(void); 152 153 /* Given a transition time, the TAI offset valid after that and an 154 * expiration time, try to establish a system leap transition. Only 155 * works if the existing table is extended. On success, updates the 156 * signature data. 157 */ 158 extern int/*BOOL*/ leapsec_add_fix(int offset, uint32_t ttime, uint32_t etime, 159 const time_t * pivot); 160 161 /* Take a time stamp and create a leap second frame for it. This will 162 * schedule a leap second for the beginning of the next month, midnight 163 * UTC. The 'insert' argument tells if a leap second is added (!=0) or 164 * removed (==0). We do not handle multiple inserts (yet?) 165 * 166 * Returns 1 if the insert worked, 0 otherwise. (It's not possible to 167 * insert a leap second into the current history -- only appending 168 * towards the future is allowed!) 169 * 170 * 'ntp_now' is subject to era unfolding. The entry is marked 171 * dynamic. The leap signature is NOT updated. 172 */ 173 extern int/*BOOL*/ leapsec_add_dyn(int/*BOOL*/ insert, uint32_t ntp_now, 174 const time_t * pivot); 175 176 /* Take a time stamp and get the associated leap information. The time 177 * stamp is subject to era unfolding around the pivot or the current 178 * system time if pivot is NULL. Sets the information in '*qr' and 179 * returns TRUE if a leap second era boundary was crossed between the 180 * last and the current query. In that case, qr->warped contains the 181 * required clock stepping, which is always zero in electric mode. 182 */ 183 extern int/*BOOL*/ leapsec_query(leap_result_t *qr, uint32_t ntpts, 184 const time_t * pivot); 185 186 /* Get the current leap frame info. Returns TRUE if the result contains 187 * useable data, FALSE if there is currently no leap second frame. 188 * This merely replicates some results from a previous query, but since 189 * it does not check the current time, only the following entries are 190 * meaningful: 191 * qr->ttime; 192 * qr->tai_offs; 193 * qr->tai_diff; 194 * qr->dynamic; 195 */ 196 extern int/*BOOL*/ leapsec_frame(leap_result_t *qr); 197 198 #endif /* !defined(NTP_LEAPSEC_H) */ 199