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