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