xref: /netbsd-src/external/bsd/ntp/dist/ntpd/ntp_leapsec.h (revision 413d532bcc3f62d122e56d92e13ac64825a40baf)
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