Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / ntp / dist / sntp / main.c
blob241f60d58a858a1d2a1a4a0b3f9664577ac2253d
1 /* $NetBSD$ */
3 #include <l_stdlib.h>
4 #include <ntp_fp.h>
5 #include <ntp.h>
6 #include <ntp_stdlib.h>
7 #include <ntp_unixtime.h>
8 #include <isc/result.h>
9 #include <isc/net.h>
10 #include <stdio.h>
12 #include <sntp-opts.h>
14 #include "crypto.h"
15 #include "kod_management.h"
16 #include "networking.h"
17 #include "utilities.h"
18 #include "log.h"
20 char *progname = "sntp"; /* for msyslog */
22 int ai_fam_pref = AF_UNSPEC;
23 volatile int debug;
25 struct key *keys = NULL;
27 void set_li_vn_mode (struct pkt *spkt, char leap, char version, char mode);
28 int sntp_main (int argc, char **argv);
29 int on_wire (struct addrinfo *host);
30 int set_time (double offset);
33 int
34 main (
35 int argc,
36 char **argv
39 return sntp_main(argc, argv);
43 * The actual main function.
45 int
46 sntp_main (
47 int argc,
48 char **argv
51 register int c;
52 struct kod_entry *reason = NULL;
53 int optct;
54 int sync_data_suc = 0;
55 struct addrinfo **resh = NULL;
56 struct addrinfo *ai;
57 int resc;
58 int kodc;
59 int ow_ret;
60 char *hostname;
62 /* IPv6 available? */
63 if (isc_net_probeipv6() != ISC_R_SUCCESS) {
64 ai_fam_pref = AF_INET;
65 #ifdef DEBUG
66 printf("No ipv6 support available, forcing ipv4\n");
67 #endif
69 else {
70 /* Check for options -4 and -6 */
71 if (HAVE_OPT(IPV4))
72 ai_fam_pref = AF_INET;
73 else if (HAVE_OPT(IPV6))
74 ai_fam_pref = AF_INET6;
77 log_msg("Started sntp", 0);
79 optct = optionProcess(&sntpOptions, argc, argv);
80 argc -= optct;
81 argv += optct;
83 /* Parse config file if declared TODO */
85 /* Initialize logging system */
86 if (HAVE_OPT(FILELOG))
87 init_log(OPT_ARG(FILELOG));
89 /*
90 * If there's a specified KOD file init KOD system. If not use
91 * default file. For embedded systems with no writable
92 * filesystem, -K /dev/null can be used to disable KoD storage.
94 if (HAVE_OPT(KOD))
95 kod_init_kod_db(OPT_ARG(KOD));
96 else
97 kod_init_kod_db("/var/db/ntp-kod");
99 if (HAVE_OPT(KEYFILE))
100 auth_init(OPT_ARG(KEYFILE), &keys);
102 #ifdef EXERCISE_KOD_DB
103 add_entry("192.168.169.170", "DENY");
104 add_entry("192.168.169.171", "DENY");
105 add_entry("192.168.169.172", "DENY");
106 add_entry("192.168.169.173", "DENY");
107 add_entry("192.168.169.174", "DENY");
108 delete_entry("192.168.169.174", "DENY");
109 delete_entry("192.168.169.172", "DENY");
110 delete_entry("192.168.169.170", "DENY");
111 if ((kodc = search_entry("192.168.169.173", &reason)) == 0)
112 printf("entry for 192.168.169.173 not found but should have been!\n");
113 else
114 free(reason);
115 #endif
117 /* Considering employing a variable that prevents functions of doing anything until
118 * everything is initialized properly
120 resc = resolve_hosts(argv, argc, &resh, ai_fam_pref);
122 if (resc < 1) {
123 printf("Unable to resolve hostname(s)\n");
124 return -1;
127 /* Select a certain ntp server according to simple criteria? For now
128 * let's just pay attention to previous KoDs.
130 for (c = 0; c < resc && !sync_data_suc; c++) {
131 ai = resh[c];
132 do {
133 hostname = addrinfo_to_str(ai);
135 if ((kodc = search_entry(hostname, &reason)) == 0) {
136 if (is_reachable(ai)) {
137 ow_ret = on_wire(ai);
138 if (ow_ret < 0)
139 printf("on_wire failed for server %s!\n", hostname);
140 else
141 sync_data_suc = 1;
143 } else {
144 printf("%d prior KoD%s for %s, skipping.\n",
145 kodc, (kodc > 1) ? "s" : "", hostname);
146 free(reason);
148 free(hostname);
149 ai = ai->ai_next;
150 } while (NULL != ai);
151 freeaddrinfo(resh[c]);
153 free(resh);
155 return 0;
158 /* The heart of (S)NTP, exchange NTP packets and compute values to correct the local clock */
160 on_wire (
161 struct addrinfo *host
164 char logmsg[32 + INET6_ADDRSTRLEN];
165 char addr_buf[INET6_ADDRSTRLEN];
166 register int try;
167 SOCKET sock;
168 struct pkt x_pkt;
169 struct pkt r_pkt;
170 char *ref;
172 for(try=0; try<5; try++) {
173 struct timeval tv_xmt, tv_dst;
174 double t21, t34, delta, offset, precision, root_dispersion;
175 int digits, error, rpktl, sw_case;
176 char *hostname = NULL, *ts_str = NULL;
177 char *log_str;
178 u_fp p_rdly, p_rdsp;
179 l_fp p_rec, p_xmt, p_ref, p_org, xmt, tmp, dst;
181 memset(&r_pkt, 0, sizeof(r_pkt));
182 memset(&x_pkt, 0, sizeof(x_pkt));
184 error = GETTIMEOFDAY(&tv_xmt, (struct timezone *)NULL);
186 tv_xmt.tv_sec += JAN_1970;
188 #ifdef DEBUG
189 printf("sntp on_wire: Current time sec: %i msec: %i\n", (unsigned int) tv_xmt.tv_sec,
190 (unsigned int) tv_xmt.tv_usec);
191 #endif
193 TVTOTS(&tv_xmt, &xmt);
194 HTONL_FP(&xmt, &(x_pkt.xmt));
196 x_pkt.stratum = STRATUM_TO_PKT(STRATUM_UNSPEC);
197 x_pkt.ppoll = 8;
198 /* FIXME! Modus broadcast + adr. check -> bdr. pkt */
199 set_li_vn_mode(&x_pkt, LEAP_NOTINSYNC, 4, 3);
201 create_socket(&sock, (sockaddr_u *)host->ai_addr);
203 sendpkt(sock, (sockaddr_u *)host->ai_addr, &x_pkt, LEN_PKT_NOMAC);
204 rpktl = recvpkt(sock, &r_pkt, &x_pkt);
206 closesocket(sock);
208 if(rpktl > 0)
209 sw_case = 1;
210 else
211 sw_case = rpktl;
213 switch(sw_case) {
214 case SERVER_UNUSEABLE:
215 return -1;
216 break;
218 case PACKET_UNUSEABLE:
219 break;
221 case SERVER_AUTH_FAIL:
222 break;
224 case KOD_DEMOBILIZE:
225 /* Received a DENY or RESTR KOD packet */
226 hostname = addrinfo_to_str(host);
227 ref = (char *)&r_pkt.refid;
228 add_entry(hostname, ref);
230 if (ENABLED_OPT(NORMALVERBOSE))
231 printf("sntp on_wire: Received KOD packet with code: %c%c%c%c from %s, demobilizing all connections\n",
232 ref[0], ref[1], ref[2], ref[3],
233 hostname);
235 log_str = emalloc(INET6_ADDRSTRLEN + 72);
236 snprintf(log_str, INET6_ADDRSTRLEN + 72,
237 "Received a KOD packet with code %c%c%c%c from %s, demobilizing all connections",
238 ref[0], ref[1], ref[2], ref[3],
239 hostname);
240 log_msg(log_str, 2);
241 free(log_str);
242 break;
244 case KOD_RATE:
245 /* Hmm... probably we should sleep a bit here */
246 break;
248 case 1:
250 /* Convert timestamps from network to host byte order */
251 p_rdly = NTOHS_FP(r_pkt.rootdelay);
252 p_rdsp = NTOHS_FP(r_pkt.rootdisp);
253 NTOHL_FP(&r_pkt.reftime, &p_ref);
254 NTOHL_FP(&r_pkt.org, &p_org);
255 NTOHL_FP(&r_pkt.rec, &p_rec);
256 NTOHL_FP(&r_pkt.xmt, &p_xmt);
258 if (ENABLED_OPT(NORMALVERBOSE)) {
259 getnameinfo(host->ai_addr, host->ai_addrlen, addr_buf,
260 sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
262 printf("sntp on_wire: Received %i bytes from %s\n", rpktl, addr_buf);
265 precision = LOGTOD(r_pkt.precision);
266 #ifdef DEBUG
267 printf("sntp precision: %f\n", precision);
268 #endif /* DEBUG */
269 for (digits = 0; (precision *= 10.) < 1.; ++digits)
270 /* empty */ ;
271 if (digits > 6)
272 digits = 6;
274 root_dispersion = FPTOD(p_rdsp);
276 #ifdef DEBUG
277 printf("sntp rootdelay: %f\n", FPTOD(p_rdly));
278 printf("sntp rootdisp: %f\n", root_dispersion);
280 pkt_output(&r_pkt, rpktl, stdout);
282 printf("sntp on_wire: r_pkt.reftime:\n");
283 l_fp_output(&(r_pkt.reftime), stdout);
284 printf("sntp on_wire: r_pkt.org:\n");
285 l_fp_output(&(r_pkt.org), stdout);
286 printf("sntp on_wire: r_pkt.rec:\n");
287 l_fp_output(&(r_pkt.rec), stdout);
288 printf("sntp on_wire: r_pkt.rec:\n");
289 l_fp_output_bin(&(r_pkt.rec), stdout);
290 printf("sntp on_wire: r_pkt.rec:\n");
291 l_fp_output_dec(&(r_pkt.rec), stdout);
292 printf("sntp on_wire: r_pkt.xmt:\n");
293 l_fp_output(&(r_pkt.xmt), stdout);
294 #endif
296 /* Compute offset etc. */
297 GETTIMEOFDAY(&tv_dst, (struct timezone *)NULL);
299 tv_dst.tv_sec += JAN_1970;
301 tmp = p_rec;
302 L_SUB(&tmp, &p_org);
304 LFPTOD(&tmp, t21);
306 TVTOTS(&tv_dst, &dst);
308 tmp = dst;
309 L_SUB(&tmp, &p_xmt);
311 LFPTOD(&tmp, t34);
313 offset = (t21 + t34) / 2.;
314 delta = t21 - t34;
316 if(ENABLED_OPT(NORMALVERBOSE))
317 printf("sntp on_wire:\tt21: %.6f\t\t t34: %.6f\n\t\tdelta: %.6f\t offset: %.6f\n",
318 t21, t34, delta, offset);
320 ts_str = tv_to_str(&tv_dst);
322 printf("%s ", ts_str);
324 if(offset > 0)
325 printf("+");
327 printf("%.*f", digits, offset);
329 if (root_dispersion > 0.)
330 printf(" +/- %f secs", root_dispersion);
332 printf("\n");
334 free(ts_str);
336 if(ENABLED_OPT(SETTOD) || ENABLED_OPT(ADJTIME))
337 return set_time(offset);
339 return 0;
343 getnameinfo(host->ai_addr, host->ai_addrlen, addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
345 snprintf(logmsg, sizeof(logmsg), "Received no useable packet from %s!", addr_buf);
346 log_msg(logmsg, 1);
348 if (ENABLED_OPT(NORMALVERBOSE))
349 printf("sntp on_wire: Received no useable packet from %s!\n", addr_buf);
351 return -1;
354 /* Compute the 8 bits for li_vn_mode */
355 void
356 set_li_vn_mode (
357 struct pkt *spkt,
358 char leap,
359 char version,
360 char mode
364 if(leap > 3) {
365 debug_msg("set_li_vn_mode: leap > 3 using max. 3");
366 leap = 3;
369 if(mode > 7) {
370 debug_msg("set_li_vn_mode: mode > 7, using client mode 3");
371 mode = 3;
374 spkt->li_vn_mode = leap << 6;
375 spkt->li_vn_mode |= version << 3;
376 spkt->li_vn_mode |= mode;
379 /* set_time corrects the local clock by offset with either settimeofday() or by default
380 * with adjtime()/adjusttimeofday().
383 set_time (
384 double offset
387 struct timeval tp;
389 if(ENABLED_OPT(SETTOD)) {
390 GETTIMEOFDAY(&tp, (struct timezone *)NULL);
392 tp.tv_sec += (int) offset;
393 tp.tv_usec += offset - (double)((int)offset);
395 if(SETTIMEOFDAY(&tp, (struct timezone *)NULL) < 0) {
396 printf("set_time: settimeofday(): Time not set: %s\n",
397 strerror(errno));
398 return -1;
400 else {
401 return 0;
404 else {
405 tp.tv_sec = (int) offset;
406 tp.tv_usec = offset - (double)((int)offset);
408 if(ADJTIMEOFDAY(&tp, NULL) < 0) {
409 printf("set_time: adjtime(): Time not set: %s\n",
410 strerror(errno));
411 return -1;
413 else {
414 return 0;