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.6 2004/09/05 02:20:15 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(int type
, char *machfrom
, struct timeval
*intvl
,
74 struct netinfo
*netfrom
)
78 static struct tsplist
*head
= &msgslist
;
79 static struct tsplist
*tail
= &msgslist
;
80 static int msgcnt
= 0;
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
));
92 for (ptr
= head
->p
; ptr
!= 0; ptr
= ptr
->p
) {
93 /* do not repeat the hundreds of messages */
96 fprintf(fd
,"\t ...%d skipped\n",
102 fprintf(fd
, length
> 1 ? "\t" : "queue:\t");
103 print(&ptr
->info
, &ptr
->addr
);
112 * Look for the requested message scanning through the
113 * linked list. If found, return it and free the space
116 while (ptr
!= NULL
) {
117 if (LOOKAT(ptr
->info
, type
, machfrom
, netfrom
, ptr
->addr
)) {
121 from_when
= ptr
->when
;
128 for (ntp
= nettab
; ntp
!= NULL
; ntp
= ntp
->next
) {
129 if ((ntp
->mask
& from
.sin_addr
.s_addr
) ==
138 fprintf(fd
, "readmsg: found ");
139 print(&msgin
, &from
);
142 /* The protocol can get far behind. When it does, it gets
143 * hopelessly confused. So delete duplicate messages.
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
) {
150 fprintf(fd
, "\tdup ");
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.
169 gettimeofday(&rtout
, 0);
170 timevaladd(&rtout
, intvl
);
173 gettimeofday(&rtime
, 0);
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
;
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.
190 if (rwait
.tv_sec
!= 0
191 && EOF
== fflush(fd
))
192 traceoff("Tracing ended for cause at %s\n");
195 FD_SET(sock
, &ready
);
196 if (!select(sock
+1, &ready
, NULL
, NULL
, &rwait
)) {
197 if (rwait
.tv_sec
== 0 && rwait
.tv_usec
== 0)
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");
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.
212 if (n
< (ssize_t
)(sizeof(struct tsp
) - MAXHOSTNAMELEN
+ 32)) {
214 "short packet (%zd/%zu bytes) from %s",
215 n
, sizeof(struct tsp
) - MAXHOSTNAMELEN
+ 32,
216 inet_ntoa(from
.sin_addr
));
219 gettimeofday(&from_when
, NULL
);
220 bytehostorder(&msgin
);
222 if (msgin
.tsp_vers
> TSPVERSION
) {
224 fprintf(fd
,"readmsg: version mismatch\n");
225 /* should do a dump of the packet */
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
));
238 for (ntp
= nettab
; ntp
!= NULL
; ntp
= ntp
->next
)
239 if ((ntp
->mask
& from
.sin_addr
.s_addr
) ==
246 * drop packets from nets we are ignoring permanently
248 if (fromnet
== NULL
) {
250 * The following messages may originate on
251 * this host with an ignored network address
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
) {
259 fprintf(fd
,"readmsg: discard null net ");
260 print(&msgin
, &from
);
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.
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
) {
280 fprintf(fd
, "readmsg: discard own ");
281 print(&msgin
, &from
);
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
293 if (fromnet
== NULL
) /* do not de-reference 0 */
295 else if (fromnet
->status
== MASTER
)
297 else if (fromnet
->status
== SLAVE
)
302 if (LOOKAT(msgin
, type
, machfrom
, netfrom
, from
)) {
304 fprintf(fd
, "readmsg: ");
305 print(&msgin
, &from
);
308 } else if (++msgcnt
> NHOSTS
*3) {
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.
316 "readmsg: discarding %d msgs\n",
319 while ((ptr
=head
->p
) != NULL
) {
325 tail
->p
= (struct tsplist
*)
326 malloc(sizeof(struct tsplist
));
331 /* timestamp msgs so SETTIMEs are correct */
332 tail
->when
= from_when
;
338 * Send the necessary acknowledgements:
339 * only the type ACK is to be sent by a slave
345 switch(msgin
.tsp_type
) {
355 fprintf(fd
, "Slaveack: ");
356 print(&msgin
, &from
);
358 xmit(TSP_ACK
,msgin
.tsp_seq
, &from
);
363 fprintf(fd
, "Slaveack: no ack: ");
364 print(&msgin
, &from
);
371 * Certain packets may arrive from this machine on ignored networks.
372 * These packets should be acknowledged.
378 switch(msgin
.tsp_type
) {
384 fprintf(fd
, "Ignoreack: ");
385 print(&msgin
, &from
);
387 xmit(TSP_ACK
,msgin
.tsp_seq
, &from
);
392 fprintf(fd
, "Ignoreack: no ack: ");
393 print(&msgin
, &from
);
400 * `masterack' sends the necessary acknowledgments
401 * to the messages received by a master
409 resp
.tsp_vers
= TSPVERSION
;
410 strlcpy(resp
.tsp_name
, hostname
, sizeof(resp
.tsp_name
));
412 switch(msgin
.tsp_type
) {
419 fprintf(fd
, "Masterack: ");
420 print(&msgin
, &from
);
422 xmit(TSP_ACK
,msgin
.tsp_seq
, &from
);
428 fprintf(fd
, "Masterack: ");
429 print(&msgin
, &from
);
431 xmit(TSP_MASTERACK
,msgin
.tsp_seq
, &from
);
436 fprintf(fd
,"Masterack: no ack: ");
437 print(&msgin
, &from
);
444 * Print a TSP message
447 print(struct tsp
*msg
, struct sockaddr_in
*addr
)
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
));
458 switch (msg
->tsp_type
) {
461 fprintf(fd
, "%s %d %-6u #%d %-15s %s\n",
462 tsptype
[msg
->tsp_type
],
466 inet_ntoa(addr
->sin_addr
),
473 tsp_time_sec
= msg
->tsp_time
.tv_sec
;
474 strlcpy(tm
, ctime(&tsp_time_sec
)+3+1, sizeof(tm
));
475 fprintf(fd
, "%s %d %-6u %s %-15s %s\n",
476 tsptype
[msg
->tsp_type
],
480 inet_ntoa(addr
->sin_addr
),
485 fprintf(fd
, "%s %d %-6u (%ld,%ld) %-15s %s\n",
486 tsptype
[msg
->tsp_type
],
489 msg
->tsp_time
.tv_sec
,
490 msg
->tsp_time
.tv_usec
,
491 inet_ntoa(addr
->sin_addr
),
496 fprintf(fd
, "%s %d %-6u %-15s %s\n",
497 tsptype
[msg
->tsp_type
],
500 inet_ntoa(addr
->sin_addr
),