xref: /csrg-svn/usr.sbin/timed/timedc/cmds.c (revision 34775)
123785Sgusella /*
223785Sgusella  * Copyright (c) 1983 Regents of the University of California.
333123Sbostic  * All rights reserved.
433123Sbostic  *
533123Sbostic  * Redistribution and use in source and binary forms are permitted
6*34775Sbostic  * provided that the above copyright notice and this paragraph are
7*34775Sbostic  * duplicated in all such forms and that any documentation,
8*34775Sbostic  * advertising materials, and other materials related to such
9*34775Sbostic  * distribution and use acknowledge that the software was developed
10*34775Sbostic  * by the University of California, Berkeley.  The name of the
11*34775Sbostic  * University may not be used to endorse or promote products derived
12*34775Sbostic  * from this software without specific prior written permission.
13*34775Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*34775Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*34775Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1623785Sgusella  */
1723785Sgusella 
1823785Sgusella #ifndef lint
19*34775Sbostic static char sccsid[] = "@(#)cmds.c	2.5 (Berkeley) 06/18/88";
2033123Sbostic #endif /* not lint */
2123785Sgusella 
2223785Sgusella #include "timedc.h"
2323785Sgusella #include <netinet/in_systm.h>
2423785Sgusella #include <netinet/ip.h>
2523785Sgusella #include <netinet/ip_icmp.h>
2623785Sgusella #define TSPTYPES
2723785Sgusella #include <protocols/timed.h>
2823785Sgusella #include <sys/file.h>
2923785Sgusella 
3023785Sgusella int id;
3123785Sgusella int sock;
3223785Sgusella int sock_raw;
3324904Sbloom char hostname[MAXHOSTNAMELEN];
3423785Sgusella struct hostent *hp, *gethostbyname();
3523785Sgusella struct sockaddr_in server;
3623785Sgusella extern int measure_delta;
3723785Sgusella int bytenetorder(), bytehostorder();
3823785Sgusella char *strcpy();
3923785Sgusella 
4023785Sgusella /*
4123785Sgusella  * Clockdiff computes the difference between the time of the machine on
4223785Sgusella  * which it is called and the time of the machines given as argument.
4323785Sgusella  * The time differences measured by clockdiff are obtained using a sequence
4423785Sgusella  * of ICMP TSTAMP messages which are returned to the sender by the IP module
4523785Sgusella  * in the remote machine.
4623785Sgusella  * In order to compare clocks of machines in different time zones, the time
4723785Sgusella  * is transmitted (as a 32-bit value) in milliseconds since midnight UT.
4823785Sgusella  * If a hosts uses a different time format, it should set the high order
4923785Sgusella  * bit of the 32-bit quantity it transmits.
5023785Sgusella  * However, VMS apparently transmits the time in milliseconds since midnight
5123785Sgusella  * local time (rather than GMT) without setting the high order bit.
5223785Sgusella  * Furthermore, it does not understand daylight-saving time.  This makes
5323785Sgusella  * clockdiff behaving inconsistently with hosts running VMS.
5423785Sgusella  *
5523785Sgusella  * In order to reduce the sensitivity to the variance of message transmission
5623785Sgusella  * time, clockdiff sends a sequence of messages.  Yet, measures between
5723785Sgusella  * two `distant' hosts can be affected by a small error. The error can, however,
5823785Sgusella  * be reduced by increasing the number of messages sent in each measurement.
5923785Sgusella  */
6023785Sgusella 
6123785Sgusella clockdiff(argc, argv)
6223785Sgusella int argc;
6323785Sgusella char *argv[];
6423785Sgusella {
6523785Sgusella 	int measure_status;
6623785Sgusella 	struct timeval ack;
6723785Sgusella 	int measure();
6823785Sgusella 
6923785Sgusella 	if(argc < 2)  {
7023785Sgusella 		printf("Usage: clockdiff host ... \n");
7123785Sgusella 		return;
7223785Sgusella 	}
7323785Sgusella 
7423785Sgusella 	id = getpid();
7523785Sgusella 	(void)gethostname(hostname,sizeof(hostname));
7623785Sgusella 
7723785Sgusella 	while (argc > 1) {
7823785Sgusella 		argc--; argv++;
7923785Sgusella 		hp = gethostbyname(*argv);
8023785Sgusella 		if (hp == NULL) {
8123785Sgusella 			printf("%s: unknown host\n", *argv);
8223785Sgusella 			continue;
8323785Sgusella 		}
8423785Sgusella 		server.sin_family = hp->h_addrtype;
8523785Sgusella 		bcopy(hp->h_addr, &(server.sin_addr.s_addr), hp->h_length);
8627239Sbloom 		ack.tv_sec = 10;
8727239Sbloom 		ack.tv_usec = 0;
8827239Sbloom 		if ((measure_status = measure(&ack, &server)) < 0) {
8923785Sgusella 			perror("measure");
9023785Sgusella 			return;
9123785Sgusella 		}
9223785Sgusella 		switch (measure_status) {
9323785Sgusella 
9423785Sgusella 		case HOSTDOWN:
9523785Sgusella 			printf("%s is down\n", hp->h_name);
9623785Sgusella 			continue;
9723785Sgusella 			break;
9823785Sgusella 		case NONSTDTIME:
9923785Sgusella 			printf("%s time transmitted in a non-standard format\n",						 hp->h_name);
10023785Sgusella 			continue;
10123785Sgusella 			break;
10223785Sgusella 		case UNREACHABLE:
10323785Sgusella 			printf("%s is unreachable\n", hp->h_name);
10423785Sgusella 			continue;
10523785Sgusella 			break;
10623785Sgusella 		default:
10723785Sgusella 			break;
10823785Sgusella 		}
10923785Sgusella 
11023785Sgusella 		if (measure_delta > 0)
11123785Sgusella 			printf("time on %s is %d ms. ahead of time on %s\n",
11223785Sgusella 						hp->h_name, measure_delta,
11323785Sgusella 						hostname);
11423785Sgusella 		else
11523785Sgusella 			if (measure_delta == 0)
11623785Sgusella 		      		printf("%s and %s have the same time\n",
11723785Sgusella 						hp->h_name, hostname);
11823785Sgusella 			else
11923785Sgusella 		      	     printf("time on %s is %d ms. behind time on %s\n",
12023785Sgusella 					hp->h_name, -measure_delta, hostname);
12123785Sgusella 	}
12223785Sgusella 	return;
12323785Sgusella }
12423785Sgusella /*
12523785Sgusella  * finds location of master timedaemon
12623785Sgusella  */
12723785Sgusella 
12823785Sgusella msite(argc)
12923785Sgusella int argc;
13023785Sgusella {
13123785Sgusella 	int length;
13225578Sbloom 	int cc;
13325578Sbloom 	fd_set ready;
13423785Sgusella 	struct sockaddr_in dest;
13523785Sgusella 	struct timeval tout;
13623785Sgusella 	struct sockaddr_in from;
13723785Sgusella 	struct tsp msg;
13823785Sgusella 	struct servent *srvp;
13923785Sgusella 
14023785Sgusella 	if (argc != 1) {
14123785Sgusella 		printf("Usage: msite\n");
14223785Sgusella 		return;
14323785Sgusella 	}
14423785Sgusella 
14523785Sgusella 	srvp = getservbyname("timed", "udp");
14623785Sgusella 	if (srvp == 0) {
14723785Sgusella 		fprintf(stderr, "udp/timed: unknown service\n");
14823785Sgusella 		return;
14923785Sgusella 	}
15023785Sgusella 	dest.sin_port = srvp->s_port;
15123785Sgusella 	dest.sin_family = AF_INET;
15223785Sgusella 
15323785Sgusella 	(void)gethostname(hostname,sizeof(hostname));
15423785Sgusella 	hp = gethostbyname(hostname);
15523785Sgusella 	if (hp == NULL) {
15623785Sgusella 		perror("gethostbyname");
15723785Sgusella 		return;
15823785Sgusella 	}
15923785Sgusella 	bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
16023785Sgusella 
16123785Sgusella 	(void)strcpy(msg.tsp_name, hostname);
16223785Sgusella 	msg.tsp_type = TSP_MSITE;
16323785Sgusella 	msg.tsp_vers = TSPVERSION;
16423785Sgusella 	bytenetorder(&msg);
16523785Sgusella 	length = sizeof(struct sockaddr_in);
16623785Sgusella 	if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
16723785Sgusella 						&dest, length) < 0) {
16823785Sgusella 		perror("sendto");
16923785Sgusella 		return;
17023785Sgusella 	}
17123785Sgusella 
17223785Sgusella 	tout.tv_sec = 15;
17323785Sgusella 	tout.tv_usec = 0;
17425578Sbloom 	FD_ZERO(&ready);
17525578Sbloom 	FD_SET(sock, &ready);
17625578Sbloom 	if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) {
17723785Sgusella 		length = sizeof(struct sockaddr_in);
17823785Sgusella 		cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0,
17923785Sgusella 							&from, &length);
18023785Sgusella 		if (cc < 0) {
18123785Sgusella 			perror("recvfrom");
18223785Sgusella 			return;
18323785Sgusella 		}
18423785Sgusella 		bytehostorder(&msg);
18523785Sgusella 		if (msg.tsp_type == TSP_ACK)
18623785Sgusella 			printf("master timedaemon runs on %s\n", msg.tsp_name);
18723785Sgusella 		else
18823785Sgusella 			printf("received wrong ack: %s\n",
18923785Sgusella 						tsptype[msg.tsp_type]);
19023785Sgusella 	} else
19123785Sgusella 		printf("communication error\n");
19223785Sgusella }
19323785Sgusella 
19423785Sgusella /*
19523785Sgusella  * quits timedc
19623785Sgusella  */
19723785Sgusella 
19823785Sgusella quit()
19923785Sgusella {
20023785Sgusella 	exit(0);
20123785Sgusella }
20223785Sgusella 
20323785Sgusella #define MAXH	4	/* max no. of hosts where election can occur */
20423785Sgusella 
20523785Sgusella /*
20623785Sgusella  * Causes the election timer to expire on the selected hosts
20723785Sgusella  * It sends just one udp message per machine, relying on
20823785Sgusella  * reliability of communication channel.
20923785Sgusella  */
21023785Sgusella 
21123785Sgusella testing(argc, argv)
21223785Sgusella int argc;
21323785Sgusella char *argv[];
21423785Sgusella {
21523785Sgusella 	int length;
21623785Sgusella 	int nhosts;
21723785Sgusella 	struct servent *srvp;
21823785Sgusella 	struct sockaddr_in sin[MAXH];
21923785Sgusella 	struct tsp msg;
22023785Sgusella 
22123785Sgusella 	if(argc < 2)  {
22223785Sgusella 		printf("Usage: testing host ...\n");
22323785Sgusella 		return;
22423785Sgusella 	}
22523785Sgusella 
22623785Sgusella 	srvp = getservbyname("timed", "udp");
22723785Sgusella 	if (srvp == 0) {
22823785Sgusella 		fprintf(stderr, "udp/timed: unknown service\n");
22923785Sgusella 		return;
23023785Sgusella 	}
23123785Sgusella 
23223785Sgusella 	nhosts = 0;
23323785Sgusella 	while (argc > 1) {
23423785Sgusella 		argc--; argv++;
23523785Sgusella 		hp = gethostbyname(*argv);
23623785Sgusella 		if (hp == NULL) {
23730101Sbostic 			printf("%s: unknown host\n", *argv);
23823785Sgusella 			argc--; argv++;
23923785Sgusella 			continue;
24023785Sgusella 		}
24123785Sgusella 		sin[nhosts].sin_port = srvp->s_port;
24223785Sgusella 		sin[nhosts].sin_family = hp->h_addrtype;
24323785Sgusella 		bcopy(hp->h_addr, &(sin[nhosts].sin_addr.s_addr), hp->h_length);
24423785Sgusella 		if (++nhosts == MAXH)
24523785Sgusella 			break;
24623785Sgusella 	}
24723785Sgusella 
24823785Sgusella 	msg.tsp_type = TSP_TEST;
24923785Sgusella 	msg.tsp_vers = TSPVERSION;
25023785Sgusella 	(void)gethostname(hostname, sizeof(hostname));
25123785Sgusella 	(void)strcpy(msg.tsp_name, hostname);
25223785Sgusella 	bytenetorder(&msg);	/* it is not really necessary here */
25323785Sgusella 	while (nhosts-- > 0) {
25423785Sgusella 		length = sizeof(struct sockaddr_in);
25523785Sgusella 		if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
25623785Sgusella 						&sin[nhosts], length) < 0) {
25723785Sgusella 			perror("sendto");
25823785Sgusella 			return;
25923785Sgusella 		}
26023785Sgusella 	}
26123785Sgusella }
26223785Sgusella 
26323785Sgusella /*
26423785Sgusella  * Enables or disables tracing on local timedaemon
26523785Sgusella  */
26623785Sgusella 
26723785Sgusella tracing(argc, argv)
26823785Sgusella int argc;
26923785Sgusella char *argv[];
27023785Sgusella {
27123785Sgusella 	int onflag;
27223785Sgusella 	int length;
27325578Sbloom 	int cc;
27425578Sbloom 	fd_set ready;
27523785Sgusella 	struct sockaddr_in dest;
27623785Sgusella 	struct timeval tout;
27723785Sgusella 	struct sockaddr_in from;
27823785Sgusella 	struct tsp msg;
27923785Sgusella 	struct servent *srvp;
28023785Sgusella 
28123785Sgusella 	if (argc != 2) {
28223785Sgusella 		printf("Usage: tracing { on | off }\n");
28323785Sgusella 		return;
28423785Sgusella 	}
28523785Sgusella 
28623785Sgusella 	srvp = getservbyname("timed", "udp");
28723785Sgusella 	if (srvp == 0) {
28823785Sgusella 		fprintf(stderr, "udp/timed: unknown service\n");
28923785Sgusella 		return;
29023785Sgusella 	}
29123785Sgusella 	dest.sin_port = srvp->s_port;
29223785Sgusella 	dest.sin_family = AF_INET;
29323785Sgusella 
29423785Sgusella 	(void)gethostname(hostname,sizeof(hostname));
29523785Sgusella 	hp = gethostbyname(hostname);
29623785Sgusella 	bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
29723785Sgusella 
29823785Sgusella 	if (strcmp(argv[1], "on") == 0) {
29923785Sgusella 		msg.tsp_type = TSP_TRACEON;
30023785Sgusella 		onflag = ON;
30123785Sgusella 	} else {
30223785Sgusella 		msg.tsp_type = TSP_TRACEOFF;
30323785Sgusella 		onflag = OFF;
30423785Sgusella 	}
30523785Sgusella 
30623785Sgusella 	(void)strcpy(msg.tsp_name, hostname);
30723785Sgusella 	msg.tsp_vers = TSPVERSION;
30823785Sgusella 	bytenetorder(&msg);
30923785Sgusella 	length = sizeof(struct sockaddr_in);
31023785Sgusella 	if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
31123785Sgusella 						&dest, length) < 0) {
31223785Sgusella 		perror("sendto");
31323785Sgusella 		return;
31423785Sgusella 	}
31523785Sgusella 
31623785Sgusella 	tout.tv_sec = 5;
31723785Sgusella 	tout.tv_usec = 0;
31825578Sbloom 	FD_ZERO(&ready);
31925578Sbloom 	FD_SET(sock, &ready);
32025578Sbloom 	if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) {
32123785Sgusella 		length = sizeof(struct sockaddr_in);
32223785Sgusella 		cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0,
32323785Sgusella 							&from, &length);
32423785Sgusella 		if (cc < 0) {
32523785Sgusella 			perror("recvfrom");
32623785Sgusella 			return;
32723785Sgusella 		}
32823785Sgusella 		bytehostorder(&msg);
32923785Sgusella 		if (msg.tsp_type == TSP_ACK)
33023785Sgusella 			if (onflag)
33123785Sgusella 				printf("timed tracing enabled\n");
33223785Sgusella 			else
33323785Sgusella 				printf("timed tracing disabled\n");
33423785Sgusella 		else
33523785Sgusella 			printf("wrong ack received: %s\n",
33623785Sgusella 						tsptype[msg.tsp_type]);
33723785Sgusella 	} else
33823785Sgusella 		printf("communication error\n");
33923785Sgusella }
34023785Sgusella 
34123785Sgusella priv_resources()
34223785Sgusella {
34323785Sgusella 	int port;
34423785Sgusella 	struct sockaddr_in sin;
34523785Sgusella 
34623785Sgusella 	sock = socket(AF_INET, SOCK_DGRAM, 0);
34723785Sgusella 	if (sock < 0) {
34823785Sgusella 		perror("opening socket");
34923785Sgusella 		return(-1);
35023785Sgusella 	}
35123785Sgusella 
35223785Sgusella 	sin.sin_family = AF_INET;
35323785Sgusella 	sin.sin_addr.s_addr = 0;
35423785Sgusella 	for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
35523785Sgusella 		sin.sin_port = htons((u_short)port);
35623785Sgusella 		if (bind(sock, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
35723785Sgusella 			break;
35823785Sgusella 		if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) {
35923785Sgusella 			perror("bind");
36023785Sgusella 			(void) close(sock);
36123785Sgusella 			return(-1);
36223785Sgusella 		}
36323785Sgusella 	}
36423785Sgusella 	if (port == IPPORT_RESERVED / 2) {
36523785Sgusella 		fprintf(stderr, "all reserved ports in use\n");
36623785Sgusella 		(void) close(sock);
36723785Sgusella 		return(-1);
36823785Sgusella 	}
36923785Sgusella 
37023785Sgusella 	sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
37123785Sgusella 	if (sock_raw < 0)  {
37223785Sgusella 		perror("opening raw socket");
37323785Sgusella 		(void) close(sock_raw);
37423785Sgusella 		return(-1);
37523785Sgusella 	}
37623785Sgusella 	return(1);
37723785Sgusella }
378