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