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