xref: /csrg-svn/usr.sbin/timed/timedc/cmds.c (revision 35784)
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
634775Sbostic  * provided that the above copyright notice and this paragraph are
734775Sbostic  * duplicated in all such forms and that any documentation,
834775Sbostic  * advertising materials, and other materials related to such
934775Sbostic  * distribution and use acknowledge that the software was developed
1034775Sbostic  * by the University of California, Berkeley.  The name of the
1134775Sbostic  * University may not be used to endorse or promote products derived
1234775Sbostic  * from this software without specific prior written permission.
1334775Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434775Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1534775Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1623785Sgusella  */
1723785Sgusella 
1823785Sgusella #ifndef lint
19*35784Sbostic static char sccsid[] = "@(#)cmds.c	2.6 (Berkeley) 10/11/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) {
81*35784Sbostic 			fprintf(stderr, "timed: %s: ", *argv);
82*35784Sbostic 			herror((char *)NULL);
8323785Sgusella 			continue;
8423785Sgusella 		}
8523785Sgusella 		server.sin_family = hp->h_addrtype;
8623785Sgusella 		bcopy(hp->h_addr, &(server.sin_addr.s_addr), hp->h_length);
8727239Sbloom 		ack.tv_sec = 10;
8827239Sbloom 		ack.tv_usec = 0;
8927239Sbloom 		if ((measure_status = measure(&ack, &server)) < 0) {
9023785Sgusella 			perror("measure");
9123785Sgusella 			return;
9223785Sgusella 		}
9323785Sgusella 		switch (measure_status) {
9423785Sgusella 
9523785Sgusella 		case HOSTDOWN:
9623785Sgusella 			printf("%s is down\n", hp->h_name);
9723785Sgusella 			continue;
9823785Sgusella 			break;
9923785Sgusella 		case NONSTDTIME:
10023785Sgusella 			printf("%s time transmitted in a non-standard format\n",						 hp->h_name);
10123785Sgusella 			continue;
10223785Sgusella 			break;
10323785Sgusella 		case UNREACHABLE:
10423785Sgusella 			printf("%s is unreachable\n", hp->h_name);
10523785Sgusella 			continue;
10623785Sgusella 			break;
10723785Sgusella 		default:
10823785Sgusella 			break;
10923785Sgusella 		}
11023785Sgusella 
11123785Sgusella 		if (measure_delta > 0)
11223785Sgusella 			printf("time on %s is %d ms. ahead of time on %s\n",
11323785Sgusella 						hp->h_name, measure_delta,
11423785Sgusella 						hostname);
11523785Sgusella 		else
11623785Sgusella 			if (measure_delta == 0)
11723785Sgusella 		      		printf("%s and %s have the same time\n",
11823785Sgusella 						hp->h_name, hostname);
11923785Sgusella 			else
12023785Sgusella 		      	     printf("time on %s is %d ms. behind time on %s\n",
12123785Sgusella 					hp->h_name, -measure_delta, hostname);
12223785Sgusella 	}
12323785Sgusella 	return;
12423785Sgusella }
12523785Sgusella /*
12623785Sgusella  * finds location of master timedaemon
12723785Sgusella  */
12823785Sgusella 
12923785Sgusella msite(argc)
13023785Sgusella int argc;
13123785Sgusella {
13223785Sgusella 	int length;
13325578Sbloom 	int cc;
13425578Sbloom 	fd_set ready;
13523785Sgusella 	struct sockaddr_in dest;
13623785Sgusella 	struct timeval tout;
13723785Sgusella 	struct sockaddr_in from;
13823785Sgusella 	struct tsp msg;
13923785Sgusella 	struct servent *srvp;
14023785Sgusella 
14123785Sgusella 	if (argc != 1) {
14223785Sgusella 		printf("Usage: msite\n");
14323785Sgusella 		return;
14423785Sgusella 	}
14523785Sgusella 
14623785Sgusella 	srvp = getservbyname("timed", "udp");
14723785Sgusella 	if (srvp == 0) {
14823785Sgusella 		fprintf(stderr, "udp/timed: unknown service\n");
14923785Sgusella 		return;
150*35784Sbostic 	}
15123785Sgusella 	dest.sin_port = srvp->s_port;
15223785Sgusella 	dest.sin_family = AF_INET;
15323785Sgusella 
154*35784Sbostic 	(void)gethostname(hostname, sizeof(hostname));
15523785Sgusella 	hp = gethostbyname(hostname);
15623785Sgusella 	if (hp == NULL) {
157*35784Sbostic 		fprintf(stderr, "timed: %s: ", hostname);
158*35784Sbostic 		herror((char *)NULL);
15923785Sgusella 		return;
16023785Sgusella 	}
16123785Sgusella 	bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
16223785Sgusella 
16323785Sgusella 	(void)strcpy(msg.tsp_name, hostname);
16423785Sgusella 	msg.tsp_type = TSP_MSITE;
16523785Sgusella 	msg.tsp_vers = TSPVERSION;
16623785Sgusella 	bytenetorder(&msg);
16723785Sgusella 	length = sizeof(struct sockaddr_in);
16823785Sgusella 	if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
16923785Sgusella 						&dest, length) < 0) {
17023785Sgusella 		perror("sendto");
17123785Sgusella 		return;
17223785Sgusella 	}
17323785Sgusella 
17423785Sgusella 	tout.tv_sec = 15;
17523785Sgusella 	tout.tv_usec = 0;
17625578Sbloom 	FD_ZERO(&ready);
17725578Sbloom 	FD_SET(sock, &ready);
17825578Sbloom 	if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) {
17923785Sgusella 		length = sizeof(struct sockaddr_in);
18023785Sgusella 		cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0,
18123785Sgusella 							&from, &length);
18223785Sgusella 		if (cc < 0) {
18323785Sgusella 			perror("recvfrom");
18423785Sgusella 			return;
18523785Sgusella 		}
18623785Sgusella 		bytehostorder(&msg);
18723785Sgusella 		if (msg.tsp_type == TSP_ACK)
18823785Sgusella 			printf("master timedaemon runs on %s\n", msg.tsp_name);
18923785Sgusella 		else
19023785Sgusella 			printf("received wrong ack: %s\n",
19123785Sgusella 						tsptype[msg.tsp_type]);
19223785Sgusella 	} else
19323785Sgusella 		printf("communication error\n");
19423785Sgusella }
19523785Sgusella 
19623785Sgusella /*
19723785Sgusella  * quits timedc
19823785Sgusella  */
19923785Sgusella 
20023785Sgusella quit()
20123785Sgusella {
20223785Sgusella 	exit(0);
20323785Sgusella }
20423785Sgusella 
20523785Sgusella #define MAXH	4	/* max no. of hosts where election can occur */
20623785Sgusella 
20723785Sgusella /*
20823785Sgusella  * Causes the election timer to expire on the selected hosts
20923785Sgusella  * It sends just one udp message per machine, relying on
21023785Sgusella  * reliability of communication channel.
21123785Sgusella  */
21223785Sgusella 
21323785Sgusella testing(argc, argv)
21423785Sgusella int argc;
21523785Sgusella char *argv[];
21623785Sgusella {
21723785Sgusella 	int length;
21823785Sgusella 	int nhosts;
21923785Sgusella 	struct servent *srvp;
22023785Sgusella 	struct sockaddr_in sin[MAXH];
22123785Sgusella 	struct tsp msg;
22223785Sgusella 
22323785Sgusella 	if(argc < 2)  {
22423785Sgusella 		printf("Usage: testing host ...\n");
22523785Sgusella 		return;
22623785Sgusella 	}
22723785Sgusella 
22823785Sgusella 	srvp = getservbyname("timed", "udp");
22923785Sgusella 	if (srvp == 0) {
23023785Sgusella 		fprintf(stderr, "udp/timed: unknown service\n");
23123785Sgusella 		return;
23223785Sgusella 	}
23323785Sgusella 
23423785Sgusella 	nhosts = 0;
23523785Sgusella 	while (argc > 1) {
23623785Sgusella 		argc--; argv++;
23723785Sgusella 		hp = gethostbyname(*argv);
23823785Sgusella 		if (hp == NULL) {
239*35784Sbostic 			fprintf(stderr, "timed: %s: ", *argv);
240*35784Sbostic 			herror((char *)NULL);
24123785Sgusella 			argc--; argv++;
24223785Sgusella 			continue;
24323785Sgusella 		}
24423785Sgusella 		sin[nhosts].sin_port = srvp->s_port;
24523785Sgusella 		sin[nhosts].sin_family = hp->h_addrtype;
24623785Sgusella 		bcopy(hp->h_addr, &(sin[nhosts].sin_addr.s_addr), hp->h_length);
24723785Sgusella 		if (++nhosts == MAXH)
24823785Sgusella 			break;
24923785Sgusella 	}
25023785Sgusella 
25123785Sgusella 	msg.tsp_type = TSP_TEST;
25223785Sgusella 	msg.tsp_vers = TSPVERSION;
25323785Sgusella 	(void)gethostname(hostname, sizeof(hostname));
25423785Sgusella 	(void)strcpy(msg.tsp_name, hostname);
25523785Sgusella 	bytenetorder(&msg);	/* it is not really necessary here */
25623785Sgusella 	while (nhosts-- > 0) {
25723785Sgusella 		length = sizeof(struct sockaddr_in);
25823785Sgusella 		if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
25923785Sgusella 						&sin[nhosts], length) < 0) {
26023785Sgusella 			perror("sendto");
26123785Sgusella 			return;
26223785Sgusella 		}
26323785Sgusella 	}
26423785Sgusella }
26523785Sgusella 
26623785Sgusella /*
26723785Sgusella  * Enables or disables tracing on local timedaemon
26823785Sgusella  */
26923785Sgusella 
27023785Sgusella tracing(argc, argv)
27123785Sgusella int argc;
27223785Sgusella char *argv[];
27323785Sgusella {
27423785Sgusella 	int onflag;
27523785Sgusella 	int length;
27625578Sbloom 	int cc;
27725578Sbloom 	fd_set ready;
27823785Sgusella 	struct sockaddr_in dest;
27923785Sgusella 	struct timeval tout;
28023785Sgusella 	struct sockaddr_in from;
28123785Sgusella 	struct tsp msg;
28223785Sgusella 	struct servent *srvp;
28323785Sgusella 
28423785Sgusella 	if (argc != 2) {
28523785Sgusella 		printf("Usage: tracing { on | off }\n");
28623785Sgusella 		return;
28723785Sgusella 	}
28823785Sgusella 
28923785Sgusella 	srvp = getservbyname("timed", "udp");
29023785Sgusella 	if (srvp == 0) {
29123785Sgusella 		fprintf(stderr, "udp/timed: unknown service\n");
29223785Sgusella 		return;
29323785Sgusella 	}
29423785Sgusella 	dest.sin_port = srvp->s_port;
29523785Sgusella 	dest.sin_family = AF_INET;
29623785Sgusella 
29723785Sgusella 	(void)gethostname(hostname,sizeof(hostname));
29823785Sgusella 	hp = gethostbyname(hostname);
29923785Sgusella 	bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
30023785Sgusella 
30123785Sgusella 	if (strcmp(argv[1], "on") == 0) {
30223785Sgusella 		msg.tsp_type = TSP_TRACEON;
30323785Sgusella 		onflag = ON;
30423785Sgusella 	} else {
30523785Sgusella 		msg.tsp_type = TSP_TRACEOFF;
30623785Sgusella 		onflag = OFF;
30723785Sgusella 	}
30823785Sgusella 
30923785Sgusella 	(void)strcpy(msg.tsp_name, hostname);
31023785Sgusella 	msg.tsp_vers = TSPVERSION;
31123785Sgusella 	bytenetorder(&msg);
31223785Sgusella 	length = sizeof(struct sockaddr_in);
31323785Sgusella 	if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
31423785Sgusella 						&dest, length) < 0) {
31523785Sgusella 		perror("sendto");
31623785Sgusella 		return;
31723785Sgusella 	}
31823785Sgusella 
31923785Sgusella 	tout.tv_sec = 5;
32023785Sgusella 	tout.tv_usec = 0;
32125578Sbloom 	FD_ZERO(&ready);
32225578Sbloom 	FD_SET(sock, &ready);
32325578Sbloom 	if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) {
32423785Sgusella 		length = sizeof(struct sockaddr_in);
32523785Sgusella 		cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0,
32623785Sgusella 							&from, &length);
32723785Sgusella 		if (cc < 0) {
32823785Sgusella 			perror("recvfrom");
32923785Sgusella 			return;
33023785Sgusella 		}
33123785Sgusella 		bytehostorder(&msg);
33223785Sgusella 		if (msg.tsp_type == TSP_ACK)
33323785Sgusella 			if (onflag)
33423785Sgusella 				printf("timed tracing enabled\n");
33523785Sgusella 			else
33623785Sgusella 				printf("timed tracing disabled\n");
33723785Sgusella 		else
33823785Sgusella 			printf("wrong ack received: %s\n",
33923785Sgusella 						tsptype[msg.tsp_type]);
34023785Sgusella 	} else
34123785Sgusella 		printf("communication error\n");
34223785Sgusella }
34323785Sgusella 
34423785Sgusella priv_resources()
34523785Sgusella {
34623785Sgusella 	int port;
34723785Sgusella 	struct sockaddr_in sin;
34823785Sgusella 
34923785Sgusella 	sock = socket(AF_INET, SOCK_DGRAM, 0);
35023785Sgusella 	if (sock < 0) {
35123785Sgusella 		perror("opening socket");
35223785Sgusella 		return(-1);
35323785Sgusella 	}
35423785Sgusella 
35523785Sgusella 	sin.sin_family = AF_INET;
35623785Sgusella 	sin.sin_addr.s_addr = 0;
35723785Sgusella 	for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
35823785Sgusella 		sin.sin_port = htons((u_short)port);
35923785Sgusella 		if (bind(sock, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
36023785Sgusella 			break;
36123785Sgusella 		if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) {
36223785Sgusella 			perror("bind");
36323785Sgusella 			(void) close(sock);
36423785Sgusella 			return(-1);
36523785Sgusella 		}
36623785Sgusella 	}
36723785Sgusella 	if (port == IPPORT_RESERVED / 2) {
36823785Sgusella 		fprintf(stderr, "all reserved ports in use\n");
36923785Sgusella 		(void) close(sock);
37023785Sgusella 		return(-1);
37123785Sgusella 	}
37223785Sgusella 
37323785Sgusella 	sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
37423785Sgusella 	if (sock_raw < 0)  {
37523785Sgusella 		perror("opening raw socket");
37623785Sgusella 		(void) close(sock_raw);
37723785Sgusella 		return(-1);
37823785Sgusella 	}
37923785Sgusella 	return(1);
38023785Sgusella }
381