1 /* 2 * Copyright (c) 1983 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)cmds.c 2.8 (Berkeley) 03/02/91"; 10 #endif /* not lint */ 11 12 #include "timedc.h" 13 #include <netinet/in_systm.h> 14 #include <netinet/ip.h> 15 #include <netinet/ip_icmp.h> 16 #define TSPTYPES 17 #include <protocols/timed.h> 18 #include <sys/file.h> 19 20 int id; 21 int sock; 22 int sock_raw; 23 char hostname[MAXHOSTNAMELEN]; 24 struct hostent *hp, *gethostbyname(); 25 struct sockaddr_in server; 26 extern int measure_delta; 27 int bytenetorder(), bytehostorder(); 28 char *strcpy(); 29 30 /* 31 * Clockdiff computes the difference between the time of the machine on 32 * which it is called and the time of the machines given as argument. 33 * The time differences measured by clockdiff are obtained using a sequence 34 * of ICMP TSTAMP messages which are returned to the sender by the IP module 35 * in the remote machine. 36 * In order to compare clocks of machines in different time zones, the time 37 * is transmitted (as a 32-bit value) in milliseconds since midnight UT. 38 * If a hosts uses a different time format, it should set the high order 39 * bit of the 32-bit quantity it transmits. 40 * However, VMS apparently transmits the time in milliseconds since midnight 41 * local time (rather than GMT) without setting the high order bit. 42 * Furthermore, it does not understand daylight-saving time. This makes 43 * clockdiff behaving inconsistently with hosts running VMS. 44 * 45 * In order to reduce the sensitivity to the variance of message transmission 46 * time, clockdiff sends a sequence of messages. Yet, measures between 47 * two `distant' hosts can be affected by a small error. The error can, however, 48 * be reduced by increasing the number of messages sent in each measurement. 49 */ 50 51 clockdiff(argc, argv) 52 int argc; 53 char *argv[]; 54 { 55 int measure_status; 56 struct timeval ack; 57 int measure(); 58 59 if(argc < 2) { 60 printf("Usage: clockdiff host ... \n"); 61 return; 62 } 63 64 id = getpid(); 65 (void)gethostname(hostname,sizeof(hostname)); 66 67 while (argc > 1) { 68 argc--; argv++; 69 hp = gethostbyname(*argv); 70 if (hp == NULL) { 71 fprintf(stderr, "timed: %s: ", *argv); 72 herror((char *)NULL); 73 continue; 74 } 75 server.sin_family = hp->h_addrtype; 76 bcopy(hp->h_addr, &(server.sin_addr.s_addr), hp->h_length); 77 ack.tv_sec = 10; 78 ack.tv_usec = 0; 79 if ((measure_status = measure(&ack, &server)) < 0) { 80 perror("measure"); 81 return; 82 } 83 switch (measure_status) { 84 85 case HOSTDOWN: 86 printf("%s is down\n", hp->h_name); 87 continue; 88 break; 89 case NONSTDTIME: 90 printf("%s time transmitted in a non-standard format\n", hp->h_name); 91 continue; 92 break; 93 case UNREACHABLE: 94 printf("%s is unreachable\n", hp->h_name); 95 continue; 96 break; 97 default: 98 break; 99 } 100 101 if (measure_delta > 0) 102 printf("time on %s is %d ms. ahead of time on %s\n", 103 hp->h_name, measure_delta, 104 hostname); 105 else 106 if (measure_delta == 0) 107 printf("%s and %s have the same time\n", 108 hp->h_name, hostname); 109 else 110 printf("time on %s is %d ms. behind time on %s\n", 111 hp->h_name, -measure_delta, hostname); 112 } 113 return; 114 } 115 /* 116 * finds location of master timedaemon 117 */ 118 119 msite(argc) 120 int argc; 121 { 122 int length; 123 int cc; 124 fd_set ready; 125 struct sockaddr_in dest; 126 struct timeval tout; 127 struct sockaddr_in from; 128 struct tsp msg; 129 struct servent *srvp; 130 131 if (argc != 1) { 132 printf("Usage: msite\n"); 133 return; 134 } 135 136 srvp = getservbyname("timed", "udp"); 137 if (srvp == 0) { 138 fprintf(stderr, "udp/timed: unknown service\n"); 139 return; 140 } 141 dest.sin_port = srvp->s_port; 142 dest.sin_family = AF_INET; 143 144 (void)gethostname(hostname, sizeof(hostname)); 145 hp = gethostbyname(hostname); 146 if (hp == NULL) { 147 fprintf(stderr, "timed: %s: ", hostname); 148 herror((char *)NULL); 149 return; 150 } 151 bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length); 152 153 (void)strcpy(msg.tsp_name, hostname); 154 msg.tsp_type = TSP_MSITE; 155 msg.tsp_vers = TSPVERSION; 156 bytenetorder(&msg); 157 length = sizeof(struct sockaddr_in); 158 if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0, 159 (struct sockaddr *)&dest, length) < 0) { 160 perror("sendto"); 161 return; 162 } 163 164 tout.tv_sec = 15; 165 tout.tv_usec = 0; 166 FD_ZERO(&ready); 167 FD_SET(sock, &ready); 168 if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) { 169 length = sizeof(struct sockaddr_in); 170 cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0, 171 (struct sockaddr *)&from, &length); 172 if (cc < 0) { 173 perror("recvfrom"); 174 return; 175 } 176 bytehostorder(&msg); 177 if (msg.tsp_type == TSP_ACK) 178 printf("master timedaemon runs on %s\n", msg.tsp_name); 179 else 180 printf("received wrong ack: %s\n", 181 tsptype[msg.tsp_type]); 182 } else 183 printf("communication error\n"); 184 } 185 186 /* 187 * quits timedc 188 */ 189 190 quit() 191 { 192 exit(0); 193 } 194 195 #define MAXH 4 /* max no. of hosts where election can occur */ 196 197 /* 198 * Causes the election timer to expire on the selected hosts 199 * It sends just one udp message per machine, relying on 200 * reliability of communication channel. 201 */ 202 203 testing(argc, argv) 204 int argc; 205 char *argv[]; 206 { 207 int length; 208 int nhosts; 209 struct servent *srvp; 210 struct sockaddr_in sin[MAXH]; 211 struct tsp msg; 212 213 if(argc < 2) { 214 printf("Usage: testing host ...\n"); 215 return; 216 } 217 218 srvp = getservbyname("timed", "udp"); 219 if (srvp == 0) { 220 fprintf(stderr, "udp/timed: unknown service\n"); 221 return; 222 } 223 224 nhosts = 0; 225 while (argc > 1) { 226 argc--; argv++; 227 hp = gethostbyname(*argv); 228 if (hp == NULL) { 229 fprintf(stderr, "timed: %s: ", *argv); 230 herror((char *)NULL); 231 argc--; argv++; 232 continue; 233 } 234 sin[nhosts].sin_port = srvp->s_port; 235 sin[nhosts].sin_family = hp->h_addrtype; 236 bcopy(hp->h_addr, &(sin[nhosts].sin_addr.s_addr), hp->h_length); 237 if (++nhosts == MAXH) 238 break; 239 } 240 241 msg.tsp_type = TSP_TEST; 242 msg.tsp_vers = TSPVERSION; 243 (void)gethostname(hostname, sizeof(hostname)); 244 (void)strcpy(msg.tsp_name, hostname); 245 bytenetorder(&msg); /* it is not really necessary here */ 246 while (nhosts-- > 0) { 247 length = sizeof(struct sockaddr_in); 248 if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0, 249 (struct sockaddr *)&sin[nhosts], length) < 0) { 250 perror("sendto"); 251 return; 252 } 253 } 254 } 255 256 /* 257 * Enables or disables tracing on local timedaemon 258 */ 259 260 tracing(argc, argv) 261 int argc; 262 char *argv[]; 263 { 264 int onflag; 265 int length; 266 int cc; 267 fd_set ready; 268 struct sockaddr_in dest; 269 struct timeval tout; 270 struct sockaddr_in from; 271 struct tsp msg; 272 struct servent *srvp; 273 274 if (argc != 2) { 275 printf("Usage: tracing { on | off }\n"); 276 return; 277 } 278 279 srvp = getservbyname("timed", "udp"); 280 if (srvp == 0) { 281 fprintf(stderr, "udp/timed: unknown service\n"); 282 return; 283 } 284 dest.sin_port = srvp->s_port; 285 dest.sin_family = AF_INET; 286 287 (void)gethostname(hostname,sizeof(hostname)); 288 hp = gethostbyname(hostname); 289 bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length); 290 291 if (strcmp(argv[1], "on") == 0) { 292 msg.tsp_type = TSP_TRACEON; 293 onflag = ON; 294 } else { 295 msg.tsp_type = TSP_TRACEOFF; 296 onflag = OFF; 297 } 298 299 (void)strcpy(msg.tsp_name, hostname); 300 msg.tsp_vers = TSPVERSION; 301 bytenetorder(&msg); 302 length = sizeof(struct sockaddr_in); 303 if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0, 304 (struct sockaddr *)&dest, length) < 0) { 305 perror("sendto"); 306 return; 307 } 308 309 tout.tv_sec = 5; 310 tout.tv_usec = 0; 311 FD_ZERO(&ready); 312 FD_SET(sock, &ready); 313 if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) { 314 length = sizeof(struct sockaddr_in); 315 cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0, 316 (struct sockaddr *)&from, &length); 317 if (cc < 0) { 318 perror("recvfrom"); 319 return; 320 } 321 bytehostorder(&msg); 322 if (msg.tsp_type == TSP_ACK) 323 if (onflag) 324 printf("timed tracing enabled\n"); 325 else 326 printf("timed tracing disabled\n"); 327 else 328 printf("wrong ack received: %s\n", 329 tsptype[msg.tsp_type]); 330 } else 331 printf("communication error\n"); 332 } 333 334 priv_resources() 335 { 336 int port; 337 struct sockaddr_in sin; 338 339 sock = socket(AF_INET, SOCK_DGRAM, 0); 340 if (sock < 0) { 341 perror("opening socket"); 342 return(-1); 343 } 344 345 sin.sin_family = AF_INET; 346 sin.sin_addr.s_addr = 0; 347 for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) { 348 sin.sin_port = htons((u_short)port); 349 if (bind(sock, (struct sockaddr *)&sin, sizeof (sin)) >= 0) 350 break; 351 if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) { 352 perror("bind"); 353 (void) close(sock); 354 return(-1); 355 } 356 } 357 if (port == IPPORT_RESERVED / 2) { 358 fprintf(stderr, "all reserved ports in use\n"); 359 (void) close(sock); 360 return(-1); 361 } 362 363 sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 364 if (sock_raw < 0) { 365 perror("opening raw socket"); 366 (void) close(sock_raw); 367 return(-1); 368 } 369 return(1); 370 } 371