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