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 #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 #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 { 62 u_int32 ystt[3]; /* year start */ 63 u_int32 test[3]; /* result time stamp */ 64 u_int32 diff[3]; /* abs difference to receive */ 65 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 tmp = ((int32)second + 72 SECSPERMIN * ((int32)minute + 73 MINSPERHR * ((int32)hour + (int32)tzoff + 74 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 if (*yearstart) { 83 /* -- get time stamp of potential solution */ 84 test[0] = (u_int32)(*yearstart) + tmp; 85 /* -- calc absolute difference to receive time */ 86 diff[0] = test[0] - rec_ui; 87 if (diff[0] >= 0x80000000u) 88 diff[0] = ~diff[0] + 1; 89 /* -- can't get closer if diff < NEARTIME */ 90 if (diff[0] < NEARTIME) { 91 *ts_ui = test[0]; 92 return diff[0] < CLOSETIME; 93 } 94 } 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 y = ntp_to_year(rec_ui - tmp); 107 for (idx = 0; idx < 3; idx++) { 108 /* -- get year start of potential solution */ 109 ystt[idx] = year_to_ntp(y + idx - 1); 110 /* -- get time stamp of potential solution */ 111 test[idx] = ystt[idx] + tmp; 112 /* -- calc absolute difference to receive time */ 113 diff[idx] = test[idx] - rec_ui; 114 if (diff[idx] >= 0x80000000u) 115 diff[idx] = ~diff[idx] + 1; 116 } 117 /* -*- assume current year fits best, then search best fit */ 118 for (min = 1, idx = 0; idx < 3; idx++) 119 if (diff[idx] < diff[min]) 120 min = idx; 121 /* -*- store results and update year start */ 122 *ts_ui = test[min]; 123 *yearstart = ystt[min]; 124 125 /* -*- tell if we could get into CLOSETIME*/ 126 return diff[min] < CLOSETIME; 127 } 128 129 static int32 130 ntp_to_year( 131 u_int32 ntp) 132 { 133 vint64 t; 134 ntpcal_split s; 135 136 t = ntpcal_ntp_to_ntp(ntp, NULL); 137 s = ntpcal_daysplit(&t); 138 s = ntpcal_split_eradays(s.hi + DAY_NTP_STARTS - 1, NULL); 139 return s.hi + 1; 140 } 141 142 static u_int32 143 year_to_ntp( 144 int32 year) 145 { 146 u_int32 days; 147 days = ntpcal_days_in_years(year-1) - DAY_NTP_STARTS + 1; 148 return days * SECSPERDAY; 149 } 150