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