]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/ntp/ntpd/ntp_leapsec.h
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / ntp / ntpd / ntp_leapsec.h
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
14 struct 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  */
21 typedef void (*leapsec_dumper)(void*, const char *fmt, ...);
22 typedef int  (*leapsec_reader)(void*);
23
24 struct leap_table;
25 typedef 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
37 extern 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  */
62 extern int/*BOOL*/ leapsec_electric(int/*BOOL*/ on);
63
64 /* Query result for a leap era. This is the minimal stateless
65  * information available for a time stamp in UTC.
66  */
67 struct leap_era {
68         vint64   ebase; /* era base (UTC of start)              */
69         vint64   ttime; /* era end (UTC of next leap second)    */
70         int16_t  taiof; /* offset to TAI in this era            */
71 };
72 typedef struct leap_era leap_era_t;
73
74 /* Query result for a leap second schedule
75  * 'ebase' is the nominal UTC time when the current leap era
76  *      started. (Era base time)
77  * 'ttime' is the next transition point in full time scale. (Nominal UTC
78  *      time when the next leap era starts.)
79  * 'ddist' is the distance to the transition, in clock seconds.
80  *      This is the distance to the due time, which is different
81  *      from the transition time if the mode is non-electric.
82  *      Only valid if 'tai_diff' is not zero.
83  * 'tai_offs' is the CURRENT distance from clock (UTC) to TAI. Always
84  *      valid.
85  * 'tai_diff' is the change in TAI offset after the next leap
86  *      transition. Zero if nothing is pending or too far ahead.
87  * 'warped' is set only once, when the the leap second occurred between
88  *      two queries. Always zero in electric mode. If non-zero,
89  *      immediately step the clock.
90  * 'proximity' is a proximity warning. See definitions below. This is
91  *      more useful than an absolute difference to the leap second.
92  * 'dynamic' != 0 if entry was requested by clock/peer
93  */
94 struct leap_result {
95         vint64   ebase;
96         vint64   ttime;
97         uint32_t ddist;
98         int16_t  tai_offs;
99         int16_t  tai_diff;
100         int16_t  warped;
101         uint8_t  proximity;
102         uint8_t  dynamic;
103 };
104 typedef struct leap_result leap_result_t;
105
106 /* The leap signature is used in two distinct circumstances, and it has
107  * slightly different content in these cases:
108  *  - it is used to indictae the time range covered by the leap second
109  *    table, and then it contains the last transition, TAI offset after
110  *    the final transition, and the expiration time.
111  *  - it is used to query data for AUTOKEY updates, and then it contains
112  *    the *current* TAI offset, the *next* transition time and the
113  *    expiration time of the table.
114  */
115 struct leap_signature {
116         uint32_t etime; /* expiration time      */
117         uint32_t ttime; /* transition time      */
118         int16_t  taiof; /* total offset to TAI  */
119 };
120 typedef struct leap_signature leap_signature_t;
121
122
123 #ifdef LEAP_SMEAR
124
125 struct leap_smear_info {
126         int enabled;        /* not 0 if smearing is generally enabled */
127         int in_progress;    /* not 0 if smearing is in progress, i.e. the offset has been computed */
128         int leap_occurred;  /* not 0 if the leap second has already occurred, i.e., during the leap second */
129         double doffset;     /* the current smear offset as double */
130         l_fp offset;        /* the current smear offset */
131         uint32_t t_offset;  /* the current time for which a smear offset has been computed */
132         long interval;      /* smear interval, in [s], should be at least some hours */
133         double intv_start;  /* start time of the smear interval */
134         double intv_end;    /* end time of the smear interval */
135 };
136 typedef struct leap_smear_info leap_smear_info_t;
137
138 #endif  /* LEAP_SMEAR */
139
140
141 #define LSPROX_NOWARN   0       /* clear radar screen         */
142 #define LSPROX_SCHEDULE 1       /* less than 1 month to target*/
143 #define LSPROX_ANNOUNCE 2       /* less than 1 day to target  */
144 #define LSPROX_ALERT    3       /* less than 10 sec to target */
145
146 /* Get the current or alternate table pointer. Getting the alternate
147  * pointer will automatically copy the primary table, so it can be
148  * subsequently modified.
149  */
150 extern leap_table_t *leapsec_get_table(int alternate);
151
152 /* Set the current leap table. Accepts only return values from
153  * 'leapsec_get_table()', so it's hard to do something wrong. Returns
154  * TRUE if the current table is the requested one.
155  */
156 extern int/*BOOL*/ leapsec_set_table(leap_table_t *);
157
158 /* Clear all leap second data. Use it for init & cleanup */
159 extern void leapsec_clear(leap_table_t*);
160
161 /* Load a leap second file. If 'blimit' is set, do not store (but
162  * register with their TAI offset) leap entries before the build date.
163  * Update the leap signature data on the fly.
164  */
165 extern int/*BOOL*/ leapsec_load(leap_table_t*, leapsec_reader,
166                                 void*, int blimit);
167
168 /* Dump the current leap table in readable format, using the provided
169  * dump formatter function.
170  */
171 extern void leapsec_dump(const leap_table_t*, leapsec_dumper func, void *farg);
172
173 /* Read a leap second file from stream. This is a convenience wrapper
174  * around the generic load function, 'leapsec_load()'.
175  */
176 extern int/*BOOL*/ leapsec_load_stream(FILE * fp, const char * fname,
177                                        int/*BOOL*/logall);
178
179 /* Read a leap second file from file. It checks that the file exists and
180  * (if 'force' is not applied) the ctime/mtime has changed since the
181  * last load. If the file has to be loaded, either due to 'force' or
182  * changed time stamps, the 'stat()' results of the file are stored in
183  * '*sb' for the next cycle. Returns TRUE on successful load, FALSE
184  * otherwise. Uses 'leapsec_load_stream()' internally.
185  */
186 extern int/*BOOL*/ leapsec_load_file(const char * fname, struct stat * sb,
187                                      int/*BOOL*/force, int/*BOOL*/logall);
188
189 /* Get the current leap data signature. This consists of the last
190  * ransition, the table expiration, and the total TAI difference at the
191  * last transition. This is valid even if the leap transition itself was
192  * culled due to the build date limit.
193  */
194 extern void        leapsec_getsig(leap_signature_t * psig);
195
196 /* Check if the leap table is expired at the given time.
197  */
198 extern int/*BOOL*/ leapsec_expired(uint32_t when, const time_t * pivot);
199
200 /* Get the distance to expiration in days.
201  * Returns negative values if expired, zero if there are less than 24hrs
202  * left, and positive numbers otherwise.
203  */
204 extern int32_t leapsec_daystolive(uint32_t when, const time_t * pivot);
205
206 /* Reset the current leap frame, so the next query will do proper table
207  * lookup from fresh. Suppresses a possible leap era transition detection
208  * for the next query.
209  */
210 extern void leapsec_reset_frame(void);
211
212 #if 0 /* currently unused -- possibly revived later */
213 /* Given a transition time, the TAI offset valid after that and an
214  * expiration time, try to establish a system leap transition. Only
215  * works if the existing table is extended. On success, updates the
216  * signature data.
217  */
218 extern int/*BOOL*/ leapsec_add_fix(int offset, uint32_t ttime, uint32_t etime,
219                                    const time_t * pivot);
220 #endif
221
222 /* Take a time stamp and create a leap second frame for it. This will
223  * schedule a leap second for the beginning of the next month, midnight
224  * UTC. The 'insert' argument tells if a leap second is added (!=0) or
225  * removed (==0). We do not handle multiple inserts (yet?)
226  *
227  * Returns 1 if the insert worked, 0 otherwise. (It's not possible to
228  * insert a leap second into the current history -- only appending
229  * towards the future is allowed!)
230  *
231  * 'ntp_now' is subject to era unfolding. The entry is marked
232  * dynamic. The leap signature is NOT updated.
233  */
234 extern int/*BOOL*/ leapsec_add_dyn(int/*BOOL*/ insert, uint32_t ntp_now,
235                                    const time_t * pivot);
236
237 /* Take a time stamp and get the associated leap information. The time
238  * stamp is subject to era unfolding around the pivot or the current
239  * system time if pivot is NULL. Sets the information in '*qr' and
240  * returns TRUE if a leap second era boundary was crossed between the
241  * last and the current query. In that case, qr->warped contains the
242  * required clock stepping, which is always zero in electric mode.
243  */
244 extern int/*BOOL*/ leapsec_query(leap_result_t * qr, uint32_t ntpts,
245                                  const time_t * pivot);
246
247 /* For a given time stamp, fetch the data for the bracketing leap
248  * era. The time stamp is subject to NTP era unfolding.
249  */
250 extern int/*BOOL*/ leapsec_query_era(leap_era_t * qr, uint32_t ntpts,
251                                      const time_t * pivot);
252
253 /* Get the current leap frame info. Returns TRUE if the result contains
254  * useable data, FALSE if there is currently no leap second frame.
255  * This merely replicates some results from a previous query, but since
256  * it does not check the current time, only the following entries are
257  * meaningful:
258  *  qr->ttime;
259  *  qr->tai_offs;
260  *  qr->tai_diff;
261  *  qr->dynamic;
262  */
263 extern int/*BOOL*/ leapsec_frame(leap_result_t *qr);
264
265
266 /* Process a AUTOKEY TAI offset information. This *might* augment the
267  * current leap data table with the given TAI offset.
268  * Returns TRUE if action was taken, FALSE otherwise.
269  */
270 extern int/*BOOL*/ leapsec_autokey_tai(int tai_offset, uint32_t ntpnow,
271                                        const time_t * pivot);
272
273 /* reset global state for unit tests */
274 extern void leapsec_ut_pristine(void);
275
276 #endif /* !defined(NTP_LEAPSEC_H) */