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