Coverage Report

Created: 2023-05-19 06:16

/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
}