/src/ntp-dev/libntp/clocktime.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * clocktime - compute the NTP date from a day of year, hour, minute |
3 | | * and second. |
4 | | */ |
5 | | #include <config.h> |
6 | | #include "ntp_fp.h" |
7 | | #include "ntp_unixtime.h" |
8 | | #include "ntp_stdlib.h" |
9 | | #include "ntp_calendar.h" |
10 | | |
11 | | /* |
12 | | * We check that the time be within CLOSETIME seconds of the receive |
13 | | * time stamp. This is about 4 hours, which hopefully should be wide |
14 | | * enough to collect most data, while close enough to keep things from |
15 | | * getting confused. |
16 | | */ |
17 | 0 | #define CLOSETIME (4u*60u*60u) |
18 | | |
19 | | /* |
20 | | * Since we try to match years, the result of a full search will not |
21 | | * change when we are already less than a half year from the receive |
22 | | * time stamp. Since the length of a year is variable we use a |
23 | | * slightly narrower limit; this might require a full evaluation near |
24 | | * the edge, but will make sure we always get the correct result. |
25 | | */ |
26 | 0 | #define NEARTIME (182u * SECSPERDAY) |
27 | | |
28 | | /* |
29 | | * local calendar helpers |
30 | | */ |
31 | | static int32 ntp_to_year(u_int32); |
32 | | static u_int32 year_to_ntp(int32); |
33 | | |
34 | | /* |
35 | | * Take a time spec given as day-of-year, hour, minute and second as |
36 | | * well as a GMT offset in hours and convert it to a NTP time stamp in |
37 | | * '*ts_ui'. The value will be in the range (rec_ui-0.5yrs) to |
38 | | * (rec_ui+0.5yrs). A hint for the current start-of-year will be |
39 | | * read from '*yearstart'. |
40 | | * |
41 | | * On return '*ts_ui' will always the best matching solution, and |
42 | | * '*yearstart' will receive the associated start-of-year. |
43 | | * |
44 | | * The function will tell if the result in 'ts_ui' is in CLOSETIME |
45 | | * (+/-4hrs) around the receive time by returning a non-zero value. |
46 | | * |
47 | | * Note: The function puts no constraints on the value ranges for the |
48 | | * time specification, but evaluates the effective seconds in |
49 | | * 32-bit arithmetic. |
50 | | */ |
51 | | int |
52 | | clocktime( |
53 | | int yday , /* day-of-year */ |
54 | | int hour , /* hour of day */ |
55 | | int minute , /* minute of hour */ |
56 | | int second , /* second of minute */ |
57 | | int tzoff , /* hours west of GMT */ |
58 | | u_int32 rec_ui , /* pivot value */ |
59 | | u_long *yearstart, /* cached start-of-year, should be fixed to u_int32 */ |
60 | | u_int32 *ts_ui ) /* effective time stamp */ |
61 | 0 | { |
62 | 0 | u_int32 ystt[3]; /* year start */ |
63 | 0 | u_int32 test[3]; /* result time stamp */ |
64 | 0 | u_int32 diff[3]; /* abs difference to receive */ |
65 | 0 | int32 y, tmp, idx, min; |
66 | | |
67 | | /* |
68 | | * Compute the offset into the year in seconds. Note that |
69 | | * this could come out to be a negative number. |
70 | | */ |
71 | 0 | tmp = ((int32)second + |
72 | 0 | SECSPERMIN * ((int32)minute + |
73 | 0 | MINSPERHR * ((int32)hour + (int32)tzoff + |
74 | 0 | HRSPERDAY * ((int32)yday - 1)))); |
75 | | /* |
76 | | * Based on the cached year start, do a first attempt. Be |
77 | | * happy and return if this gets us better than NEARTIME to |
78 | | * the receive time stamp. Do this only if the cached year |
79 | | * start is not zero, which will not happen after 1900 for the |
80 | | * next few thousand years. |
81 | | */ |
82 | 0 | if (*yearstart) { |
83 | | /* -- get time stamp of potential solution */ |
84 | 0 | test[0] = (u_int32)(*yearstart) + tmp; |
85 | | /* -- calc absolute difference to receive time */ |
86 | 0 | diff[0] = test[0] - rec_ui; |
87 | 0 | if (diff[0] >= 0x80000000u) |
88 | 0 | diff[0] = ~diff[0] + 1; |
89 | | /* -- can't get closer if diff < NEARTIME */ |
90 | 0 | if (diff[0] < NEARTIME) { |
91 | 0 | *ts_ui = test[0]; |
92 | 0 | return diff[0] < CLOSETIME; |
93 | 0 | } |
94 | 0 | } |
95 | | |
96 | | /* |
97 | | * Now the dance begins. Based on the receive time stamp and |
98 | | * the seconds offset in 'tmp', we make an educated guess |
99 | | * about the year to start with. This takes us on the spot |
100 | | * with a fuzz of +/-1 year. |
101 | | * |
102 | | * We calculate the effective timestamps for the three years |
103 | | * around the guess and select the entry with the minimum |
104 | | * absolute difference to the receive time stamp. |
105 | | */ |
106 | 0 | y = ntp_to_year(rec_ui - tmp); |
107 | 0 | for (idx = 0; idx < 3; idx++) { |
108 | | /* -- get year start of potential solution */ |
109 | 0 | ystt[idx] = year_to_ntp(y + idx - 1); |
110 | | /* -- get time stamp of potential solution */ |
111 | 0 | test[idx] = ystt[idx] + tmp; |
112 | | /* -- calc absolute difference to receive time */ |
113 | 0 | diff[idx] = test[idx] - rec_ui; |
114 | 0 | if (diff[idx] >= 0x80000000u) |
115 | 0 | diff[idx] = ~diff[idx] + 1; |
116 | 0 | } |
117 | | /* -*- assume current year fits best, then search best fit */ |
118 | 0 | for (min = 1, idx = 0; idx < 3; idx++) |
119 | 0 | if (diff[idx] < diff[min]) |
120 | 0 | min = idx; |
121 | | /* -*- store results and update year start */ |
122 | 0 | *ts_ui = test[min]; |
123 | 0 | *yearstart = ystt[min]; |
124 | | |
125 | | /* -*- tell if we could get into CLOSETIME*/ |
126 | 0 | return diff[min] < CLOSETIME; |
127 | 0 | } |
128 | | |
129 | | static int32 |
130 | | ntp_to_year( |
131 | | u_int32 ntp) |
132 | 0 | { |
133 | 0 | vint64 t; |
134 | 0 | ntpcal_split s; |
135 | |
|
136 | 0 | t = ntpcal_ntp_to_ntp(ntp, NULL); |
137 | 0 | s = ntpcal_daysplit(&t); |
138 | 0 | s = ntpcal_split_eradays(s.hi + DAY_NTP_STARTS - 1, NULL); |
139 | 0 | return s.hi + 1; |
140 | 0 | } |
141 | | |
142 | | static u_int32 |
143 | | year_to_ntp( |
144 | | int32 year) |
145 | 0 | { |
146 | 0 | u_int32 days; |
147 | 0 | days = ntpcal_days_in_years(year-1) - DAY_NTP_STARTS + 1; |
148 | 0 | return days * SECSPERDAY; |
149 | 0 | } |