xref: /original-bsd/usr.sbin/timed/timedc/cmds.c (revision 2bb802fc)
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.6 (Berkeley) 10/11/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 			fprintf(stderr, "timed: %s: ", *argv);
82 			herror((char *)NULL);
83 			continue;
84 		}
85 		server.sin_family = hp->h_addrtype;
86 		bcopy(hp->h_addr, &(server.sin_addr.s_addr), hp->h_length);
87 		ack.tv_sec = 10;
88 		ack.tv_usec = 0;
89 		if ((measure_status = measure(&ack, &server)) < 0) {
90 			perror("measure");
91 			return;
92 		}
93 		switch (measure_status) {
94 
95 		case HOSTDOWN:
96 			printf("%s is down\n", hp->h_name);
97 			continue;
98 			break;
99 		case NONSTDTIME:
100 			printf("%s time transmitted in a non-standard format\n",						 hp->h_name);
101 			continue;
102 			break;
103 		case UNREACHABLE:
104 			printf("%s is unreachable\n", hp->h_name);
105 			continue;
106 			break;
107 		default:
108 			break;
109 		}
110 
111 		if (measure_delta > 0)
112 			printf("time on %s is %d ms. ahead of time on %s\n",
113 						hp->h_name, measure_delta,
114 						hostname);
115 		else
116 			if (measure_delta == 0)
117 		      		printf("%s and %s have the same time\n",
118 						hp->h_name, hostname);
119 			else
120 		      	     printf("time on %s is %d ms. behind time on %s\n",
121 					hp->h_name, -measure_delta, hostname);
122 	}
123 	return;
124 }
125 /*
126  * finds location of master timedaemon
127  */
128 
129 msite(argc)
130 int argc;
131 {
132 	int length;
133 	int cc;
134 	fd_set ready;
135 	struct sockaddr_in dest;
136 	struct timeval tout;
137 	struct sockaddr_in from;
138 	struct tsp msg;
139 	struct servent *srvp;
140 
141 	if (argc != 1) {
142 		printf("Usage: msite\n");
143 		return;
144 	}
145 
146 	srvp = getservbyname("timed", "udp");
147 	if (srvp == 0) {
148 		fprintf(stderr, "udp/timed: unknown service\n");
149 		return;
150 	}
151 	dest.sin_port = srvp->s_port;
152 	dest.sin_family = AF_INET;
153 
154 	(void)gethostname(hostname, sizeof(hostname));
155 	hp = gethostbyname(hostname);
156 	if (hp == NULL) {
157 		fprintf(stderr, "timed: %s: ", hostname);
158 		herror((char *)NULL);
159 		return;
160 	}
161 	bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
162 
163 	(void)strcpy(msg.tsp_name, hostname);
164 	msg.tsp_type = TSP_MSITE;
165 	msg.tsp_vers = TSPVERSION;
166 	bytenetorder(&msg);
167 	length = sizeof(struct sockaddr_in);
168 	if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
169 						&dest, length) < 0) {
170 		perror("sendto");
171 		return;
172 	}
173 
174 	tout.tv_sec = 15;
175 	tout.tv_usec = 0;
176 	FD_ZERO(&ready);
177 	FD_SET(sock, &ready);
178 	if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) {
179 		length = sizeof(struct sockaddr_in);
180 		cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0,
181 							&from, &length);
182 		if (cc < 0) {
183 			perror("recvfrom");
184 			return;
185 		}
186 		bytehostorder(&msg);
187 		if (msg.tsp_type == TSP_ACK)
188 			printf("master timedaemon runs on %s\n", msg.tsp_name);
189 		else
190 			printf("received wrong ack: %s\n",
191 						tsptype[msg.tsp_type]);
192 	} else
193 		printf("communication error\n");
194 }
195 
196 /*
197  * quits timedc
198  */
199 
200 quit()
201 {
202 	exit(0);
203 }
204 
205 #define MAXH	4	/* max no. of hosts where election can occur */
206 
207 /*
208  * Causes the election timer to expire on the selected hosts
209  * It sends just one udp message per machine, relying on
210  * reliability of communication channel.
211  */
212 
213 testing(argc, argv)
214 int argc;
215 char *argv[];
216 {
217 	int length;
218 	int nhosts;
219 	struct servent *srvp;
220 	struct sockaddr_in sin[MAXH];
221 	struct tsp msg;
222 
223 	if(argc < 2)  {
224 		printf("Usage: testing host ...\n");
225 		return;
226 	}
227 
228 	srvp = getservbyname("timed", "udp");
229 	if (srvp == 0) {
230 		fprintf(stderr, "udp/timed: unknown service\n");
231 		return;
232 	}
233 
234 	nhosts = 0;
235 	while (argc > 1) {
236 		argc--; argv++;
237 		hp = gethostbyname(*argv);
238 		if (hp == NULL) {
239 			fprintf(stderr, "timed: %s: ", *argv);
240 			herror((char *)NULL);
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;
277 	fd_set ready;
278 	struct sockaddr_in dest;
279 	struct timeval tout;
280 	struct sockaddr_in from;
281 	struct tsp msg;
282 	struct servent *srvp;
283 
284 	if (argc != 2) {
285 		printf("Usage: tracing { on | off }\n");
286 		return;
287 	}
288 
289 	srvp = getservbyname("timed", "udp");
290 	if (srvp == 0) {
291 		fprintf(stderr, "udp/timed: unknown service\n");
292 		return;
293 	}
294 	dest.sin_port = srvp->s_port;
295 	dest.sin_family = AF_INET;
296 
297 	(void)gethostname(hostname,sizeof(hostname));
298 	hp = gethostbyname(hostname);
299 	bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
300 
301 	if (strcmp(argv[1], "on") == 0) {
302 		msg.tsp_type = TSP_TRACEON;
303 		onflag = ON;
304 	} else {
305 		msg.tsp_type = TSP_TRACEOFF;
306 		onflag = OFF;
307 	}
308 
309 	(void)strcpy(msg.tsp_name, hostname);
310 	msg.tsp_vers = TSPVERSION;
311 	bytenetorder(&msg);
312 	length = sizeof(struct sockaddr_in);
313 	if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
314 						&dest, length) < 0) {
315 		perror("sendto");
316 		return;
317 	}
318 
319 	tout.tv_sec = 5;
320 	tout.tv_usec = 0;
321 	FD_ZERO(&ready);
322 	FD_SET(sock, &ready);
323 	if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) {
324 		length = sizeof(struct sockaddr_in);
325 		cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0,
326 							&from, &length);
327 		if (cc < 0) {
328 			perror("recvfrom");
329 			return;
330 		}
331 		bytehostorder(&msg);
332 		if (msg.tsp_type == TSP_ACK)
333 			if (onflag)
334 				printf("timed tracing enabled\n");
335 			else
336 				printf("timed tracing disabled\n");
337 		else
338 			printf("wrong ack received: %s\n",
339 						tsptype[msg.tsp_type]);
340 	} else
341 		printf("communication error\n");
342 }
343 
344 priv_resources()
345 {
346 	int port;
347 	struct sockaddr_in sin;
348 
349 	sock = socket(AF_INET, SOCK_DGRAM, 0);
350 	if (sock < 0) {
351 		perror("opening socket");
352 		return(-1);
353 	}
354 
355 	sin.sin_family = AF_INET;
356 	sin.sin_addr.s_addr = 0;
357 	for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
358 		sin.sin_port = htons((u_short)port);
359 		if (bind(sock, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
360 			break;
361 		if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) {
362 			perror("bind");
363 			(void) close(sock);
364 			return(-1);
365 		}
366 	}
367 	if (port == IPPORT_RESERVED / 2) {
368 		fprintf(stderr, "all reserved ports in use\n");
369 		(void) close(sock);
370 		return(-1);
371 	}
372 
373 	sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
374 	if (sock_raw < 0)  {
375 		perror("opening raw socket");
376 		(void) close(sock_raw);
377 		return(-1);
378 	}
379 	return(1);
380 }
381