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