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