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