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.5 (Berkeley) 06/18/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 printf("%s: unknown host\n", *argv); 82 continue; 83 } 84 server.sin_family = hp->h_addrtype; 85 bcopy(hp->h_addr, &(server.sin_addr.s_addr), hp->h_length); 86 ack.tv_sec = 10; 87 ack.tv_usec = 0; 88 if ((measure_status = measure(&ack, &server)) < 0) { 89 perror("measure"); 90 return; 91 } 92 switch (measure_status) { 93 94 case HOSTDOWN: 95 printf("%s is down\n", hp->h_name); 96 continue; 97 break; 98 case NONSTDTIME: 99 printf("%s time transmitted in a non-standard format\n", hp->h_name); 100 continue; 101 break; 102 case UNREACHABLE: 103 printf("%s is unreachable\n", hp->h_name); 104 continue; 105 break; 106 default: 107 break; 108 } 109 110 if (measure_delta > 0) 111 printf("time on %s is %d ms. ahead of time on %s\n", 112 hp->h_name, measure_delta, 113 hostname); 114 else 115 if (measure_delta == 0) 116 printf("%s and %s have the same time\n", 117 hp->h_name, hostname); 118 else 119 printf("time on %s is %d ms. behind time on %s\n", 120 hp->h_name, -measure_delta, hostname); 121 } 122 return; 123 } 124 /* 125 * finds location of master timedaemon 126 */ 127 128 msite(argc) 129 int argc; 130 { 131 int length; 132 int cc; 133 fd_set ready; 134 struct sockaddr_in dest; 135 struct timeval tout; 136 struct sockaddr_in from; 137 struct tsp msg; 138 struct servent *srvp; 139 140 if (argc != 1) { 141 printf("Usage: msite\n"); 142 return; 143 } 144 145 srvp = getservbyname("timed", "udp"); 146 if (srvp == 0) { 147 fprintf(stderr, "udp/timed: unknown service\n"); 148 return; 149 } 150 dest.sin_port = srvp->s_port; 151 dest.sin_family = AF_INET; 152 153 (void)gethostname(hostname,sizeof(hostname)); 154 hp = gethostbyname(hostname); 155 if (hp == NULL) { 156 perror("gethostbyname"); 157 return; 158 } 159 bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length); 160 161 (void)strcpy(msg.tsp_name, hostname); 162 msg.tsp_type = TSP_MSITE; 163 msg.tsp_vers = TSPVERSION; 164 bytenetorder(&msg); 165 length = sizeof(struct sockaddr_in); 166 if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0, 167 &dest, length) < 0) { 168 perror("sendto"); 169 return; 170 } 171 172 tout.tv_sec = 15; 173 tout.tv_usec = 0; 174 FD_ZERO(&ready); 175 FD_SET(sock, &ready); 176 if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) { 177 length = sizeof(struct sockaddr_in); 178 cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0, 179 &from, &length); 180 if (cc < 0) { 181 perror("recvfrom"); 182 return; 183 } 184 bytehostorder(&msg); 185 if (msg.tsp_type == TSP_ACK) 186 printf("master timedaemon runs on %s\n", msg.tsp_name); 187 else 188 printf("received wrong ack: %s\n", 189 tsptype[msg.tsp_type]); 190 } else 191 printf("communication error\n"); 192 } 193 194 /* 195 * quits timedc 196 */ 197 198 quit() 199 { 200 exit(0); 201 } 202 203 #define MAXH 4 /* max no. of hosts where election can occur */ 204 205 /* 206 * Causes the election timer to expire on the selected hosts 207 * It sends just one udp message per machine, relying on 208 * reliability of communication channel. 209 */ 210 211 testing(argc, argv) 212 int argc; 213 char *argv[]; 214 { 215 int length; 216 int nhosts; 217 struct servent *srvp; 218 struct sockaddr_in sin[MAXH]; 219 struct tsp msg; 220 221 if(argc < 2) { 222 printf("Usage: testing host ...\n"); 223 return; 224 } 225 226 srvp = getservbyname("timed", "udp"); 227 if (srvp == 0) { 228 fprintf(stderr, "udp/timed: unknown service\n"); 229 return; 230 } 231 232 nhosts = 0; 233 while (argc > 1) { 234 argc--; argv++; 235 hp = gethostbyname(*argv); 236 if (hp == NULL) { 237 printf("%s: unknown host\n", *argv); 238 argc--; argv++; 239 continue; 240 } 241 sin[nhosts].sin_port = srvp->s_port; 242 sin[nhosts].sin_family = hp->h_addrtype; 243 bcopy(hp->h_addr, &(sin[nhosts].sin_addr.s_addr), hp->h_length); 244 if (++nhosts == MAXH) 245 break; 246 } 247 248 msg.tsp_type = TSP_TEST; 249 msg.tsp_vers = TSPVERSION; 250 (void)gethostname(hostname, sizeof(hostname)); 251 (void)strcpy(msg.tsp_name, hostname); 252 bytenetorder(&msg); /* it is not really necessary here */ 253 while (nhosts-- > 0) { 254 length = sizeof(struct sockaddr_in); 255 if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0, 256 &sin[nhosts], length) < 0) { 257 perror("sendto"); 258 return; 259 } 260 } 261 } 262 263 /* 264 * Enables or disables tracing on local timedaemon 265 */ 266 267 tracing(argc, argv) 268 int argc; 269 char *argv[]; 270 { 271 int onflag; 272 int length; 273 int cc; 274 fd_set ready; 275 struct sockaddr_in dest; 276 struct timeval tout; 277 struct sockaddr_in from; 278 struct tsp msg; 279 struct servent *srvp; 280 281 if (argc != 2) { 282 printf("Usage: tracing { on | off }\n"); 283 return; 284 } 285 286 srvp = getservbyname("timed", "udp"); 287 if (srvp == 0) { 288 fprintf(stderr, "udp/timed: unknown service\n"); 289 return; 290 } 291 dest.sin_port = srvp->s_port; 292 dest.sin_family = AF_INET; 293 294 (void)gethostname(hostname,sizeof(hostname)); 295 hp = gethostbyname(hostname); 296 bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length); 297 298 if (strcmp(argv[1], "on") == 0) { 299 msg.tsp_type = TSP_TRACEON; 300 onflag = ON; 301 } else { 302 msg.tsp_type = TSP_TRACEOFF; 303 onflag = OFF; 304 } 305 306 (void)strcpy(msg.tsp_name, hostname); 307 msg.tsp_vers = TSPVERSION; 308 bytenetorder(&msg); 309 length = sizeof(struct sockaddr_in); 310 if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0, 311 &dest, length) < 0) { 312 perror("sendto"); 313 return; 314 } 315 316 tout.tv_sec = 5; 317 tout.tv_usec = 0; 318 FD_ZERO(&ready); 319 FD_SET(sock, &ready); 320 if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) { 321 length = sizeof(struct sockaddr_in); 322 cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0, 323 &from, &length); 324 if (cc < 0) { 325 perror("recvfrom"); 326 return; 327 } 328 bytehostorder(&msg); 329 if (msg.tsp_type == TSP_ACK) 330 if (onflag) 331 printf("timed tracing enabled\n"); 332 else 333 printf("timed tracing disabled\n"); 334 else 335 printf("wrong ack received: %s\n", 336 tsptype[msg.tsp_type]); 337 } else 338 printf("communication error\n"); 339 } 340 341 priv_resources() 342 { 343 int port; 344 struct sockaddr_in sin; 345 346 sock = socket(AF_INET, SOCK_DGRAM, 0); 347 if (sock < 0) { 348 perror("opening socket"); 349 return(-1); 350 } 351 352 sin.sin_family = AF_INET; 353 sin.sin_addr.s_addr = 0; 354 for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) { 355 sin.sin_port = htons((u_short)port); 356 if (bind(sock, (struct sockaddr *)&sin, sizeof (sin)) >= 0) 357 break; 358 if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) { 359 perror("bind"); 360 (void) close(sock); 361 return(-1); 362 } 363 } 364 if (port == IPPORT_RESERVED / 2) { 365 fprintf(stderr, "all reserved ports in use\n"); 366 (void) close(sock); 367 return(-1); 368 } 369 370 sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 371 if (sock_raw < 0) { 372 perror("opening raw socket"); 373 (void) close(sock_raw); 374 return(-1); 375 } 376 return(1); 377 } 378