2 * Copyright (c) 1985, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
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 $
35 * $DragonFly: src/usr.sbin/timed/timed/readmsg.c,v 1.2 2003/06/17 04:30:03 dillon Exp $
40 extern char *tsptype[];
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
46 #define LOOKAT(msg, mtype, mfrom, netp, froms) \
47 (((mtype) == TSP_ANY || (mtype) == (msg).tsp_type) && \
48 ((mfrom) == 0 || !strcmp((mfrom), (msg).tsp_name)) && \
50 ((netp)->mask & (froms).sin_addr.s_addr) == (netp)->net.s_addr))
52 struct timeval rtime, rwait, rtout;
54 static struct tsplist {
57 struct sockaddr_in addr;
60 struct sockaddr_in from;
61 struct netinfo *fromnet;
62 struct timeval from_when;
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.
73 readmsg(type, machfrom, intvl, netfrom)
76 struct timeval *intvl;
77 struct netinfo *netfrom;
81 static struct tsplist *head = &msgslist;
82 static struct tsplist *tail = &msgslist;
83 static int msgcnt = 0;
85 register struct netinfo *ntp;
86 register struct tsplist *ptr;
90 fprintf(fd, "readmsg: looking for %s from %s, %s\n",
91 tsptype[type], machfrom == NULL ? "ANY" : machfrom,
92 netfrom == NULL ? "ANYNET" : inet_ntoa(netfrom->net));
95 for (ptr = head->p; ptr != 0; ptr = ptr->p) {
96 /* do not repeat the hundreds of messages */
99 fprintf(fd,"\t ...%d skipped\n",
105 fprintf(fd, length > 1 ? "\t" : "queue:\t");
106 print(&ptr->info, &ptr->addr);
115 * Look for the requested message scanning through the
116 * linked list. If found, return it and free the space
119 while (ptr != NULL) {
120 if (LOOKAT(ptr->info, type, machfrom, netfrom, ptr->addr)) {
124 from_when = ptr->when;
131 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
132 if ((ntp->mask & from.sin_addr.s_addr) ==
141 fprintf(fd, "readmsg: found ");
142 print(&msgin, &from);
145 /* The protocol can get far behind. When it does, it gets
146 * hopelessly confused. So delete duplicate messages.
148 for (ptr = prev; (ptr = ptr->p) != NULL; prev = ptr) {
149 if (ptr->addr.sin_addr.s_addr
150 == from.sin_addr.s_addr
151 && ptr->info.tsp_type == msgin.tsp_type) {
153 fprintf(fd, "\tdup ");
166 * If the message was not in the linked list, it may still be
167 * coming from the network. Set the timer and wait
168 * on a select to read the next incoming message: if it is the
169 * right one, return it, otherwise insert it in the linked list.
172 (void)gettimeofday(&rtout, 0);
173 timevaladd(&rtout, intvl);
176 (void)gettimeofday(&rtime, 0);
177 timevalsub(&rwait, &rtout, &rtime);
178 if (rwait.tv_sec < 0)
179 rwait.tv_sec = rwait.tv_usec = 0;
180 else if (rwait.tv_sec == 0
181 && rwait.tv_usec < 1000000/CLK_TCK)
182 rwait.tv_usec = 1000000/CLK_TCK;
185 fprintf(fd, "readmsg: wait %ld.%6ld at %s\n",
186 rwait.tv_sec, rwait.tv_usec, date());
187 /* Notice a full disk, as we flush trace info.
188 * It is better to flush periodically than at
189 * every line because the tracing consists of bursts
190 * of many lines. Without care, tracing slows
191 * down the code enough to break the protocol.
193 if (rwait.tv_sec != 0
194 && EOF == fflush(fd))
195 traceoff("Tracing ended for cause at %s\n");
198 FD_SET(sock, &ready);
199 if (!select(sock+1, &ready, (fd_set *)0, (fd_set *)0,
201 if (rwait.tv_sec == 0 && rwait.tv_usec == 0)
205 length = sizeof(from);
206 if ((n = recvfrom(sock, (char *)&msgin, sizeof(struct tsp), 0,
207 (struct sockaddr*)&from, &length)) < 0) {
208 syslog(LOG_ERR, "recvfrom: %m");
212 * The 4.3BSD protocol spec had a 32-byte tsp_name field, and
213 * this is still OS-dependent. Demand that the packet is at
214 * least long enough to hold a 4.3BSD packet.
216 if (n < (ssize_t)(sizeof(struct tsp) - MAXHOSTNAMELEN + 32)) {
218 "short packet (%u/%u bytes) from %s",
219 n, sizeof(struct tsp) - MAXHOSTNAMELEN + 32,
220 inet_ntoa(from.sin_addr));
223 (void)gettimeofday(&from_when, (struct timezone *)0);
224 bytehostorder(&msgin);
226 if (msgin.tsp_vers > TSPVERSION) {
228 fprintf(fd,"readmsg: version mismatch\n");
229 /* should do a dump of the packet */
234 if (memchr(msgin.tsp_name,
235 '\0', sizeof msgin.tsp_name) == NULL) {
236 syslog(LOG_NOTICE, "hostname field not NUL terminated "
237 "in packet from %s", inet_ntoa(from.sin_addr));
242 for (ntp = nettab; ntp != NULL; ntp = ntp->next)
243 if ((ntp->mask & from.sin_addr.s_addr) ==
250 * drop packets from nets we are ignoring permanently
252 if (fromnet == NULL) {
254 * The following messages may originate on
255 * this host with an ignored network address
257 if (msgin.tsp_type != TSP_TRACEON &&
258 msgin.tsp_type != TSP_SETDATE &&
259 msgin.tsp_type != TSP_MSITE &&
260 msgin.tsp_type != TSP_TEST &&
261 msgin.tsp_type != TSP_TRACEOFF) {
263 fprintf(fd,"readmsg: discard null net ");
264 print(&msgin, &from);
271 * Throw away messages coming from this machine,
272 * unless they are of some particular type.
273 * This gets rid of broadcast messages and reduces
274 * master processing time.
276 if (!strcmp(msgin.tsp_name, hostname)
277 && msgin.tsp_type != TSP_SETDATE
278 && msgin.tsp_type != TSP_TEST
279 && msgin.tsp_type != TSP_MSITE
280 && msgin.tsp_type != TSP_TRACEON
281 && msgin.tsp_type != TSP_TRACEOFF
282 && msgin.tsp_type != TSP_LOOP) {
284 fprintf(fd, "readmsg: discard own ");
285 print(&msgin, &from);
291 * Send acknowledgements here; this is faster and
292 * avoids deadlocks that would occur if acks were
293 * sent from a higher level routine. Different
294 * acknowledgements are necessary, depending on
297 if (fromnet == NULL) /* do not de-reference 0 */
299 else if (fromnet->status == MASTER)
301 else if (fromnet->status == SLAVE)
306 if (LOOKAT(msgin, type, machfrom, netfrom, from)) {
308 fprintf(fd, "readmsg: ");
309 print(&msgin, &from);
312 } else if (++msgcnt > NHOSTS*3) {
314 /* The protocol gets hopelessly confused if it gets too far
315 * behind. However, it seems able to recover from all cases of lost
316 * packets. Therefore, if we are swamped, throw everything away.
320 "readmsg: discarding %d msgs\n",
323 while ((ptr=head->p) != NULL) {
329 tail->p = (struct tsplist *)
330 malloc(sizeof(struct tsplist));
335 /* timestamp msgs so SETTIMEs are correct */
336 tail->when = from_when;
342 * Send the necessary acknowledgements:
343 * only the type ACK is to be sent by a slave
348 switch(msgin.tsp_type) {
358 fprintf(fd, "Slaveack: ");
359 print(&msgin, &from);
361 xmit(TSP_ACK,msgin.tsp_seq, &from);
366 fprintf(fd, "Slaveack: no ack: ");
367 print(&msgin, &from);
374 * Certain packets may arrive from this machine on ignored networks.
375 * These packets should be acknowledged.
380 switch(msgin.tsp_type) {
386 fprintf(fd, "Ignoreack: ");
387 print(&msgin, &from);
389 xmit(TSP_ACK,msgin.tsp_seq, &from);
394 fprintf(fd, "Ignoreack: no ack: ");
395 print(&msgin, &from);
402 * `masterack' sends the necessary acknowledgments
403 * to the messages received by a master
411 resp.tsp_vers = TSPVERSION;
412 (void)strcpy(resp.tsp_name, hostname);
414 switch(msgin.tsp_type) {
421 fprintf(fd, "Masterack: ");
422 print(&msgin, &from);
424 xmit(TSP_ACK,msgin.tsp_seq, &from);
430 fprintf(fd, "Masterack: ");
431 print(&msgin, &from);
433 xmit(TSP_MASTERACK,msgin.tsp_seq, &from);
438 fprintf(fd,"Masterack: no ack: ");
439 print(&msgin, &from);
446 * Print a TSP message
451 struct sockaddr_in *addr;
456 if (msg->tsp_type >= TSPTYPENUMBER) {
457 fprintf(fd, "bad type (%u) on packet from %s\n",
458 msg->tsp_type, inet_ntoa(addr->sin_addr));
462 switch (msg->tsp_type) {
465 fprintf(fd, "%s %d %-6u #%d %-15s %s\n",
466 tsptype[msg->tsp_type],
470 inet_ntoa(addr->sin_addr),
478 (void)cftime(tm, "%D %T", &msg->tsp_time.tv_sec);
480 tsp_time_sec = msg->tsp_time.tv_sec;
481 strncpy(tm, ctime(&tsp_time_sec)+3+1, sizeof(tm));
482 tm[15] = '\0'; /* ugh */
484 fprintf(fd, "%s %d %-6u %s %-15s %s\n",
485 tsptype[msg->tsp_type],
489 inet_ntoa(addr->sin_addr),
494 fprintf(fd, "%s %d %-6u (%ld,%ld) %-15s %s\n",
495 tsptype[msg->tsp_type],
498 msg->tsp_time.tv_sec,
499 msg->tsp_time.tv_usec,
500 inet_ntoa(addr->sin_addr),
505 fprintf(fd, "%s %d %-6u %-15s %s\n",
506 tsptype[msg->tsp_type],
509 inet_ntoa(addr->sin_addr),