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