1 /*- 2 * Copyright (c) 1985, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)readmsg.c 8.1 (Berkeley) 06/06/93"; 10 #endif /* not lint */ 11 12 #ifdef sgi 13 #ident "$Revision: 1.17 $" 14 #endif 15 16 #include "globals.h" 17 18 extern char *tsptype[]; 19 20 /* 21 * LOOKAT checks if the message is of the requested type and comes from 22 * the right machine, returning 1 in case of affirmative answer 23 */ 24 #define LOOKAT(msg, mtype, mfrom, netp, froms) \ 25 (((mtype) == TSP_ANY || (mtype) == (msg).tsp_type) && \ 26 ((mfrom) == 0 || !strcmp((mfrom), (msg).tsp_name)) && \ 27 ((netp) == 0 || \ 28 ((netp)->mask & (froms).sin_addr.s_addr) == (netp)->net.s_addr)) 29 30 struct timeval rtime, rwait, rtout; 31 struct tsp msgin; 32 static struct tsplist { 33 struct tsp info; 34 struct timeval when; 35 struct sockaddr_in addr; 36 struct tsplist *p; 37 } msgslist; 38 struct sockaddr_in from; 39 struct netinfo *fromnet; 40 struct timeval from_when; 41 42 /* 43 * `readmsg' returns message `type' sent by `machfrom' if it finds it 44 * either in the receive queue, or in a linked list of previously received 45 * messages that it maintains. 46 * Otherwise it waits to see if the appropriate message arrives within 47 * `intvl' seconds. If not, it returns NULL. 48 */ 49 50 struct tsp * 51 readmsg(type, machfrom, intvl, netfrom) 52 int type; 53 char *machfrom; 54 struct timeval *intvl; 55 struct netinfo *netfrom; 56 { 57 int length; 58 fd_set ready; 59 static struct tsplist *head = &msgslist; 60 static struct tsplist *tail = &msgslist; 61 static int msgcnt = 0; 62 struct tsplist *prev; 63 register struct netinfo *ntp; 64 register struct tsplist *ptr; 65 66 if (trace) { 67 fprintf(fd, "readmsg: looking for %s from %s, %s\n", 68 tsptype[type], machfrom == NULL ? "ANY" : machfrom, 69 netfrom == NULL ? "ANYNET" : inet_ntoa(netfrom->net)); 70 if (head->p != 0) { 71 length = 1; 72 for (ptr = head->p; ptr != 0; ptr = ptr->p) { 73 /* do not repeat the hundreds of messages */ 74 if (++length > 3) { 75 if (ptr == tail) { 76 fprintf(fd,"\t ...%d skipped\n", 77 length); 78 } else { 79 continue; 80 } 81 } 82 fprintf(fd, length > 1 ? "\t" : "queue:\t"); 83 print(&ptr->info, &ptr->addr); 84 } 85 } 86 } 87 88 ptr = head->p; 89 prev = head; 90 91 /* 92 * Look for the requested message scanning through the 93 * linked list. If found, return it and free the space 94 */ 95 96 while (ptr != NULL) { 97 if (LOOKAT(ptr->info, type, machfrom, netfrom, ptr->addr)) { 98 again: 99 msgin = ptr->info; 100 from = ptr->addr; 101 from_when = ptr->when; 102 prev->p = ptr->p; 103 if (ptr == tail) 104 tail = prev; 105 free((char *)ptr); 106 fromnet = NULL; 107 if (netfrom == NULL) 108 for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 109 if ((ntp->mask & from.sin_addr.s_addr) == 110 ntp->net.s_addr) { 111 fromnet = ntp; 112 break; 113 } 114 } 115 else 116 fromnet = netfrom; 117 if (trace) { 118 fprintf(fd, "readmsg: found "); 119 print(&msgin, &from); 120 } 121 122 /* The protocol can get far behind. When it does, it gets 123 * hopelessly confused. So delete duplicate messages. 124 */ 125 for (ptr = prev; (ptr = ptr->p) != NULL; prev = ptr) { 126 if (ptr->addr.sin_addr.s_addr 127 == from.sin_addr.s_addr 128 && ptr->info.tsp_type == msgin.tsp_type) { 129 if (trace) 130 fprintf(fd, "\tdup "); 131 goto again; 132 } 133 } 134 msgcnt--; 135 return(&msgin); 136 } else { 137 prev = ptr; 138 ptr = ptr->p; 139 } 140 } 141 142 /* 143 * If the message was not in the linked list, it may still be 144 * coming from the network. Set the timer and wait 145 * on a select to read the next incoming message: if it is the 146 * right one, return it, otherwise insert it in the linked list. 147 */ 148 149 (void)gettimeofday(&rtout, 0); 150 timevaladd(&rtout, intvl); 151 FD_ZERO(&ready); 152 for (;;) { 153 (void)gettimeofday(&rtime, 0); 154 timevalsub(&rwait, &rtout, &rtime); 155 if (rwait.tv_sec < 0) 156 rwait.tv_sec = rwait.tv_usec = 0; 157 else if (rwait.tv_sec == 0 158 && rwait.tv_usec < 1000000/CLK_TCK) 159 rwait.tv_usec = 1000000/CLK_TCK; 160 161 if (trace) { 162 fprintf(fd, "readmsg: wait %ld.%6ld at %s\n", 163 rwait.tv_sec, rwait.tv_usec, date()); 164 /* Notice a full disk, as we flush trace info. 165 * It is better to flush periodically than at 166 * every line because the tracing consists of bursts 167 * of many lines. Without care, tracing slows 168 * down the code enough to break the protocol. 169 */ 170 if (rwait.tv_sec != 0 171 && EOF == fflush(fd)) 172 traceoff("Tracing ended for cause at %s\n"); 173 } 174 175 FD_SET(sock, &ready); 176 if (!select(sock+1, &ready, (fd_set *)0, (fd_set *)0, 177 &rwait)) { 178 if (rwait.tv_sec == 0 && rwait.tv_usec == 0) 179 return(0); 180 continue; 181 } 182 length = sizeof(from); 183 if (recvfrom(sock, (char *)&msgin, sizeof(struct tsp), 0, 184 (struct sockaddr*)&from, &length) < 0) { 185 syslog(LOG_ERR, "recvfrom: %m"); 186 exit(1); 187 } 188 (void)gettimeofday(&from_when, (struct timezone *)0); 189 bytehostorder(&msgin); 190 191 if (msgin.tsp_vers > TSPVERSION) { 192 if (trace) { 193 fprintf(fd,"readmsg: version mismatch\n"); 194 /* should do a dump of the packet */ 195 } 196 continue; 197 } 198 199 fromnet = NULL; 200 for (ntp = nettab; ntp != NULL; ntp = ntp->next) 201 if ((ntp->mask & from.sin_addr.s_addr) == 202 ntp->net.s_addr) { 203 fromnet = ntp; 204 break; 205 } 206 207 /* 208 * drop packets from nets we are ignoring permanently 209 */ 210 if (fromnet == NULL) { 211 /* 212 * The following messages may originate on 213 * this host with an ignored network address 214 */ 215 if (msgin.tsp_type != TSP_TRACEON && 216 msgin.tsp_type != TSP_SETDATE && 217 msgin.tsp_type != TSP_MSITE && 218 msgin.tsp_type != TSP_TEST && 219 msgin.tsp_type != TSP_TRACEOFF) { 220 if (trace) { 221 fprintf(fd,"readmsg: discard null net "); 222 print(&msgin, &from); 223 } 224 continue; 225 } 226 } 227 228 /* 229 * Throw away messages coming from this machine, 230 * unless they are of some particular type. 231 * This gets rid of broadcast messages and reduces 232 * master processing time. 233 */ 234 if (!strcmp(msgin.tsp_name, hostname) 235 && msgin.tsp_type != TSP_SETDATE 236 && msgin.tsp_type != TSP_TEST 237 && msgin.tsp_type != TSP_MSITE 238 && msgin.tsp_type != TSP_TRACEON 239 && msgin.tsp_type != TSP_TRACEOFF 240 && msgin.tsp_type != TSP_LOOP) { 241 if (trace) { 242 fprintf(fd, "readmsg: discard own "); 243 print(&msgin, &from); 244 } 245 continue; 246 } 247 248 /* 249 * Send acknowledgements here; this is faster and 250 * avoids deadlocks that would occur if acks were 251 * sent from a higher level routine. Different 252 * acknowledgements are necessary, depending on 253 * status. 254 */ 255 if (fromnet == NULL) /* do not de-reference 0 */ 256 ignoreack(); 257 else if (fromnet->status == MASTER) 258 masterack(); 259 else if (fromnet->status == SLAVE) 260 slaveack(); 261 else 262 ignoreack(); 263 264 if (LOOKAT(msgin, type, machfrom, netfrom, from)) { 265 if (trace) { 266 fprintf(fd, "readmsg: "); 267 print(&msgin, &from); 268 } 269 return(&msgin); 270 } else if (++msgcnt > NHOSTS*3) { 271 272 /* The protocol gets hopelessly confused if it gets too far 273 * behind. However, it seems able to recover from all cases of lost 274 * packets. Therefore, if we are swamped, throw everything away. 275 */ 276 if (trace) 277 fprintf(fd, 278 "readmsg: discarding %d msgs\n", 279 msgcnt); 280 msgcnt = 0; 281 while ((ptr=head->p) != NULL) { 282 head->p = ptr->p; 283 free((char *)ptr); 284 } 285 tail = head; 286 } else { 287 tail->p = (struct tsplist *) 288 malloc(sizeof(struct tsplist)); 289 tail = tail->p; 290 tail->p = NULL; 291 tail->info = msgin; 292 tail->addr = from; 293 /* timestamp msgs so SETTIMEs are correct */ 294 tail->when = from_when; 295 } 296 } 297 } 298 299 /* 300 * Send the necessary acknowledgements: 301 * only the type ACK is to be sent by a slave 302 */ 303 void 304 slaveack() 305 { 306 switch(msgin.tsp_type) { 307 308 case TSP_ADJTIME: 309 case TSP_SETTIME: 310 case TSP_ACCEPT: 311 case TSP_REFUSE: 312 case TSP_TRACEON: 313 case TSP_TRACEOFF: 314 case TSP_QUIT: 315 if (trace) { 316 fprintf(fd, "Slaveack: "); 317 print(&msgin, &from); 318 } 319 xmit(TSP_ACK,msgin.tsp_seq, &from); 320 break; 321 322 default: 323 if (trace) { 324 fprintf(fd, "Slaveack: no ack: "); 325 print(&msgin, &from); 326 } 327 break; 328 } 329 } 330 331 /* 332 * Certain packets may arrive from this machine on ignored networks. 333 * These packets should be acknowledged. 334 */ 335 void 336 ignoreack() 337 { 338 switch(msgin.tsp_type) { 339 340 case TSP_TRACEON: 341 case TSP_TRACEOFF: 342 case TSP_QUIT: 343 if (trace) { 344 fprintf(fd, "Ignoreack: "); 345 print(&msgin, &from); 346 } 347 xmit(TSP_ACK,msgin.tsp_seq, &from); 348 break; 349 350 default: 351 if (trace) { 352 fprintf(fd, "Ignoreack: no ack: "); 353 print(&msgin, &from); 354 } 355 break; 356 } 357 } 358 359 /* 360 * `masterack' sends the necessary acknowledgments 361 * to the messages received by a master 362 */ 363 void 364 masterack() 365 { 366 struct tsp resp; 367 368 resp = msgin; 369 resp.tsp_vers = TSPVERSION; 370 (void)strcpy(resp.tsp_name, hostname); 371 372 switch(msgin.tsp_type) { 373 374 case TSP_QUIT: 375 case TSP_TRACEON: 376 case TSP_TRACEOFF: 377 case TSP_MSITEREQ: 378 if (trace) { 379 fprintf(fd, "Masterack: "); 380 print(&msgin, &from); 381 } 382 xmit(TSP_ACK,msgin.tsp_seq, &from); 383 break; 384 385 case TSP_RESOLVE: 386 case TSP_MASTERREQ: 387 if (trace) { 388 fprintf(fd, "Masterack: "); 389 print(&msgin, &from); 390 } 391 xmit(TSP_MASTERACK,msgin.tsp_seq, &from); 392 break; 393 394 default: 395 if (trace) { 396 fprintf(fd,"Masterack: no ack: "); 397 print(&msgin, &from); 398 } 399 break; 400 } 401 } 402 403 /* 404 * Print a TSP message 405 */ 406 void 407 print(msg, addr) 408 struct tsp *msg; 409 struct sockaddr_in *addr; 410 { 411 char tm[26]; 412 switch (msg->tsp_type) { 413 414 case TSP_LOOP: 415 fprintf(fd, "%s %d %-6u #%d %-15s %s\n", 416 tsptype[msg->tsp_type], 417 msg->tsp_vers, 418 msg->tsp_seq, 419 msg->tsp_hopcnt, 420 inet_ntoa(addr->sin_addr), 421 msg->tsp_name); 422 break; 423 424 case TSP_SETTIME: 425 case TSP_SETDATE: 426 case TSP_SETDATEREQ: 427 #ifdef sgi 428 (void)cftime(tm, "%D %T", &msg->tsp_time.tv_sec); 429 #else 430 strncpy(tm, ctime(&msg->tsp_time.tv_sec)+3+1, sizeof(tm)); 431 tm[15] = '\0'; /* ugh */ 432 #endif /* sgi */ 433 fprintf(fd, "%s %d %-6u %s %-15s %s\n", 434 tsptype[msg->tsp_type], 435 msg->tsp_vers, 436 msg->tsp_seq, 437 tm, 438 inet_ntoa(addr->sin_addr), 439 msg->tsp_name); 440 break; 441 442 case TSP_ADJTIME: 443 fprintf(fd, "%s %d %-6u (%ld,%ld) %-15s %s\n", 444 tsptype[msg->tsp_type], 445 msg->tsp_vers, 446 msg->tsp_seq, 447 msg->tsp_time.tv_sec, 448 msg->tsp_time.tv_usec, 449 inet_ntoa(addr->sin_addr), 450 msg->tsp_name); 451 break; 452 453 default: 454 fprintf(fd, "%s %d %-6u %-15s %s\n", 455 tsptype[msg->tsp_type], 456 msg->tsp_vers, 457 msg->tsp_seq, 458 inet_ntoa(addr->sin_addr), 459 msg->tsp_name); 460 break; 461 } 462 } 463