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#define FOR_sntp
32#include "toys.h"
33
34GLOBALS(
35 long r;
36 char *p, *m, *M;
37)
38
39
40#define SEVENTIES 2208988800L
41
42
43
44
45
46static unsigned long long lunchtime(struct timespec *television, long long diff)
47{
48 struct timespec tv;
49
50 clock_gettime(CLOCK_REALTIME, &tv);
51 if (diff) nanomove(&tv, diff);
52
53 if (television) *television = tv;
54
55
56
57
58 return ((tv.tv_sec+SEVENTIES)<<32)+(((long long)tv.tv_nsec)<<32)/1000000000;
59}
60
61
62static void doublyso(unsigned long long now, struct timespec *tv)
63{
64
65 tv->tv_sec = (now>>32) + (1LL<<32)*!(now&(1LL<<63));
66 tv->tv_sec -= SEVENTIES;
67 tv->tv_nsec = ((now&0xFFFFFFFF)*1000000000)>>32;
68}
69
70void sntp_main(void)
71{
72 struct timespec tv, tv2;
73 unsigned long long *pktime = (void *)toybuf, now, then, before = before;
74 long long diff = 0;
75 struct addrinfo *ai;
76 union socksaddr sa;
77 int fd, tries = 0;
78
79 if (!(FLAG(S)||FLAG(m)) && !*toys.optargs)
80 error_exit("Need -Sm or SERVER address");
81
82
83 if (!TT.p || !*TT.p) TT.p = "123";
84 ai = xgetaddrinfo(*toys.optargs, TT.p, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
85 AI_PASSIVE*!*toys.optargs);
86
87 if (FLAG(d) && daemon(0, 0)) perror_exit("daemonize");
88
89
90 if (FLAG(S)|FLAG(m)) {
91 fd = xbindany(ai);
92 if (TT.m) {
93 struct ip_mreq group;
94
95
96 memset(&group, 0, sizeof(group));
97 group.imr_multiaddr.s_addr = inet_addr(TT.m);
98 xsetsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &group, sizeof(group));
99 }
100 } else fd = xsocket(ai->ai_family, SOCK_DGRAM, IPPROTO_UDP);
101
102
103
104
105
106
107 for (;;) {
108 now = millitime();
109
110
111 if (FLAG(m) || FLAG(S)) then = -1;
112
113
114 else {
115 then = now + 3000;
116 if (FLAG(d) || FLAG(D)) then = now + (1<<TT.r)*1000;
117
118
119 memset(toybuf, 0, 48);
120 *toybuf = 0xe3;
121 toybuf[2] = 8;
122 pktime[5] = SWAP_BE64(before = lunchtime(&tv, diff));
123 xsendto(fd, toybuf, 48, ai->ai_addr);
124 }
125
126
127 for (;;) {
128 int strike;
129
130
131
132 if (then>0 && then<(now = millitime())) break;;
133 strike = xrecvwait(fd, toybuf, sizeof(toybuf), &sa, then-now);
134 if (strike<1) {
135 if (!(FLAG(S)||FLAG(m)||FLAG(D)||FLAG(d)) && ++tries == 3)
136 error_exit("no reply from %s", *toys.optargs);
137 break;
138 }
139 if (strike<48) continue;
140
141
142 if (!FLAG(S) || FLAG(m)) {
143 char buf[128];
144 int mode = 7&*toybuf;
145
146
147 xstrncpy(buf, ntop(ai->ai_addr), 128);
148 strike = strcmp(buf, ntop((void *)&sa));
149
150 if (!FLAG(S) && !FLAG(m) && before != SWAP_BE64(pktime[3])) continue;
151
152 if (strike && !FLAG(S)) continue;
153 if (!((FLAG(m) && mode==5) || (FLAG(S) && mode==3) ||
154 (!FLAG(m) && !FLAG(S) && mode==4))) continue;
155 }
156
157
158 if (strike) {
159 char *buf = toybuf+48;
160
161 *buf = 0x24;
162 buf[1] = 3;
163 buf[2] = 10;
164 buf[3] = 250;
165 strcpy(buf+12, "LOCL");
166 pktime[6+3] = pktime[5];
167
168 pktime[6+2] = pktime[6+4] = pktime[6+5] = SWAP_BE64(lunchtime(0, 0));
169 xsendto(fd, buf, 48, (void *)&sa);
170
171
172 } else {
173 int unset = !diff;
174
175
176
177
178
179
180
181 lunchtime(&tv2, diff);
182 diff = nanodiff(&tv, &tv2);
183 if (unset && diff) break;
184
185
186
187
188
189
190
191
192 nanomove(&tv, diff/2);
193 doublyso(SWAP_BE64(pktime[5]), &tv2);
194 diff = nanodiff(&tv, &tv2);
195
196 if (FLAG(s)) {
197
198 clock_gettime(CLOCK_REALTIME, &tv2);
199 nanomove(&tv2, diff);
200 if (clock_settime(CLOCK_REALTIME, &tv2))
201 perror_exit("clock_settime");
202 } else if (FLAG(a)) {
203 struct timeval why;
204
205
206
207 memset(&tv2, 0, sizeof(tv2));
208 nanomove(&tv2, diff);
209 why.tv_sec = tv2.tv_sec;
210 why.tv_usec = tv2.tv_nsec/1000;
211 if (adjtime(&why, 0)) perror_exit("adjtime");
212 }
213
214
215 if (!FLAG(q)) {
216 format_iso_time(toybuf, sizeof(toybuf)-1, &tv2);
217 printf("%s offset %c%lld.%09lld secs\n", toybuf, (diff<0) ? '-' : '+',
218 llabs(diff/1000000000), llabs(diff%1000000000));
219 }
220
221
222 if (!FLAG(d) && !FLAG(D)) return;
223 }
224 }
225 }
226}
227