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