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