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.13 (Berkeley) 03/02/91"; 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, (struct sockaddr *)&from, &length) < 0) { 156 syslog(LOG_ERR, 157 "receiving datagram packet: %m"); 158 exit(1); 159 } 160 161 bytehostorder(&msgin); 162 163 if (msgin.tsp_vers > TSPVERSION) { 164 if (trace) { 165 fprintf(fd, "readmsg: version mismatch\n"); 166 /* should do a dump of the packet, but... */ 167 } 168 continue; 169 } 170 171 fromnet = NULL; 172 for (ntp = nettab; ntp != NULL; ntp = ntp->next) 173 if ((ntp->mask & from.sin_addr.s_addr) == 174 ntp->net) { 175 fromnet = ntp; 176 break; 177 } 178 179 /* 180 * drop packets from nets we are ignoring permanently 181 */ 182 if (fromnet == NULL) { 183 /* 184 * The following messages may originate on 185 * this host with an ignored network address 186 */ 187 if (msgin.tsp_type != TSP_TRACEON && 188 msgin.tsp_type != TSP_SETDATE && 189 msgin.tsp_type != TSP_MSITE && 190 #ifdef TESTING 191 msgin.tsp_type != TSP_TEST && 192 #endif 193 msgin.tsp_type != TSP_TRACEOFF) { 194 if (trace) { 195 fprintf(fd, "readmsg: discarded: "); 196 print(&msgin, &from); 197 } 198 continue; 199 } 200 } 201 202 /* 203 * Throw away messages coming from this machine, unless 204 * they are of some particular type. 205 * This gets rid of broadcast messages and reduces 206 * master processing time. 207 */ 208 if ( !(strcmp(msgin.tsp_name, hostname) != 0 || 209 msgin.tsp_type == TSP_SETDATE || 210 #ifdef TESTING 211 msgin.tsp_type == TSP_TEST || 212 #endif 213 msgin.tsp_type == TSP_MSITE || 214 (msgin.tsp_type == TSP_LOOP && 215 msgin.tsp_hopcnt != 10) || 216 msgin.tsp_type == TSP_TRACEON || 217 msgin.tsp_type == TSP_TRACEOFF)) { 218 if (trace) { 219 fprintf(fd, "readmsg: discarded: "); 220 print(&msgin, &from); 221 } 222 continue; 223 } 224 225 /* 226 * Send acknowledgements here; this is faster and avoids 227 * deadlocks that would occur if acks were sent from a 228 * higher level routine. Different acknowledgements are 229 * necessary, depending on status. 230 */ 231 if (fromnet->status == MASTER) 232 masterack(); 233 else if (fromnet->status == SLAVE) 234 slaveack(); 235 else 236 ignoreack(); 237 238 if (LOOKAT(msgin, type, machfrom, netfrom, from)) { 239 if (trace) { 240 fprintf(fd, "readmsg: "); 241 print(&msgin, &from); 242 } 243 return(&msgin); 244 } else { 245 tail->p = (struct tsplist *) 246 malloc(sizeof(struct tsplist)); 247 tail = tail->p; 248 tail->p = NULL; 249 tail->info = msgin; 250 tail->addr = from; 251 } 252 } else { 253 break; 254 } 255 } 256 return((struct tsp *)NULL); 257 } 258 259 /* 260 * `slaveack' sends the necessary acknowledgements: 261 * only the type ACK is to be sent by a slave 262 */ 263 264 slaveack() 265 { 266 int length; 267 struct tsp resp; 268 269 length = sizeof(struct sockaddr_in); 270 switch(msgin.tsp_type) { 271 272 case TSP_ADJTIME: 273 case TSP_SETTIME: 274 case TSP_ACCEPT: 275 case TSP_REFUSE: 276 case TSP_TRACEON: 277 case TSP_TRACEOFF: 278 case TSP_QUIT: 279 resp = msgin; 280 resp.tsp_type = TSP_ACK; 281 resp.tsp_vers = TSPVERSION; 282 (void)strcpy(resp.tsp_name, hostname); 283 if (trace) { 284 fprintf(fd, "Slaveack: "); 285 print(&resp, &from); 286 } 287 bytenetorder(&resp); /* this is not really necessary here */ 288 if (sendto(sock, (char *)&resp, sizeof(struct tsp), 0, 289 (struct sockaddr *)&from, length) < 0) { 290 syslog(LOG_ERR, "sendto: %m"); 291 exit(1); 292 } 293 break; 294 default: 295 break; 296 } 297 } 298 299 /* 300 * Certain packets may arrive from this machine on ignored networks. 301 * These packets should be acknowledged. 302 */ 303 304 ignoreack() 305 { 306 int length; 307 struct tsp resp; 308 309 length = sizeof(struct sockaddr_in); 310 switch(msgin.tsp_type) { 311 312 case TSP_TRACEON: 313 case TSP_TRACEOFF: 314 resp = msgin; 315 resp.tsp_type = TSP_ACK; 316 resp.tsp_vers = TSPVERSION; 317 (void)strcpy(resp.tsp_name, hostname); 318 if (trace) { 319 fprintf(fd, "Ignoreack: "); 320 print(&resp, &from); 321 } 322 bytenetorder(&resp); /* this is not really necessary here */ 323 if (sendto(sock, (char *)&resp, sizeof(struct tsp), 0, 324 (struct sockaddr *)&from, length) < 0) { 325 syslog(LOG_ERR, "sendto: %m"); 326 exit(1); 327 } 328 break; 329 default: 330 break; 331 } 332 } 333 334 /* 335 * `masterack' sends the necessary acknowledgments 336 * to the messages received by a master 337 */ 338 339 masterack() 340 { 341 int length; 342 struct tsp resp; 343 344 length = sizeof(struct sockaddr_in); 345 346 resp = msgin; 347 resp.tsp_vers = TSPVERSION; 348 (void)strcpy(resp.tsp_name, hostname); 349 350 switch(msgin.tsp_type) { 351 352 case TSP_QUIT: 353 case TSP_TRACEON: 354 case TSP_TRACEOFF: 355 case TSP_MSITE: 356 case TSP_MSITEREQ: 357 resp.tsp_type = TSP_ACK; 358 bytenetorder(&resp); 359 if (trace) { 360 fprintf(fd, "Masterack: "); 361 print(&resp, &from); 362 } 363 if (sendto(sock, (char *)&resp, sizeof(struct tsp), 0, 364 (struct sockaddr *)&from, length) < 0) { 365 syslog(LOG_ERR, "sendto: %m"); 366 exit(1); 367 } 368 break; 369 case TSP_RESOLVE: 370 case TSP_MASTERREQ: 371 resp.tsp_type = TSP_MASTERACK; 372 bytenetorder(&resp); 373 if (trace) { 374 fprintf(fd, "Masterack: "); 375 print(&resp, &from); 376 } 377 if (sendto(sock, (char *)&resp, sizeof(struct tsp), 0, 378 (struct sockaddr *)&from, length) < 0) { 379 syslog(LOG_ERR, "sendto: %m"); 380 exit(1); 381 } 382 break; 383 case TSP_SETDATEREQ: 384 resp.tsp_type = TSP_DATEACK; 385 bytenetorder(&resp); 386 if (trace) { 387 fprintf(fd, "Masterack: "); 388 print(&resp, &from); 389 } 390 if (sendto(sock, (char *)&resp, sizeof(struct tsp), 0, 391 (struct sockaddr *)&from, length) < 0) { 392 syslog(LOG_ERR, "sendto: %m"); 393 exit(1); 394 } 395 break; 396 default: 397 break; 398 } 399 } 400 401 /* 402 * Print a TSP message 403 */ 404 print(msg, addr) 405 struct tsp *msg; 406 struct sockaddr_in *addr; 407 { 408 switch (msg->tsp_type) { 409 410 case TSP_LOOP: 411 fprintf(fd, "%s %d %d (#%d) %s %s\n", 412 tsptype[msg->tsp_type], 413 msg->tsp_vers, 414 msg->tsp_seq, 415 msg->tsp_hopcnt, 416 msg->tsp_name, 417 inet_ntoa(addr->sin_addr)); 418 break; 419 420 case TSP_SETTIME: 421 case TSP_ADJTIME: 422 case TSP_SETDATE: 423 case TSP_SETDATEREQ: 424 fprintf(fd, "%s %d %d (%d, %d) %s %s\n", 425 tsptype[msg->tsp_type], 426 msg->tsp_vers, 427 msg->tsp_seq, 428 msg->tsp_time.tv_sec, 429 msg->tsp_time.tv_usec, 430 msg->tsp_name, 431 inet_ntoa(addr->sin_addr)); 432 break; 433 434 default: 435 fprintf(fd, "%s %d %d %s %s\n", 436 tsptype[msg->tsp_type], 437 msg->tsp_vers, 438 msg->tsp_seq, 439 msg->tsp_name, 440 inet_ntoa(addr->sin_addr)); 441 break; 442 } 443 } 444