| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
1 | /*- |
| 2 | * Copyright (c) 1985, 1993 | |
| 3 | * The Regents of the University of California. All rights reserved. | |
| 4 | * | |
| 5 | * Redistribution and use in source and binary forms, with or without | |
| 6 | * modification, are permitted provided that the following conditions | |
| 7 | * are met: | |
| 8 | * 1. Redistributions of source code must retain the above copyright | |
| 9 | * notice, this list of conditions and the following disclaimer. | |
| 10 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 11 | * notice, this list of conditions and the following disclaimer in the | |
| 12 | * documentation and/or other materials provided with the distribution. | |
| 13 | * 3. All advertising materials mentioning features or use of this software | |
| 14 | * must display the following acknowledgement: | |
| 15 | * This product includes software developed by the University of | |
| 16 | * California, Berkeley and its contributors. | |
| 17 | * 4. Neither the name of the University nor the names of its contributors | |
| 18 | * may be used to endorse or promote products derived from this software | |
| 19 | * without specific prior written permission. | |
| 20 | * | |
| 21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
| 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
| 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 31 | * SUCH DAMAGE. | |
| 1de703da MD |
32 | * |
| 33 | * @(#)readmsg.c 8.1 (Berkeley) 6/6/93 | |
| 34 | * $FreeBSD: src/usr.sbin/timed/timed/readmsg.c,v 1.5.2.3 2001/08/31 08:02:05 kris Exp $ | |
| 37c7aa4c | 35 | * $DragonFly: src/usr.sbin/timed/timed/readmsg.c,v 1.6 2004/09/05 02:20:15 dillon Exp $ |
| 984263bc MD |
36 | */ |
| 37 | ||
| 984263bc MD |
38 | #include "globals.h" |
| 39 | ||
| 40 | extern char *tsptype[]; | |
| 41 | ||
| 42 | /* | |
| 43 | * LOOKAT checks if the message is of the requested type and comes from | |
| 44 | * the right machine, returning 1 in case of affirmative answer | |
| 45 | */ | |
| 46 | #define LOOKAT(msg, mtype, mfrom, netp, froms) \ | |
| 47 | (((mtype) == TSP_ANY || (mtype) == (msg).tsp_type) && \ | |
| 48 | ((mfrom) == 0 || !strcmp((mfrom), (msg).tsp_name)) && \ | |
| 49 | ((netp) == 0 || \ | |
| 50 | ((netp)->mask & (froms).sin_addr.s_addr) == (netp)->net.s_addr)) | |
| 51 | ||
| 52 | struct timeval rtime, rwait, rtout; | |
| 53 | struct tsp msgin; | |
| 54 | static struct tsplist { | |
| 55 | struct tsp info; | |
| 56 | struct timeval when; | |
| 57 | struct sockaddr_in addr; | |
| 58 | struct tsplist *p; | |
| 59 | } msgslist; | |
| 60 | struct sockaddr_in from; | |
| 61 | struct netinfo *fromnet; | |
| 62 | struct timeval from_when; | |
| 63 | ||
| 64 | /* | |
| 65 | * `readmsg' returns message `type' sent by `machfrom' if it finds it | |
| 66 | * either in the receive queue, or in a linked list of previously received | |
| 67 | * messages that it maintains. | |
| 68 | * Otherwise it waits to see if the appropriate message arrives within | |
| 69 | * `intvl' seconds. If not, it returns NULL. | |
| 70 | */ | |
| 71 | ||
| 72 | struct tsp * | |
| 320b887a EN |
73 | readmsg(int type, char *machfrom, struct timeval *intvl, |
| 74 | struct netinfo *netfrom) | |
| 984263bc MD |
75 | { |
| 76 | int length; | |
| 77 | fd_set ready; | |
| 78 | static struct tsplist *head = &msgslist; | |
| 79 | static struct tsplist *tail = &msgslist; | |
| 80 | static int msgcnt = 0; | |
| 81 | struct tsplist *prev; | |
| 320b887a EN |
82 | struct netinfo *ntp; |
| 83 | struct tsplist *ptr; | |
| 984263bc MD |
84 | ssize_t n; |
| 85 | ||
| 86 | if (trace) { | |
| 87 | fprintf(fd, "readmsg: looking for %s from %s, %s\n", | |
| 88 | tsptype[type], machfrom == NULL ? "ANY" : machfrom, | |
| 89 | netfrom == NULL ? "ANYNET" : inet_ntoa(netfrom->net)); | |
| 90 | if (head->p != 0) { | |
| 91 | length = 1; | |
| 92 | for (ptr = head->p; ptr != 0; ptr = ptr->p) { | |
| 93 | /* do not repeat the hundreds of messages */ | |
| 94 | if (++length > 3) { | |
| 95 | if (ptr == tail) { | |
| 96 | fprintf(fd,"\t ...%d skipped\n", | |
| 97 | length); | |
| 98 | } else { | |
| 99 | continue; | |
| 100 | } | |
| 101 | } | |
| 102 | fprintf(fd, length > 1 ? "\t" : "queue:\t"); | |
| 103 | print(&ptr->info, &ptr->addr); | |
| 104 | } | |
| 105 | } | |
| 106 | } | |
| 107 | ||
| 108 | ptr = head->p; | |
| 109 | prev = head; | |
| 110 | ||
| 111 | /* | |
| 112 | * Look for the requested message scanning through the | |
| 113 | * linked list. If found, return it and free the space | |
| 114 | */ | |
| 115 | ||
| 116 | while (ptr != NULL) { | |
| 117 | if (LOOKAT(ptr->info, type, machfrom, netfrom, ptr->addr)) { | |
| 118 | again: | |
| 119 | msgin = ptr->info; | |
| 120 | from = ptr->addr; | |
| 121 | from_when = ptr->when; | |
| 122 | prev->p = ptr->p; | |
| 123 | if (ptr == tail) | |
| 124 | tail = prev; | |
| 125 | free((char *)ptr); | |
| 126 | fromnet = NULL; | |
| 127 | if (netfrom == NULL) | |
| 128 | for (ntp = nettab; ntp != NULL; ntp = ntp->next) { | |
| 129 | if ((ntp->mask & from.sin_addr.s_addr) == | |
| 130 | ntp->net.s_addr) { | |
| 131 | fromnet = ntp; | |
| 132 | break; | |
| 133 | } | |
| 134 | } | |
| 135 | else | |
| 136 | fromnet = netfrom; | |
| 137 | if (trace) { | |
| 138 | fprintf(fd, "readmsg: found "); | |
| 139 | print(&msgin, &from); | |
| 140 | } | |
| 141 | ||
| 142 | /* The protocol can get far behind. When it does, it gets | |
| 143 | * hopelessly confused. So delete duplicate messages. | |
| 144 | */ | |
| 145 | for (ptr = prev; (ptr = ptr->p) != NULL; prev = ptr) { | |
| 146 | if (ptr->addr.sin_addr.s_addr | |
| 147 | == from.sin_addr.s_addr | |
| 148 | && ptr->info.tsp_type == msgin.tsp_type) { | |
| 149 | if (trace) | |
| 150 | fprintf(fd, "\tdup "); | |
| 151 | goto again; | |
| 152 | } | |
| 153 | } | |
| 154 | msgcnt--; | |
| 155 | return(&msgin); | |
| 156 | } else { | |
| 157 | prev = ptr; | |
| 158 | ptr = ptr->p; | |
| 159 | } | |
| 160 | } | |
| 161 | ||
| 162 | /* | |
| 163 | * If the message was not in the linked list, it may still be | |
| 164 | * coming from the network. Set the timer and wait | |
| 165 | * on a select to read the next incoming message: if it is the | |
| 166 | * right one, return it, otherwise insert it in the linked list. | |
| 167 | */ | |
| 168 | ||
| 37c7aa4c | 169 | gettimeofday(&rtout, 0); |
| 984263bc MD |
170 | timevaladd(&rtout, intvl); |
| 171 | FD_ZERO(&ready); | |
| 172 | for (;;) { | |
| 37c7aa4c | 173 | gettimeofday(&rtime, 0); |
| 984263bc MD |
174 | timevalsub(&rwait, &rtout, &rtime); |
| 175 | if (rwait.tv_sec < 0) | |
| 176 | rwait.tv_sec = rwait.tv_usec = 0; | |
| 177 | else if (rwait.tv_sec == 0 | |
| 178 | && rwait.tv_usec < 1000000/CLK_TCK) | |
| 179 | rwait.tv_usec = 1000000/CLK_TCK; | |
| 180 | ||
| 181 | if (trace) { | |
| 182 | fprintf(fd, "readmsg: wait %ld.%6ld at %s\n", | |
| 183 | rwait.tv_sec, rwait.tv_usec, date()); | |
| 184 | /* Notice a full disk, as we flush trace info. | |
| 185 | * It is better to flush periodically than at | |
| 186 | * every line because the tracing consists of bursts | |
| 187 | * of many lines. Without care, tracing slows | |
| 188 | * down the code enough to break the protocol. | |
| 189 | */ | |
| 190 | if (rwait.tv_sec != 0 | |
| 191 | && EOF == fflush(fd)) | |
| 192 | traceoff("Tracing ended for cause at %s\n"); | |
| 193 | } | |
| 194 | ||
| 195 | FD_SET(sock, &ready); | |
| 60233e58 | 196 | if (!select(sock+1, &ready, NULL, NULL, &rwait)) { |
| 984263bc MD |
197 | if (rwait.tv_sec == 0 && rwait.tv_usec == 0) |
| 198 | return(0); | |
| 199 | continue; | |
| 200 | } | |
| 201 | length = sizeof(from); | |
| 202 | if ((n = recvfrom(sock, (char *)&msgin, sizeof(struct tsp), 0, | |
| 203 | (struct sockaddr*)&from, &length)) < 0) { | |
| 204 | syslog(LOG_ERR, "recvfrom: %m"); | |
| 205 | exit(1); | |
| 206 | } | |
| 207 | /* | |
| 208 | * The 4.3BSD protocol spec had a 32-byte tsp_name field, and | |
| 209 | * this is still OS-dependent. Demand that the packet is at | |
| 210 | * least long enough to hold a 4.3BSD packet. | |
| 211 | */ | |
| 212 | if (n < (ssize_t)(sizeof(struct tsp) - MAXHOSTNAMELEN + 32)) { | |
| 213 | syslog(LOG_NOTICE, | |
| 424e8382 | 214 | "short packet (%zd/%zu bytes) from %s", |
| 984263bc MD |
215 | n, sizeof(struct tsp) - MAXHOSTNAMELEN + 32, |
| 216 | inet_ntoa(from.sin_addr)); | |
| 217 | continue; | |
| 218 | } | |
| 60233e58 | 219 | gettimeofday(&from_when, NULL); |
| 984263bc MD |
220 | bytehostorder(&msgin); |
| 221 | ||
| 222 | if (msgin.tsp_vers > TSPVERSION) { | |
| 223 | if (trace) { | |
| 224 | fprintf(fd,"readmsg: version mismatch\n"); | |
| 225 | /* should do a dump of the packet */ | |
| 226 | } | |
| 227 | continue; | |
| 228 | } | |
| 229 | ||
| 230 | if (memchr(msgin.tsp_name, | |
| 231 | '\0', sizeof msgin.tsp_name) == NULL) { | |
| 232 | syslog(LOG_NOTICE, "hostname field not NUL terminated " | |
| 233 | "in packet from %s", inet_ntoa(from.sin_addr)); | |
| 234 | continue; | |
| 235 | } | |
| 236 | ||
| 237 | fromnet = NULL; | |
| 238 | for (ntp = nettab; ntp != NULL; ntp = ntp->next) | |
| 239 | if ((ntp->mask & from.sin_addr.s_addr) == | |
| 240 | ntp->net.s_addr) { | |
| 241 | fromnet = ntp; | |
| 242 | break; | |
| 243 | } | |
| 244 | ||
| 245 | /* | |
| 246 | * drop packets from nets we are ignoring permanently | |
| 247 | */ | |
| 248 | if (fromnet == NULL) { | |
| 249 | /* | |
| 250 | * The following messages may originate on | |
| 251 | * this host with an ignored network address | |
| 252 | */ | |
| 253 | if (msgin.tsp_type != TSP_TRACEON && | |
| 254 | msgin.tsp_type != TSP_SETDATE && | |
| 255 | msgin.tsp_type != TSP_MSITE && | |
| 256 | msgin.tsp_type != TSP_TEST && | |
| 257 | msgin.tsp_type != TSP_TRACEOFF) { | |
| 258 | if (trace) { | |
| 259 | fprintf(fd,"readmsg: discard null net "); | |
| 260 | print(&msgin, &from); | |
| 261 | } | |
| 262 | continue; | |
| 263 | } | |
| 264 | } | |
| 265 | ||
| 266 | /* | |
| 267 | * Throw away messages coming from this machine, | |
| 268 | * unless they are of some particular type. | |
| 269 | * This gets rid of broadcast messages and reduces | |
| 270 | * master processing time. | |
| 271 | */ | |
| 272 | if (!strcmp(msgin.tsp_name, hostname) | |
| 273 | && msgin.tsp_type != TSP_SETDATE | |
| 274 | && msgin.tsp_type != TSP_TEST | |
| 275 | && msgin.tsp_type != TSP_MSITE | |
| 276 | && msgin.tsp_type != TSP_TRACEON | |
| 277 | && msgin.tsp_type != TSP_TRACEOFF | |
| 278 | && msgin.tsp_type != TSP_LOOP) { | |
| 279 | if (trace) { | |
| 280 | fprintf(fd, "readmsg: discard own "); | |
| 281 | print(&msgin, &from); | |
| 282 | } | |
| 283 | continue; | |
| 284 | } | |
| 285 | ||
| 286 | /* | |
| 287 | * Send acknowledgements here; this is faster and | |
| 288 | * avoids deadlocks that would occur if acks were | |
| 289 | * sent from a higher level routine. Different | |
| 290 | * acknowledgements are necessary, depending on | |
| 291 | * status. | |
| 292 | */ | |
| 293 | if (fromnet == NULL) /* do not de-reference 0 */ | |
| 294 | ignoreack(); | |
| 295 | else if (fromnet->status == MASTER) | |
| 296 | masterack(); | |
| 297 | else if (fromnet->status == SLAVE) | |
| 298 | slaveack(); | |
| 299 | else | |
| 300 | ignoreack(); | |
| 301 | ||
| 302 | if (LOOKAT(msgin, type, machfrom, netfrom, from)) { | |
| 303 | if (trace) { | |
| 304 | fprintf(fd, "readmsg: "); | |
| 305 | print(&msgin, &from); | |
| 306 | } | |
| 307 | return(&msgin); | |
| 308 | } else if (++msgcnt > NHOSTS*3) { | |
| 309 | ||
| 310 | /* The protocol gets hopelessly confused if it gets too far | |
| 311 | * behind. However, it seems able to recover from all cases of lost | |
| 312 | * packets. Therefore, if we are swamped, throw everything away. | |
| 313 | */ | |
| 314 | if (trace) | |
| 315 | fprintf(fd, | |
| 316 | "readmsg: discarding %d msgs\n", | |
| 317 | msgcnt); | |
| 318 | msgcnt = 0; | |
| 319 | while ((ptr=head->p) != NULL) { | |
| 320 | head->p = ptr->p; | |
| 321 | free((char *)ptr); | |
| 322 | } | |
| 323 | tail = head; | |
| 324 | } else { | |
| 325 | tail->p = (struct tsplist *) | |
| 326 | malloc(sizeof(struct tsplist)); | |
| 327 | tail = tail->p; | |
| 328 | tail->p = NULL; | |
| 329 | tail->info = msgin; | |
| 330 | tail->addr = from; | |
| 331 | /* timestamp msgs so SETTIMEs are correct */ | |
| 332 | tail->when = from_when; | |
| 333 | } | |
| 334 | } | |
| 335 | } | |
| 336 | ||
| 337 | /* | |
| 338 | * Send the necessary acknowledgements: | |
| 339 | * only the type ACK is to be sent by a slave | |
| 340 | */ | |
| 341 | void | |
| 320b887a | 342 | slaveack(void) |
| 984263bc | 343 | { |
| 320b887a | 344 | |
| 984263bc MD |
345 | switch(msgin.tsp_type) { |
| 346 | ||
| 347 | case TSP_ADJTIME: | |
| 348 | case TSP_SETTIME: | |
| 349 | case TSP_ACCEPT: | |
| 350 | case TSP_REFUSE: | |
| 351 | case TSP_TRACEON: | |
| 352 | case TSP_TRACEOFF: | |
| 353 | case TSP_QUIT: | |
| 354 | if (trace) { | |
| 355 | fprintf(fd, "Slaveack: "); | |
| 356 | print(&msgin, &from); | |
| 357 | } | |
| 358 | xmit(TSP_ACK,msgin.tsp_seq, &from); | |
| 359 | break; | |
| 360 | ||
| 361 | default: | |
| 362 | if (trace) { | |
| 363 | fprintf(fd, "Slaveack: no ack: "); | |
| 364 | print(&msgin, &from); | |
| 365 | } | |
| 366 | break; | |
| 367 | } | |
| 368 | } | |
| 369 | ||
| 370 | /* | |
| 371 | * Certain packets may arrive from this machine on ignored networks. | |
| 372 | * These packets should be acknowledged. | |
| 373 | */ | |
| 374 | void | |
| 320b887a | 375 | ignoreack(void) |
| 984263bc | 376 | { |
| 320b887a | 377 | |
| 984263bc MD |
378 | switch(msgin.tsp_type) { |
| 379 | ||
| 380 | case TSP_TRACEON: | |
| 381 | case TSP_TRACEOFF: | |
| 382 | case TSP_QUIT: | |
| 383 | if (trace) { | |
| 384 | fprintf(fd, "Ignoreack: "); | |
| 385 | print(&msgin, &from); | |
| 386 | } | |
| 387 | xmit(TSP_ACK,msgin.tsp_seq, &from); | |
| 388 | break; | |
| 389 | ||
| 390 | default: | |
| 391 | if (trace) { | |
| 392 | fprintf(fd, "Ignoreack: no ack: "); | |
| 393 | print(&msgin, &from); | |
| 394 | } | |
| 395 | break; | |
| 396 | } | |
| 397 | } | |
| 398 | ||
| 399 | /* | |
| 400 | * `masterack' sends the necessary acknowledgments | |
| 401 | * to the messages received by a master | |
| 402 | */ | |
| 403 | void | |
| 320b887a | 404 | masterack(void) |
| 984263bc MD |
405 | { |
| 406 | struct tsp resp; | |
| 407 | ||
| 408 | resp = msgin; | |
| 409 | resp.tsp_vers = TSPVERSION; | |
| 372138d3 | 410 | strlcpy(resp.tsp_name, hostname, sizeof(resp.tsp_name)); |
| 984263bc MD |
411 | |
| 412 | switch(msgin.tsp_type) { | |
| 413 | ||
| 414 | case TSP_QUIT: | |
| 415 | case TSP_TRACEON: | |
| 416 | case TSP_TRACEOFF: | |
| 417 | case TSP_MSITEREQ: | |
| 418 | if (trace) { | |
| 419 | fprintf(fd, "Masterack: "); | |
| 420 | print(&msgin, &from); | |
| 421 | } | |
| 422 | xmit(TSP_ACK,msgin.tsp_seq, &from); | |
| 423 | break; | |
| 424 | ||
| 425 | case TSP_RESOLVE: | |
| 426 | case TSP_MASTERREQ: | |
| 427 | if (trace) { | |
| 428 | fprintf(fd, "Masterack: "); | |
| 429 | print(&msgin, &from); | |
| 430 | } | |
| 431 | xmit(TSP_MASTERACK,msgin.tsp_seq, &from); | |
| 432 | break; | |
| 433 | ||
| 434 | default: | |
| 435 | if (trace) { | |
| 436 | fprintf(fd,"Masterack: no ack: "); | |
| 437 | print(&msgin, &from); | |
| 438 | } | |
| 439 | break; | |
| 440 | } | |
| 441 | } | |
| 442 | ||
| 443 | /* | |
| 444 | * Print a TSP message | |
| 445 | */ | |
| 446 | void | |
| 320b887a | 447 | print(struct tsp *msg, struct sockaddr_in *addr) |
| 984263bc MD |
448 | { |
| 449 | char tm[26]; | |
| 450 | time_t tsp_time_sec; | |
| 451 | ||
| 452 | if (msg->tsp_type >= TSPTYPENUMBER) { | |
| 453 | fprintf(fd, "bad type (%u) on packet from %s\n", | |
| 454 | msg->tsp_type, inet_ntoa(addr->sin_addr)); | |
| 455 | return; | |
| 456 | } | |
| 457 | ||
| 458 | switch (msg->tsp_type) { | |
| 459 | ||
| 460 | case TSP_LOOP: | |
| 461 | fprintf(fd, "%s %d %-6u #%d %-15s %s\n", | |
| 462 | tsptype[msg->tsp_type], | |
| 463 | msg->tsp_vers, | |
| 464 | msg->tsp_seq, | |
| 465 | msg->tsp_hopcnt, | |
| 466 | inet_ntoa(addr->sin_addr), | |
| 467 | msg->tsp_name); | |
| 468 | break; | |
| 469 | ||
| 470 | case TSP_SETTIME: | |
| 471 | case TSP_SETDATE: | |
| 472 | case TSP_SETDATEREQ: | |
| 984263bc | 473 | tsp_time_sec = msg->tsp_time.tv_sec; |
| 372138d3 | 474 | strlcpy(tm, ctime(&tsp_time_sec)+3+1, sizeof(tm)); |
| 984263bc MD |
475 | fprintf(fd, "%s %d %-6u %s %-15s %s\n", |
| 476 | tsptype[msg->tsp_type], | |
| 477 | msg->tsp_vers, | |
| 478 | msg->tsp_seq, | |
| 479 | tm, | |
| 480 | inet_ntoa(addr->sin_addr), | |
| 481 | msg->tsp_name); | |
| 482 | break; | |
| 483 | ||
| 484 | case TSP_ADJTIME: | |
| 485 | fprintf(fd, "%s %d %-6u (%ld,%ld) %-15s %s\n", | |
| 486 | tsptype[msg->tsp_type], | |
| 487 | msg->tsp_vers, | |
| 488 | msg->tsp_seq, | |
| 489 | msg->tsp_time.tv_sec, | |
| 490 | msg->tsp_time.tv_usec, | |
| 491 | inet_ntoa(addr->sin_addr), | |
| 492 | msg->tsp_name); | |
| 493 | break; | |
| 494 | ||
| 495 | default: | |
| 496 | fprintf(fd, "%s %d %-6u %-15s %s\n", | |
| 497 | tsptype[msg->tsp_type], | |
| 498 | msg->tsp_vers, | |
| 499 | msg->tsp_seq, | |
| 500 | inet_ntoa(addr->sin_addr), | |
| 501 | msg->tsp_name); | |
| 502 | break; | |
| 503 | } | |
| 504 | } |