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