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