123785Sgusella /* 223785Sgusella * Copyright (c) 1983 Regents of the University of California. 323785Sgusella * All rights reserved. The Berkeley software License Agreement 423785Sgusella * specifies the terms and conditions for redistribution. 523785Sgusella */ 623785Sgusella 723785Sgusella #ifndef lint 8*25578Sbloom static char sccsid[] = "@(#)cmds.c 2.1 (Berkeley) 12/10/85"; 923785Sgusella #endif not lint 1023785Sgusella 1123785Sgusella #include "timedc.h" 1223785Sgusella #include <netinet/in_systm.h> 1323785Sgusella #include <netinet/ip.h> 1423785Sgusella #include <netinet/ip_icmp.h> 1523785Sgusella #define TSPTYPES 1623785Sgusella #include <protocols/timed.h> 1723785Sgusella #include <sys/file.h> 1823785Sgusella 1923785Sgusella int id; 2023785Sgusella int sock; 2123785Sgusella int sock_raw; 2224904Sbloom char hostname[MAXHOSTNAMELEN]; 2323785Sgusella struct hostent *hp, *gethostbyname(); 2423785Sgusella struct sockaddr_in server; 2523785Sgusella extern int measure_delta; 2623785Sgusella int bytenetorder(), bytehostorder(); 2723785Sgusella char *strcpy(); 2823785Sgusella 2923785Sgusella /* 3023785Sgusella * Clockdiff computes the difference between the time of the machine on 3123785Sgusella * which it is called and the time of the machines given as argument. 3223785Sgusella * The time differences measured by clockdiff are obtained using a sequence 3323785Sgusella * of ICMP TSTAMP messages which are returned to the sender by the IP module 3423785Sgusella * in the remote machine. 3523785Sgusella * In order to compare clocks of machines in different time zones, the time 3623785Sgusella * is transmitted (as a 32-bit value) in milliseconds since midnight UT. 3723785Sgusella * If a hosts uses a different time format, it should set the high order 3823785Sgusella * bit of the 32-bit quantity it transmits. 3923785Sgusella * However, VMS apparently transmits the time in milliseconds since midnight 4023785Sgusella * local time (rather than GMT) without setting the high order bit. 4123785Sgusella * Furthermore, it does not understand daylight-saving time. This makes 4223785Sgusella * clockdiff behaving inconsistently with hosts running VMS. 4323785Sgusella * 4423785Sgusella * In order to reduce the sensitivity to the variance of message transmission 4523785Sgusella * time, clockdiff sends a sequence of messages. Yet, measures between 4623785Sgusella * two `distant' hosts can be affected by a small error. The error can, however, 4723785Sgusella * be reduced by increasing the number of messages sent in each measurement. 4823785Sgusella */ 4923785Sgusella 5023785Sgusella clockdiff(argc, argv) 5123785Sgusella int argc; 5223785Sgusella char *argv[]; 5323785Sgusella { 5423785Sgusella int measure_status; 5523785Sgusella struct timeval ack; 5623785Sgusella int measure(); 5723785Sgusella 5823785Sgusella if(argc < 2) { 5923785Sgusella printf("Usage: clockdiff host ... \n"); 6023785Sgusella return; 6123785Sgusella } 6223785Sgusella 6323785Sgusella id = getpid(); 6423785Sgusella (void)gethostname(hostname,sizeof(hostname)); 6523785Sgusella 6623785Sgusella while (argc > 1) { 6723785Sgusella argc--; argv++; 6823785Sgusella hp = gethostbyname(*argv); 6923785Sgusella if (hp == NULL) { 7023785Sgusella printf("%s: unknown host\n", *argv); 7123785Sgusella continue; 7223785Sgusella } 7323785Sgusella server.sin_family = hp->h_addrtype; 7423785Sgusella bcopy(hp->h_addr, &(server.sin_addr.s_addr), hp->h_length); 7523785Sgusella ack.tv_sec = 1; 7623785Sgusella ack.tv_usec = 500000; 77*25578Sbloom if ((measure_status = measure(&ack, &server, OFF)) < 0) { 7823785Sgusella perror("measure"); 7923785Sgusella return; 8023785Sgusella } 8123785Sgusella switch (measure_status) { 8223785Sgusella 8323785Sgusella case HOSTDOWN: 8423785Sgusella printf("%s is down\n", hp->h_name); 8523785Sgusella continue; 8623785Sgusella break; 8723785Sgusella case NONSTDTIME: 8823785Sgusella printf("%s time transmitted in a non-standard format\n", hp->h_name); 8923785Sgusella continue; 9023785Sgusella break; 9123785Sgusella case UNREACHABLE: 9223785Sgusella printf("%s is unreachable\n", hp->h_name); 9323785Sgusella continue; 9423785Sgusella break; 9523785Sgusella default: 9623785Sgusella break; 9723785Sgusella } 9823785Sgusella 9923785Sgusella if (measure_delta > 0) 10023785Sgusella printf("time on %s is %d ms. ahead of time on %s\n", 10123785Sgusella hp->h_name, measure_delta, 10223785Sgusella hostname); 10323785Sgusella else 10423785Sgusella if (measure_delta == 0) 10523785Sgusella printf("%s and %s have the same time\n", 10623785Sgusella hp->h_name, hostname); 10723785Sgusella else 10823785Sgusella printf("time on %s is %d ms. behind time on %s\n", 10923785Sgusella hp->h_name, -measure_delta, hostname); 11023785Sgusella } 11123785Sgusella return; 11223785Sgusella } 11323785Sgusella /* 11423785Sgusella * finds location of master timedaemon 11523785Sgusella */ 11623785Sgusella 11723785Sgusella msite(argc) 11823785Sgusella int argc; 11923785Sgusella { 12023785Sgusella int length; 121*25578Sbloom int cc; 122*25578Sbloom fd_set ready; 12323785Sgusella struct sockaddr_in dest; 12423785Sgusella struct timeval tout; 12523785Sgusella struct sockaddr_in from; 12623785Sgusella struct tsp msg; 12723785Sgusella struct servent *srvp; 12823785Sgusella 12923785Sgusella if (argc != 1) { 13023785Sgusella printf("Usage: msite\n"); 13123785Sgusella return; 13223785Sgusella } 13323785Sgusella 13423785Sgusella srvp = getservbyname("timed", "udp"); 13523785Sgusella if (srvp == 0) { 13623785Sgusella fprintf(stderr, "udp/timed: unknown service\n"); 13723785Sgusella return; 13823785Sgusella } 13923785Sgusella dest.sin_port = srvp->s_port; 14023785Sgusella dest.sin_family = AF_INET; 14123785Sgusella 14223785Sgusella (void)gethostname(hostname,sizeof(hostname)); 14323785Sgusella hp = gethostbyname(hostname); 14423785Sgusella if (hp == NULL) { 14523785Sgusella perror("gethostbyname"); 14623785Sgusella return; 14723785Sgusella } 14823785Sgusella bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length); 14923785Sgusella 15023785Sgusella (void)strcpy(msg.tsp_name, hostname); 15123785Sgusella msg.tsp_type = TSP_MSITE; 15223785Sgusella msg.tsp_vers = TSPVERSION; 15323785Sgusella bytenetorder(&msg); 15423785Sgusella length = sizeof(struct sockaddr_in); 15523785Sgusella if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0, 15623785Sgusella &dest, length) < 0) { 15723785Sgusella perror("sendto"); 15823785Sgusella return; 15923785Sgusella } 16023785Sgusella 16123785Sgusella tout.tv_sec = 15; 16223785Sgusella tout.tv_usec = 0; 163*25578Sbloom FD_ZERO(&ready); 164*25578Sbloom FD_SET(sock, &ready); 165*25578Sbloom if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) { 16623785Sgusella length = sizeof(struct sockaddr_in); 16723785Sgusella cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0, 16823785Sgusella &from, &length); 16923785Sgusella if (cc < 0) { 17023785Sgusella perror("recvfrom"); 17123785Sgusella return; 17223785Sgusella } 17323785Sgusella bytehostorder(&msg); 17423785Sgusella if (msg.tsp_type == TSP_ACK) 17523785Sgusella printf("master timedaemon runs on %s\n", msg.tsp_name); 17623785Sgusella else 17723785Sgusella printf("received wrong ack: %s\n", 17823785Sgusella tsptype[msg.tsp_type]); 17923785Sgusella } else 18023785Sgusella printf("communication error\n"); 18123785Sgusella } 18223785Sgusella 18323785Sgusella /* 18423785Sgusella * quits timedc 18523785Sgusella */ 18623785Sgusella 18723785Sgusella quit() 18823785Sgusella { 18923785Sgusella exit(0); 19023785Sgusella } 19123785Sgusella 19223785Sgusella #define MAXH 4 /* max no. of hosts where election can occur */ 19323785Sgusella 19423785Sgusella /* 19523785Sgusella * Causes the election timer to expire on the selected hosts 19623785Sgusella * It sends just one udp message per machine, relying on 19723785Sgusella * reliability of communication channel. 19823785Sgusella */ 19923785Sgusella 20023785Sgusella testing(argc, argv) 20123785Sgusella int argc; 20223785Sgusella char *argv[]; 20323785Sgusella { 20423785Sgusella int length; 20523785Sgusella int nhosts; 20623785Sgusella struct servent *srvp; 20723785Sgusella struct sockaddr_in sin[MAXH]; 20823785Sgusella struct tsp msg; 20923785Sgusella 21023785Sgusella if(argc < 2) { 21123785Sgusella printf("Usage: testing host ...\n"); 21223785Sgusella return; 21323785Sgusella } 21423785Sgusella 21523785Sgusella srvp = getservbyname("timed", "udp"); 21623785Sgusella if (srvp == 0) { 21723785Sgusella fprintf(stderr, "udp/timed: unknown service\n"); 21823785Sgusella return; 21923785Sgusella } 22023785Sgusella 22123785Sgusella nhosts = 0; 22223785Sgusella while (argc > 1) { 22323785Sgusella argc--; argv++; 22423785Sgusella hp = gethostbyname(*argv); 22523785Sgusella if (hp == NULL) { 22623785Sgusella printf("%s: unknown host %s\n", *argv); 22723785Sgusella argc--; argv++; 22823785Sgusella continue; 22923785Sgusella } 23023785Sgusella sin[nhosts].sin_port = srvp->s_port; 23123785Sgusella sin[nhosts].sin_family = hp->h_addrtype; 23223785Sgusella bcopy(hp->h_addr, &(sin[nhosts].sin_addr.s_addr), hp->h_length); 23323785Sgusella if (++nhosts == MAXH) 23423785Sgusella break; 23523785Sgusella } 23623785Sgusella 23723785Sgusella msg.tsp_type = TSP_TEST; 23823785Sgusella msg.tsp_vers = TSPVERSION; 23923785Sgusella (void)gethostname(hostname, sizeof(hostname)); 24023785Sgusella (void)strcpy(msg.tsp_name, hostname); 24123785Sgusella bytenetorder(&msg); /* it is not really necessary here */ 24223785Sgusella while (nhosts-- > 0) { 24323785Sgusella length = sizeof(struct sockaddr_in); 24423785Sgusella if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0, 24523785Sgusella &sin[nhosts], length) < 0) { 24623785Sgusella perror("sendto"); 24723785Sgusella return; 24823785Sgusella } 24923785Sgusella } 25023785Sgusella } 25123785Sgusella 25223785Sgusella /* 25323785Sgusella * Enables or disables tracing on local timedaemon 25423785Sgusella */ 25523785Sgusella 25623785Sgusella tracing(argc, argv) 25723785Sgusella int argc; 25823785Sgusella char *argv[]; 25923785Sgusella { 26023785Sgusella int onflag; 26123785Sgusella int length; 262*25578Sbloom int cc; 263*25578Sbloom fd_set ready; 26423785Sgusella struct sockaddr_in dest; 26523785Sgusella struct timeval tout; 26623785Sgusella struct sockaddr_in from; 26723785Sgusella struct tsp msg; 26823785Sgusella struct servent *srvp; 26923785Sgusella 27023785Sgusella if (argc != 2) { 27123785Sgusella printf("Usage: tracing { on | off }\n"); 27223785Sgusella return; 27323785Sgusella } 27423785Sgusella 27523785Sgusella srvp = getservbyname("timed", "udp"); 27623785Sgusella if (srvp == 0) { 27723785Sgusella fprintf(stderr, "udp/timed: unknown service\n"); 27823785Sgusella return; 27923785Sgusella } 28023785Sgusella dest.sin_port = srvp->s_port; 28123785Sgusella dest.sin_family = AF_INET; 28223785Sgusella 28323785Sgusella (void)gethostname(hostname,sizeof(hostname)); 28423785Sgusella hp = gethostbyname(hostname); 28523785Sgusella bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length); 28623785Sgusella 28723785Sgusella if (strcmp(argv[1], "on") == 0) { 28823785Sgusella msg.tsp_type = TSP_TRACEON; 28923785Sgusella onflag = ON; 29023785Sgusella } else { 29123785Sgusella msg.tsp_type = TSP_TRACEOFF; 29223785Sgusella onflag = OFF; 29323785Sgusella } 29423785Sgusella 29523785Sgusella (void)strcpy(msg.tsp_name, hostname); 29623785Sgusella msg.tsp_vers = TSPVERSION; 29723785Sgusella bytenetorder(&msg); 29823785Sgusella length = sizeof(struct sockaddr_in); 29923785Sgusella if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0, 30023785Sgusella &dest, length) < 0) { 30123785Sgusella perror("sendto"); 30223785Sgusella return; 30323785Sgusella } 30423785Sgusella 30523785Sgusella tout.tv_sec = 5; 30623785Sgusella tout.tv_usec = 0; 307*25578Sbloom FD_ZERO(&ready); 308*25578Sbloom FD_SET(sock, &ready); 309*25578Sbloom if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) { 31023785Sgusella length = sizeof(struct sockaddr_in); 31123785Sgusella cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0, 31223785Sgusella &from, &length); 31323785Sgusella if (cc < 0) { 31423785Sgusella perror("recvfrom"); 31523785Sgusella return; 31623785Sgusella } 31723785Sgusella bytehostorder(&msg); 31823785Sgusella if (msg.tsp_type == TSP_ACK) 31923785Sgusella if (onflag) 32023785Sgusella printf("timed tracing enabled\n"); 32123785Sgusella else 32223785Sgusella printf("timed tracing disabled\n"); 32323785Sgusella else 32423785Sgusella printf("wrong ack received: %s\n", 32523785Sgusella tsptype[msg.tsp_type]); 32623785Sgusella } else 32723785Sgusella printf("communication error\n"); 32823785Sgusella } 32923785Sgusella 33023785Sgusella priv_resources() 33123785Sgusella { 33223785Sgusella int port; 33323785Sgusella struct sockaddr_in sin; 33423785Sgusella 33523785Sgusella sock = socket(AF_INET, SOCK_DGRAM, 0); 33623785Sgusella if (sock < 0) { 33723785Sgusella perror("opening socket"); 33823785Sgusella return(-1); 33923785Sgusella } 34023785Sgusella 34123785Sgusella sin.sin_family = AF_INET; 34223785Sgusella sin.sin_addr.s_addr = 0; 34323785Sgusella for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) { 34423785Sgusella sin.sin_port = htons((u_short)port); 34523785Sgusella if (bind(sock, (struct sockaddr *)&sin, sizeof (sin)) >= 0) 34623785Sgusella break; 34723785Sgusella if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) { 34823785Sgusella perror("bind"); 34923785Sgusella (void) close(sock); 35023785Sgusella return(-1); 35123785Sgusella } 35223785Sgusella } 35323785Sgusella if (port == IPPORT_RESERVED / 2) { 35423785Sgusella fprintf(stderr, "all reserved ports in use\n"); 35523785Sgusella (void) close(sock); 35623785Sgusella return(-1); 35723785Sgusella } 35823785Sgusella 35923785Sgusella sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 36023785Sgusella if (sock_raw < 0) { 36123785Sgusella perror("opening raw socket"); 36223785Sgusella (void) close(sock_raw); 36323785Sgusella return(-1); 36423785Sgusella } 36523785Sgusella return(1); 36623785Sgusella } 367