xref: /csrg-svn/usr.sbin/timed/timedc/cmds.c (revision 23785)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)cmds.c	1.1 (Berkeley) 06/27/85";
9 #endif not lint
10 
11 #include "timedc.h"
12 #include <netinet/in_systm.h>
13 #include <netinet/ip.h>
14 #include <netinet/ip_icmp.h>
15 #define TSPTYPES
16 #include <protocols/timed.h>
17 #include <sys/file.h>
18 
19 #define OFF	0
20 #define ON	1
21 
22 int id;
23 int sock;
24 int sock_raw;
25 char hostname[32];
26 struct hostent *hp, *gethostbyname();
27 struct sockaddr_in server;
28 extern int measure_delta;
29 int bytenetorder(), bytehostorder();
30 char *strcpy();
31 
32 /*
33  * Clockdiff computes the difference between the time of the machine on
34  * which it is called and the time of the machines given as argument.
35  * The time differences measured by clockdiff are obtained using a sequence
36  * of ICMP TSTAMP messages which are returned to the sender by the IP module
37  * in the remote machine.
38  * In order to compare clocks of machines in different time zones, the time
39  * is transmitted (as a 32-bit value) in milliseconds since midnight UT.
40  * If a hosts uses a different time format, it should set the high order
41  * bit of the 32-bit quantity it transmits.
42  * However, VMS apparently transmits the time in milliseconds since midnight
43  * local time (rather than GMT) without setting the high order bit.
44  * Furthermore, it does not understand daylight-saving time.  This makes
45  * clockdiff behaving inconsistently with hosts running VMS.
46  *
47  * In order to reduce the sensitivity to the variance of message transmission
48  * time, clockdiff sends a sequence of messages.  Yet, measures between
49  * two `distant' hosts can be affected by a small error. The error can, however,
50  * be reduced by increasing the number of messages sent in each measurement.
51  */
52 
53 clockdiff(argc, argv)
54 int argc;
55 char *argv[];
56 {
57 	int measure_status;
58 	struct timeval ack;
59 	int measure();
60 
61 	if(argc < 2)  {
62 		printf("Usage: clockdiff host ... \n");
63 		return;
64 	}
65 
66 	id = getpid();
67 	(void)gethostname(hostname,sizeof(hostname));
68 
69 	while (argc > 1) {
70 		argc--; argv++;
71 		hp = gethostbyname(*argv);
72 		if (hp == NULL) {
73 			printf("%s: unknown host\n", *argv);
74 			continue;
75 		}
76 		server.sin_family = hp->h_addrtype;
77 		bcopy(hp->h_addr, &(server.sin_addr.s_addr), hp->h_length);
78 		ack.tv_sec = 1;
79 		ack.tv_usec = 500000;
80 		if ((measure_status = measure(&ack, OFF)) < 0) {
81 			perror("measure");
82 			return;
83 		}
84 		switch (measure_status) {
85 
86 		case HOSTDOWN:
87 			printf("%s is down\n", hp->h_name);
88 			continue;
89 			break;
90 		case NONSTDTIME:
91 			printf("%s time transmitted in a non-standard format\n",						 hp->h_name);
92 			continue;
93 			break;
94 		case UNREACHABLE:
95 			printf("%s is unreachable\n", hp->h_name);
96 			continue;
97 			break;
98 		default:
99 			break;
100 		}
101 
102 		if (measure_delta > 0)
103 			printf("time on %s is %d ms. ahead of time on %s\n",
104 						hp->h_name, measure_delta,
105 						hostname);
106 		else
107 			if (measure_delta == 0)
108 		      		printf("%s and %s have the same time\n",
109 						hp->h_name, hostname);
110 			else
111 		      	     printf("time on %s is %d ms. behind time on %s\n",
112 					hp->h_name, -measure_delta, hostname);
113 	}
114 	return;
115 }
116 /*
117  * finds location of master timedaemon
118  */
119 
120 msite(argc)
121 int argc;
122 {
123 	int length;
124 	int cc, ready, found;
125 	struct sockaddr_in dest;
126 	struct timeval tout;
127 	struct sockaddr_in from;
128 	struct tsp msg;
129 	struct servent *srvp;
130 
131 	if (argc != 1) {
132 		printf("Usage: msite\n");
133 		return;
134 	}
135 
136 	(void) open("/etc/timed", O_WRONLY, 01700);
137 	if (errno != ETXTBSY) {
138 		printf("No timed on this machine\n");
139 		return;
140 	}
141 
142 	srvp = getservbyname("timed", "udp");
143 	if (srvp == 0) {
144 		fprintf(stderr, "udp/timed: unknown service\n");
145 		return;
146 	}
147 	dest.sin_port = srvp->s_port;
148 	dest.sin_family = AF_INET;
149 
150 	(void)gethostname(hostname,sizeof(hostname));
151 	hp = gethostbyname(hostname);
152 	if (hp == NULL) {
153 		perror("gethostbyname");
154 		return;
155 	}
156 	bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
157 
158 	(void)strcpy(msg.tsp_name, hostname);
159 	msg.tsp_type = TSP_MSITE;
160 	msg.tsp_vers = TSPVERSION;
161 	bytenetorder(&msg);
162 	length = sizeof(struct sockaddr_in);
163 	if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
164 						&dest, length) < 0) {
165 		perror("sendto");
166 		return;
167 	}
168 
169 	tout.tv_sec = 15;
170 	tout.tv_usec = 0;
171 	ready = 1<<sock;
172 	found = select(20, &ready, (int *)0, (int *)0, &tout);
173 	if (found) {
174 		length = sizeof(struct sockaddr_in);
175 		cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0,
176 							&from, &length);
177 		if (cc < 0) {
178 			perror("recvfrom");
179 			return;
180 		}
181 		bytehostorder(&msg);
182 		if (msg.tsp_type == TSP_ACK)
183 			printf("master timedaemon runs on %s\n", msg.tsp_name);
184 		else
185 			printf("received wrong ack: %s\n",
186 						tsptype[msg.tsp_type]);
187 	} else
188 		printf("communication error\n");
189 }
190 
191 /*
192  * quits timedc
193  */
194 
195 quit()
196 {
197 	exit(0);
198 }
199 
200 #define MAXH	4	/* max no. of hosts where election can occur */
201 
202 /*
203  * Causes the election timer to expire on the selected hosts
204  * It sends just one udp message per machine, relying on
205  * reliability of communication channel.
206  */
207 
208 testing(argc, argv)
209 int argc;
210 char *argv[];
211 {
212 	int length;
213 	int nhosts;
214 	struct servent *srvp;
215 	struct sockaddr_in sin[MAXH];
216 	struct tsp msg;
217 
218 	if(argc < 2)  {
219 		printf("Usage: testing host ...\n");
220 		return;
221 	}
222 
223 	(void) open("/etc/timed", O_WRONLY, 01700);
224 	if (errno != ETXTBSY) {
225 		printf("No timed on this machine\n");
226 		return;
227 	}
228 
229 	srvp = getservbyname("timed", "udp");
230 	if (srvp == 0) {
231 		fprintf(stderr, "udp/timed: unknown service\n");
232 		return;
233 	}
234 
235 	nhosts = 0;
236 	while (argc > 1) {
237 		argc--; argv++;
238 		hp = gethostbyname(*argv);
239 		if (hp == NULL) {
240 			printf("%s: unknown host %s\n", *argv);
241 			argc--; argv++;
242 			continue;
243 		}
244 		sin[nhosts].sin_port = srvp->s_port;
245 		sin[nhosts].sin_family = hp->h_addrtype;
246 		bcopy(hp->h_addr, &(sin[nhosts].sin_addr.s_addr), hp->h_length);
247 		if (++nhosts == MAXH)
248 			break;
249 	}
250 
251 	msg.tsp_type = TSP_TEST;
252 	msg.tsp_vers = TSPVERSION;
253 	(void)gethostname(hostname, sizeof(hostname));
254 	(void)strcpy(msg.tsp_name, hostname);
255 	bytenetorder(&msg);	/* it is not really necessary here */
256 	while (nhosts-- > 0) {
257 		length = sizeof(struct sockaddr_in);
258 		if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
259 						&sin[nhosts], length) < 0) {
260 			perror("sendto");
261 			return;
262 		}
263 	}
264 }
265 
266 /*
267  * Enables or disables tracing on local timedaemon
268  */
269 
270 tracing(argc, argv)
271 int argc;
272 char *argv[];
273 {
274 	int onflag;
275 	int length;
276 	int cc, ready, found;
277 	struct sockaddr_in dest;
278 	struct timeval tout;
279 	struct sockaddr_in from;
280 	struct tsp msg;
281 	struct servent *srvp;
282 
283 	if (argc != 2) {
284 		printf("Usage: tracing { on | off }\n");
285 		return;
286 	}
287 
288 	(void) open("/etc/timed", O_WRONLY, 01700);
289 	if (errno != ETXTBSY) {
290 		printf("No timed on this machine\n");
291 		return;
292 	}
293 
294 	srvp = getservbyname("timed", "udp");
295 	if (srvp == 0) {
296 		fprintf(stderr, "udp/timed: unknown service\n");
297 		return;
298 	}
299 	dest.sin_port = srvp->s_port;
300 	dest.sin_family = AF_INET;
301 
302 	(void)gethostname(hostname,sizeof(hostname));
303 	hp = gethostbyname(hostname);
304 	bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
305 
306 	if (strcmp(argv[1], "on") == 0) {
307 		msg.tsp_type = TSP_TRACEON;
308 		onflag = ON;
309 	} else {
310 		msg.tsp_type = TSP_TRACEOFF;
311 		onflag = OFF;
312 	}
313 
314 	(void)strcpy(msg.tsp_name, hostname);
315 	msg.tsp_vers = TSPVERSION;
316 	bytenetorder(&msg);
317 	length = sizeof(struct sockaddr_in);
318 	if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
319 						&dest, length) < 0) {
320 		perror("sendto");
321 		return;
322 	}
323 
324 	tout.tv_sec = 5;
325 	tout.tv_usec = 0;
326 	ready = 1<<sock;
327 	found = select(20, &ready, (int *)0, (int *)0, &tout);
328 	if (found) {
329 		length = sizeof(struct sockaddr_in);
330 		cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0,
331 							&from, &length);
332 		if (cc < 0) {
333 			perror("recvfrom");
334 			return;
335 		}
336 		bytehostorder(&msg);
337 		if (msg.tsp_type == TSP_ACK)
338 			if (onflag)
339 				printf("timed tracing enabled\n");
340 			else
341 				printf("timed tracing disabled\n");
342 		else
343 			printf("wrong ack received: %s\n",
344 						tsptype[msg.tsp_type]);
345 	} else
346 		printf("communication error\n");
347 }
348 
349 priv_resources()
350 {
351 	int port;
352 	struct sockaddr_in sin;
353 
354 	sock = socket(AF_INET, SOCK_DGRAM, 0);
355 	if (sock < 0) {
356 		perror("opening socket");
357 		return(-1);
358 	}
359 
360 	sin.sin_family = AF_INET;
361 	sin.sin_addr.s_addr = 0;
362 	for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
363 		sin.sin_port = htons((u_short)port);
364 		if (bind(sock, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
365 			break;
366 		if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) {
367 			perror("bind");
368 			(void) close(sock);
369 			return(-1);
370 		}
371 	}
372 	if (port == IPPORT_RESERVED / 2) {
373 		fprintf(stderr, "all reserved ports in use\n");
374 		(void) close(sock);
375 		return(-1);
376 	}
377 
378 	sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
379 	if (sock_raw < 0)  {
380 		perror("opening raw socket");
381 		(void) close(sock_raw);
382 		return(-1);
383 	}
384 	return(1);
385 }
386