Home | History | Annotate | Line # | Download | only in timedc
cmds.c revision 1.3
      1 /*-
      2  * Copyright (c) 1985, 1993 The Regents of the University of California.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *	This product includes software developed by the University of
     16  *	California, Berkeley and its contributors.
     17  * 4. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  */
     33 
     34 #ifndef lint
     35 static char sccsid[] = "@(#)cmds.c	5.1 (Berkeley) 5/11/93";
     36 #endif /* not lint */
     37 
     38 #ifdef sgi
     39 #ident "$Revision: 1.3 $"
     40 #endif
     41 
     42 #include "timedc.h"
     43 #include <sys/file.h>
     44 
     45 #include <netinet/in_systm.h>
     46 #include <netinet/ip.h>
     47 #include <netinet/ip_icmp.h>
     48 
     49 #include <stdlib.h>
     50 #include <strings.h>
     51 #include <unistd.h>
     52 
     53 #define TSPTYPES
     54 #include <protocols/timed.h>
     55 
     56 #ifdef sgi
     57 #include <bstring.h>
     58 #include <sys/clock.h>
     59 #else
     60 #define	SECHR	(60*60)
     61 #define	SECDAY	(24*SECHR)
     62 #endif /* sgi */
     63 
     64 # define DATE_PROTO "udp"
     65 # define DATE_PORT "time"
     66 
     67 
     68 int sock;
     69 int sock_raw;
     70 char myname[MAXHOSTNAMELEN];
     71 struct hostent *hp;
     72 struct sockaddr_in server;
     73 struct sockaddr_in dayaddr;
     74 extern int measure_delta;
     75 
     76 void bytenetorder(struct tsp *);
     77 void bytehostorder(struct tsp *);
     78 
     79 
     80 #define BU ((unsigned long)2208988800)	/* seconds before UNIX epoch */
     81 
     82 
     83 /* compute the difference between our date and another machine
     84  */
     85 static int				/* difference in days from our time */
     86 daydiff(char *hostname)
     87 {
     88 	int i;
     89 	int trials;
     90 	struct timeval tout, now;
     91 	fd_set ready;
     92 	struct sockaddr from;
     93 	int fromlen;
     94 	unsigned long sec;
     95 
     96 
     97 	/* wait 2 seconds between 10 tries */
     98 	tout.tv_sec = 2;
     99 	tout.tv_usec = 0;
    100 	for (trials = 0; trials < 10; trials++) {
    101 		/* ask for the time */
    102 		sec = 0;
    103 		if (sendto(sock, &sec, sizeof(sec), 0,
    104 			   (struct sockaddr*)&dayaddr, sizeof(dayaddr)) < 0) {
    105 			perror("sendto(sock)");
    106 			return 0;
    107 		}
    108 
    109 		for (;;) {
    110 			FD_ZERO(&ready);
    111 			FD_SET(sock, &ready);
    112 			i = select(sock+1, &ready, (fd_set *)0,
    113 				   (fd_set *)0, &tout);
    114 			if (i < 0) {
    115 				if (errno == EINTR)
    116 					continue;
    117 				perror("select(date read)");
    118 				return 0;
    119 			}
    120 			if (0 == i)
    121 				break;
    122 
    123 			fromlen = sizeof(from);
    124 			if (recvfrom(sock,&sec,sizeof(sec),0,
    125 				     &from,&fromlen) < 0) {
    126 				perror("recvfrom(date read)");
    127 				return 0;
    128 			}
    129 
    130 			sec = ntohl(sec);
    131 			if (sec < BU) {
    132 				fprintf(stderr,
    133 					"%s says it is before 1970: %lu",
    134 					hostname, sec);
    135 				return 0;
    136 			}
    137 			sec -= BU;
    138 
    139 			(void)gettimeofday(&now, (struct timezone*)0);
    140 			return (sec - now.tv_sec);
    141 		}
    142 	}
    143 
    144 	/* if we get here, we tried too many times */
    145 	fprintf(stderr,"%s will not tell us the date\n", hostname);
    146 	return 0;
    147 }
    148 
    149 
    150 /*
    151  * Clockdiff computes the difference between the time of the machine on
    152  * which it is called and the time of the machines given as argument.
    153  * The time differences measured by clockdiff are obtained using a sequence
    154  * of ICMP TSTAMP messages which are returned to the sender by the IP module
    155  * in the remote machine.
    156  * In order to compare clocks of machines in different time zones, the time
    157  * is transmitted (as a 32-bit value) in milliseconds since midnight UT.
    158  * If a hosts uses a different time format, it should set the high order
    159  * bit of the 32-bit quantity it transmits.
    160  * However, VMS apparently transmits the time in milliseconds since midnight
    161  * local time (rather than GMT) without setting the high order bit.
    162  * Furthermore, it does not understand daylight-saving time.  This makes
    163  * clockdiff behaving inconsistently with hosts running VMS.
    164  *
    165  * In order to reduce the sensitivity to the variance of message transmission
    166  * time, clockdiff sends a sequence of messages.  Yet, measures between
    167  * two `distant' hosts can be affected by a small error. The error can,
    168  * however, be reduced by increasing the number of messages sent in each
    169  * measurement.
    170  */
    171 void
    172 clockdiff(argc, argv)
    173 	int argc;
    174 	char *argv[];
    175 {
    176 	int measure_status;
    177 	extern int measure(u_long, u_long, char *, struct sockaddr_in*, int);
    178 	register int avg_cnt;
    179 	register long avg;
    180 	struct servent *sp;
    181 
    182 	if (argc < 2)  {
    183 		printf("Usage: clockdiff host ... \n");
    184 		return;
    185 	}
    186 
    187 	(void)gethostname(myname,sizeof(myname));
    188 
    189 	/* get the address for the date ready */
    190 	sp = getservbyname(DATE_PORT, DATE_PROTO);
    191 	if (!sp) {
    192 		(void)fprintf(stderr, "%s/%s is an unknown service\n",
    193 			      DATE_PORT, DATE_PROTO);
    194 		dayaddr.sin_port = 0;
    195 	} else {
    196 		dayaddr.sin_port = sp->s_port;
    197 	}
    198 
    199 	while (argc > 1) {
    200 		argc--; argv++;
    201 		hp = gethostbyname(*argv);
    202 		if (hp == NULL) {
    203 			fprintf(stderr, "timedc: %s: ", *argv);
    204 			herror(0);
    205 			continue;
    206 		}
    207 
    208 		server.sin_family = hp->h_addrtype;
    209 		bcopy(hp->h_addr, &server.sin_addr.s_addr, hp->h_length);
    210 		for (avg_cnt = 0, avg = 0; avg_cnt < 16; avg_cnt++) {
    211 			measure_status = measure(10000,100, *argv, &server, 1);
    212 			if (measure_status != GOOD)
    213 				break;
    214 			avg += measure_delta;
    215 		}
    216 		if (measure_status == GOOD)
    217 			measure_delta = avg/avg_cnt;
    218 
    219 		switch (measure_status) {
    220 		case HOSTDOWN:
    221 			printf("%s is down\n", hp->h_name);
    222 			continue;
    223 		case NONSTDTIME:
    224 			printf("%s transmitts a non-standard time format\n",
    225 			       hp->h_name);
    226 			continue;
    227 		case UNREACHABLE:
    228 			printf("%s is unreachable\n", hp->h_name);
    229 			continue;
    230 		}
    231 
    232 		/*
    233 		 * Try to get the date only after using ICMP timestamps to
    234 		 * get the time.  This is because the date protocol
    235 		 * is optional.
    236 		 */
    237 		if (dayaddr.sin_port != 0) {
    238 			dayaddr.sin_family = hp->h_addrtype;
    239 			bcopy(hp->h_addr, &dayaddr.sin_addr.s_addr,
    240 			      hp->h_length);
    241 			avg = daydiff(*argv);
    242 			if (avg > SECDAY) {
    243 				printf("time on %s is %ld days ahead %s\n",
    244 				       hp->h_name, avg/SECDAY, myname);
    245 				continue;
    246 			} else if (avg < -SECDAY) {
    247 				printf("time on %s is %ld days behind %s\n",
    248 				       hp->h_name, -avg/SECDAY, myname);
    249 				continue;
    250 			}
    251 		}
    252 
    253 		if (measure_delta > 0) {
    254 			printf("time on %s is %d ms. ahead of time on %s\n",
    255 			       hp->h_name, measure_delta, myname);
    256 		} else if (measure_delta == 0) {
    257 			printf("%s and %s have the same time\n",
    258 			       hp->h_name, myname);
    259 		} else {
    260 			printf("time on %s is %d ms. behind time on %s\n",
    261 			       hp->h_name, -measure_delta, myname);
    262 		}
    263 	}
    264 	return;
    265 }
    266 
    267 
    268 /*
    269  * finds location of master timedaemon
    270  */
    271 void
    272 msite(int argc, char *argv[])
    273 {
    274 	int cc;
    275 	fd_set ready;
    276 	struct sockaddr_in dest;
    277 	int i, length;
    278 	struct sockaddr from;
    279 	struct timeval tout;
    280 	struct tsp msg;
    281 	struct servent *srvp;
    282 	char *tgtname;
    283 
    284 	if (argc < 1) {
    285 		printf("Usage: msite [hostname]\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(myname, sizeof(myname));
    298 	i = 1;
    299 	do {
    300 		tgtname = (i >= argc) ? myname : argv[i];
    301 		hp = gethostbyname(tgtname);
    302 		if (hp == 0) {
    303 			fprintf(stderr, "timedc: %s: ", tgtname);
    304 			herror(0);
    305 			continue;
    306 		}
    307 		bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
    308 
    309 		(void)strcpy(msg.tsp_name, myname);
    310 		msg.tsp_type = TSP_MSITE;
    311 		msg.tsp_vers = TSPVERSION;
    312 		bytenetorder(&msg);
    313 		if (sendto(sock, &msg, sizeof(struct tsp), 0,
    314 			   (struct sockaddr*)&dest,
    315 			   sizeof(struct sockaddr)) < 0) {
    316 			perror("sendto");
    317 			continue;
    318 		}
    319 
    320 		tout.tv_sec = 15;
    321 		tout.tv_usec = 0;
    322 		FD_ZERO(&ready);
    323 		FD_SET(sock, &ready);
    324 		if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0,
    325 			   &tout)) {
    326 			length = sizeof(struct sockaddr);
    327 			cc = recvfrom(sock, &msg, sizeof(struct tsp), 0,
    328 				      &from, &length);
    329 			if (cc < 0) {
    330 				perror("recvfrom");
    331 				continue;
    332 			}
    333 			bytehostorder(&msg);
    334 			if (msg.tsp_type == TSP_ACK) {
    335 				printf("master timedaemon at %s is %s\n",
    336 				       tgtname, msg.tsp_name);
    337 			} else {
    338 				printf("received wrong ack: %s\n",
    339 				       tsptype[msg.tsp_type]);
    340 			}
    341 		} else {
    342 			printf("communication error with %s\n", tgtname);
    343 		}
    344 	} while (++i < argc);
    345 }
    346 
    347 /*
    348  * quits timedc
    349  */
    350 void
    351 quit()
    352 {
    353 	exit(0);
    354 }
    355 
    356 
    357 /*
    358  * Causes the election timer to expire on the selected hosts
    359  * It sends just one udp message per machine, relying on
    360  * reliability of communication channel.
    361  */
    362 void
    363 testing(int argc, char *argv[])
    364 {
    365 	struct servent *srvp;
    366 	struct sockaddr_in sin;
    367 	struct tsp msg;
    368 
    369 	if (argc < 2)  {
    370 		printf("Usage: election host1 [host2 ...]\n");
    371 		return;
    372 	}
    373 
    374 	srvp = getservbyname("timed", "udp");
    375 	if (srvp == 0) {
    376 		fprintf(stderr, "udp/timed: unknown service\n");
    377 		return;
    378 	}
    379 
    380 	while (argc > 1) {
    381 		argc--; argv++;
    382 		hp = gethostbyname(*argv);
    383 		if (hp == NULL) {
    384 			fprintf(stderr, "timedc: %s: ", *argv);
    385 			herror(0);
    386 			argc--; argv++;
    387 			continue;
    388 		}
    389 		sin.sin_port = srvp->s_port;
    390 		sin.sin_family = hp->h_addrtype;
    391 		bcopy(hp->h_addr, &sin.sin_addr.s_addr, hp->h_length);
    392 
    393 		msg.tsp_type = TSP_TEST;
    394 		msg.tsp_vers = TSPVERSION;
    395 		(void)gethostname(myname, sizeof(myname));
    396 		(void)strncpy(msg.tsp_name, myname, sizeof(msg.tsp_name));
    397 		bytenetorder(&msg);
    398 		if (sendto(sock, &msg, sizeof(struct tsp), 0,
    399 			   (struct sockaddr*)&sin,
    400 			   sizeof(struct sockaddr)) < 0) {
    401 			perror("sendto");
    402 		}
    403 	}
    404 }
    405 
    406 
    407 /*
    408  * Enables or disables tracing on local timedaemon
    409  */
    410 void
    411 tracing(int argc, char *argv[])
    412 {
    413 	int onflag;
    414 	int length;
    415 	int cc;
    416 	fd_set ready;
    417 	struct sockaddr_in dest;
    418 	struct sockaddr from;
    419 	struct timeval tout;
    420 	struct tsp msg;
    421 	struct servent *srvp;
    422 
    423 	if (argc != 2) {
    424 		printf("Usage: tracing { on | off }\n");
    425 		return;
    426 	}
    427 
    428 	srvp = getservbyname("timed", "udp");
    429 	if (srvp == 0) {
    430 		fprintf(stderr, "udp/timed: unknown service\n");
    431 		return;
    432 	}
    433 	dest.sin_port = srvp->s_port;
    434 	dest.sin_family = AF_INET;
    435 
    436 	(void)gethostname(myname,sizeof(myname));
    437 	hp = gethostbyname(myname);
    438 	bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
    439 
    440 	if (strcmp(argv[1], "on") == 0) {
    441 		msg.tsp_type = TSP_TRACEON;
    442 		onflag = ON;
    443 	} else {
    444 		msg.tsp_type = TSP_TRACEOFF;
    445 		onflag = OFF;
    446 	}
    447 
    448 	(void)strcpy(msg.tsp_name, myname);
    449 	msg.tsp_vers = TSPVERSION;
    450 	bytenetorder(&msg);
    451 	if (sendto(sock, &msg, sizeof(struct tsp), 0,
    452 		   (struct sockaddr*)&dest, sizeof(struct sockaddr)) < 0) {
    453 		perror("sendto");
    454 		return;
    455 	}
    456 
    457 	tout.tv_sec = 5;
    458 	tout.tv_usec = 0;
    459 	FD_ZERO(&ready);
    460 	FD_SET(sock, &ready);
    461 	if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) {
    462 		length = sizeof(struct sockaddr);
    463 		cc = recvfrom(sock, &msg, sizeof(struct tsp), 0,
    464 			      &from, &length);
    465 		if (cc < 0) {
    466 			perror("recvfrom");
    467 			return;
    468 		}
    469 		bytehostorder(&msg);
    470 		if (msg.tsp_type == TSP_ACK)
    471 			if (onflag)
    472 				printf("timed tracing enabled\n");
    473 			else
    474 				printf("timed tracing disabled\n");
    475 		else
    476 			printf("wrong ack received: %s\n",
    477 						tsptype[msg.tsp_type]);
    478 	} else
    479 		printf("communication error\n");
    480 }
    481 
    482 int
    483 priv_resources()
    484 {
    485 	int port;
    486 	struct sockaddr_in sin;
    487 
    488 	sock = socket(AF_INET, SOCK_DGRAM, 0);
    489 	if (sock < 0) {
    490 		perror("opening socket");
    491 		return(-1);
    492 	}
    493 
    494 	sin.sin_family = AF_INET;
    495 	sin.sin_addr.s_addr = 0;
    496 	for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
    497 		sin.sin_port = htons((u_short)port);
    498 		if (bind(sock, (struct sockaddr*)&sin, sizeof (sin)) >= 0)
    499 			break;
    500 		if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) {
    501 			perror("bind");
    502 			(void) close(sock);
    503 			return(-1);
    504 		}
    505 	}
    506 	if (port == IPPORT_RESERVED / 2) {
    507 		fprintf(stderr, "all reserved ports in use\n");
    508 		(void) close(sock);
    509 		return(-1);
    510 	}
    511 
    512 	sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    513 	if (sock_raw < 0)  {
    514 		perror("opening raw socket");
    515 		(void) close(sock);
    516 		return(-1);
    517 	}
    518 	return(1);
    519 }
    520