aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/xntpd/lib/clocktime.c
blob: 0217f2b5c4a67d5fe304f467508aed283c31218e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
 * clocktime - compute the NTP date from a day of year, hour, minute
 *	       and second.
 */
#include "ntp_fp.h"
#include "ntp_unixtime.h"
#include "ntp_stdlib.h"

/*
 * Hacks to avoid excercising the multiplier.  I have no pride.
 */
#define	MULBY10(x)	(((x)<<3) + ((x)<<1))
#define	MULBY60(x)	(((x)<<6) - ((x)<<2))	/* watch overflow */
#define	MULBY24(x)	(((x)<<4) + ((x)<<3))

/*
 * Two days, in seconds.
 */
#define	TWODAYS		(2*24*60*60)

/*
 * We demand that the time be within CLOSETIME seconds of the receive
 * time stamp.  This is about 4 hours, which hopefully should be
 * wide enough to collect most data, while close enough to keep things
 * from getting confused.
 */
#define	CLOSETIME	(4*60*60)


int
clocktime(yday, hour, minute, second, tzoff, rec_ui, yearstart, ts_ui)
	int yday;
	int hour;
	int minute;
	int second;
	int tzoff;
	u_long rec_ui;
	u_long *yearstart;
	U_LONG *ts_ui;
{
	register long tmp;
	register u_long date;
	register u_long yst;

	/*
	 * Compute the offset into the year in seconds.  Note that
	 * this could come out to be a negative number.
	 */
	tmp = (long)(MULBY24((yday-1)) + hour + tzoff);
	tmp = MULBY60(tmp) + (long)minute;
	tmp = MULBY60(tmp) + (long)second;

	/*
	 * Initialize yearstart, if necessary.
	 */
	yst = *yearstart;
	if (yst == 0) {
		yst = calyearstart(rec_ui);
		*yearstart = yst;
	}

	/*
	 * Now the fun begins.  We demand that the received clock time
	 * be within CLOSETIME of the receive timestamp, but
	 * there is uncertainty about the year the timestamp is in.
	 * Use the current year start for the first check, this should
	 * work most of the time.
	 */
	date = (u_long)(tmp + (long)yst);
	if (date < (rec_ui + CLOSETIME) &&
	    date > (rec_ui - CLOSETIME)) {
		*ts_ui = date;
		return 1;
	}

	/*
	 * Trouble.  Next check is to see if the year rolled over and, if
	 * so, try again with the new year's start.
	 */
	yst = calyearstart(rec_ui);
	if (yst != *yearstart) {
		date = (u_long)((long)yst + tmp);
		*ts_ui = date;
		if (date < (rec_ui + CLOSETIME) &&
		    date > (rec_ui - CLOSETIME)) {
			*yearstart = yst;
			return 1;
		}
	}

	/*
	 * Here we know the year start matches the current system
	 * time.  One remaining possibility is that the time code
	 * is in the year previous to that of the system time.  This
	 * is only worth checking if the receive timestamp is less
	 * than a couple of days into the new year.
	 */
	if ((rec_ui - yst) < TWODAYS) {
		yst = calyearstart(yst - TWODAYS);
		if (yst != *yearstart) {
			date = (u_long)(tmp + (long)yst);
			if (date < (rec_ui + CLOSETIME) &&
			    date > (rec_ui - CLOSETIME)) {
				*yearstart = yst;
				*ts_ui = date;
				return 1;
			}
		}
	}

	/*
	 * One last possibility is that the time stamp is in the year
	 * following the year the system is in.  Try this one before
	 * giving up.
	 */
	yst = calyearstart(rec_ui + TWODAYS);
	if (yst != *yearstart) {
		date = (u_long)((long)yst + tmp);
		if (date < (rec_ui + CLOSETIME) &&
		    date > (rec_ui - CLOSETIME)) {
			*yearstart = yst;
			*ts_ui = date;
			return 1;
		}
	}

	/*
	 * Give it up.
	 */
	return 0;
}