]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ntp/libntp/clocktime.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ntp / libntp / clocktime.c
1 /*
2  * clocktime - compute the NTP date from a day of year, hour, minute
3  *             and second.
4  */
5 #include "ntp_fp.h"
6 #include "ntp_unixtime.h"
7 #include "ntp_stdlib.h"
8
9 /*
10  * Hacks to avoid excercising the multiplier.  I have no pride.
11  */
12 #define MULBY10(x)      (((x)<<3) + ((x)<<1))
13 #define MULBY60(x)      (((x)<<6) - ((x)<<2))   /* watch overflow */
14 #define MULBY24(x)      (((x)<<4) + ((x)<<3))
15
16 /*
17  * Two days, in seconds.
18  */
19 #define TWODAYS         (2*24*60*60)
20
21 /*
22  * We demand that the time be within CLOSETIME seconds of the receive
23  * time stamp.  This is about 4 hours, which hopefully should be
24  * wide enough to collect most data, while close enough to keep things
25  * from getting confused.
26  */
27 #define CLOSETIME       (4*60*60)
28
29
30 int
31 clocktime(
32         int yday,
33         int hour,
34         int minute,
35         int second,
36         int tzoff,
37         u_long rec_ui,
38         u_long *yearstart,
39         u_int32 *ts_ui
40         )
41 {
42         register long tmp;
43         register u_long date;
44         register u_long yst;
45
46         /*
47          * Compute the offset into the year in seconds.  Note that
48          * this could come out to be a negative number.
49          */
50         tmp = (long)(MULBY24((yday-1)) + hour + tzoff);
51         tmp = MULBY60(tmp) + (long)minute;
52         tmp = MULBY60(tmp) + (long)second;
53
54         /*
55          * Initialize yearstart, if necessary.
56          */
57         yst = *yearstart;
58         if (yst == 0) {
59                 yst = calyearstart(rec_ui);
60                 *yearstart = yst;
61         }
62
63         /*
64          * Now the fun begins.  We demand that the received clock time
65          * be within CLOSETIME of the receive timestamp, but
66          * there is uncertainty about the year the timestamp is in.
67          * Use the current year start for the first check, this should
68          * work most of the time.
69          */
70         date = (u_long)(tmp + (long)yst);
71         if (date < (rec_ui + CLOSETIME) &&
72             date > (rec_ui - CLOSETIME)) {
73                 *ts_ui = date;
74                 return 1;
75         }
76
77         /*
78          * Trouble.  Next check is to see if the year rolled over and, if
79          * so, try again with the new year's start.
80          */
81         yst = calyearstart(rec_ui);
82         if (yst != *yearstart) {
83                 date = (u_long)((long)yst + tmp);
84                 *ts_ui = date;
85                 if (date < (rec_ui + CLOSETIME) &&
86                     date > (rec_ui - CLOSETIME)) {
87                         *yearstart = yst;
88                         return 1;
89                 }
90         }
91
92         /*
93          * Here we know the year start matches the current system
94          * time.  One remaining possibility is that the time code
95          * is in the year previous to that of the system time.  This
96          * is only worth checking if the receive timestamp is less
97          * than a couple of days into the new year.
98          */
99         if ((rec_ui - yst) < TWODAYS) {
100                 yst = calyearstart(yst - TWODAYS);
101                 if (yst != *yearstart) {
102                         date = (u_long)(tmp + (long)yst);
103                         if (date < (rec_ui + CLOSETIME) &&
104                             date > (rec_ui - CLOSETIME)) {
105                                 *yearstart = yst;
106                                 *ts_ui = date;
107                                 return 1;
108                         }
109                 }
110         }
111
112         /*
113          * One last possibility is that the time stamp is in the year
114          * following the year the system is in.  Try this one before
115          * giving up.
116          */
117         yst = calyearstart(rec_ui + TWODAYS);
118         if (yst != *yearstart) {
119                 date = (u_long)((long)yst + tmp);
120                 if (date < (rec_ui + CLOSETIME) &&
121                     date > (rec_ui - CLOSETIME)) {
122                         *yearstart = yst;
123                         *ts_ui = date;
124                         return 1;
125                 }
126         }
127
128         /*
129          * Give it up.
130          */
131         return 0;
132 }