Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / usr.sbin / timed / timed / readmsg.c
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.
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 $
35  * $DragonFly: src/usr.sbin/timed/timed/readmsg.c,v 1.2 2003/06/17 04:30:03 dillon Exp $
36  */
37
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 *
73 readmsg(type, machfrom, intvl, netfrom)
74         int type;
75         char *machfrom;
76         struct timeval *intvl;
77         struct netinfo *netfrom;
78 {
79         int length;
80         fd_set ready;
81         static struct tsplist *head = &msgslist;
82         static struct tsplist *tail = &msgslist;
83         static int msgcnt = 0;
84         struct tsplist *prev;
85         register struct netinfo *ntp;
86         register struct tsplist *ptr;
87         ssize_t n;
88
89         if (trace) {
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));
93                 if (head->p != 0) {
94                         length = 1;
95                         for (ptr = head->p; ptr != 0; ptr = ptr->p) {
96                                 /* do not repeat the hundreds of messages */
97                                 if (++length > 3) {
98                                         if (ptr == tail) {
99                                                 fprintf(fd,"\t ...%d skipped\n",
100                                                         length);
101                                         } else {
102                                                 continue;
103                                         }
104                                 }
105                                 fprintf(fd, length > 1 ? "\t" : "queue:\t");
106                                 print(&ptr->info, &ptr->addr);
107                         }
108                 }
109         }
110
111         ptr = head->p;
112         prev = head;
113
114         /*
115          * Look for the requested message scanning through the
116          * linked list. If found, return it and free the space
117          */
118
119         while (ptr != NULL) {
120                 if (LOOKAT(ptr->info, type, machfrom, netfrom, ptr->addr)) {
121 again:
122                         msgin = ptr->info;
123                         from = ptr->addr;
124                         from_when = ptr->when;
125                         prev->p = ptr->p;
126                         if (ptr == tail)
127                                 tail = prev;
128                         free((char *)ptr);
129                         fromnet = NULL;
130                         if (netfrom == NULL)
131                             for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
132                                     if ((ntp->mask & from.sin_addr.s_addr) ==
133                                         ntp->net.s_addr) {
134                                             fromnet = ntp;
135                                             break;
136                                     }
137                             }
138                         else
139                             fromnet = netfrom;
140                         if (trace) {
141                                 fprintf(fd, "readmsg: found ");
142                                 print(&msgin, &from);
143                         }
144
145 /* The protocol can get far behind.  When it does, it gets
146  *      hopelessly confused.  So delete duplicate messages.
147  */
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) {
152                                         if (trace)
153                                                 fprintf(fd, "\tdup ");
154                                         goto again;
155                                 }
156                         }
157                         msgcnt--;
158                         return(&msgin);
159                 } else {
160                         prev = ptr;
161                         ptr = ptr->p;
162                 }
163         }
164
165         /*
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.
170          */
171
172         (void)gettimeofday(&rtout, 0);
173         timevaladd(&rtout, intvl);
174         FD_ZERO(&ready);
175         for (;;) {
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;
183
184                 if (trace) {
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.
192                          */
193                         if (rwait.tv_sec != 0
194                             && EOF == fflush(fd))
195                                 traceoff("Tracing ended for cause at %s\n");
196                 }
197
198                 FD_SET(sock, &ready);
199                 if (!select(sock+1, &ready, (fd_set *)0, (fd_set *)0,
200                            &rwait)) {
201                         if (rwait.tv_sec == 0 && rwait.tv_usec == 0)
202                                 return(0);
203                         continue;
204                 }
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");
209                         exit(1);
210                 }
211                 /*
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.
215                  */
216                 if (n < (ssize_t)(sizeof(struct tsp) - MAXHOSTNAMELEN + 32)) {
217                         syslog(LOG_NOTICE,
218                             "short packet (%u/%u bytes) from %s",
219                               n, sizeof(struct tsp) - MAXHOSTNAMELEN + 32,
220                               inet_ntoa(from.sin_addr));
221                         continue;
222                 }
223                 (void)gettimeofday(&from_when, (struct timezone *)0);
224                 bytehostorder(&msgin);
225
226                 if (msgin.tsp_vers > TSPVERSION) {
227                         if (trace) {
228                             fprintf(fd,"readmsg: version mismatch\n");
229                             /* should do a dump of the packet */
230                         }
231                         continue;
232                 }
233
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));
238                         continue;
239                 }
240
241                 fromnet = NULL;
242                 for (ntp = nettab; ntp != NULL; ntp = ntp->next)
243                         if ((ntp->mask & from.sin_addr.s_addr) ==
244                             ntp->net.s_addr) {
245                                 fromnet = ntp;
246                                 break;
247                         }
248
249                 /*
250                  * drop packets from nets we are ignoring permanently
251                  */
252                 if (fromnet == NULL) {
253                         /*
254                          * The following messages may originate on
255                          * this host with an ignored network address
256                          */
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) {
262                                 if (trace) {
263                                     fprintf(fd,"readmsg: discard null net ");
264                                     print(&msgin, &from);
265                                 }
266                                 continue;
267                         }
268                 }
269
270                 /*
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.
275                  */
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) {
283                         if (trace) {
284                                 fprintf(fd, "readmsg: discard own ");
285                                 print(&msgin, &from);
286                         }
287                         continue;
288                 }
289
290                 /*
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
295                  * status.
296                  */
297                 if (fromnet == NULL)    /* do not de-reference 0 */
298                         ignoreack();
299                 else if (fromnet->status == MASTER)
300                         masterack();
301                 else if (fromnet->status == SLAVE)
302                         slaveack();
303                 else
304                         ignoreack();
305
306                 if (LOOKAT(msgin, type, machfrom, netfrom, from)) {
307                         if (trace) {
308                                 fprintf(fd, "readmsg: ");
309                                 print(&msgin, &from);
310                         }
311                         return(&msgin);
312                 } else if (++msgcnt > NHOSTS*3) {
313
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.
317 */
318                         if (trace)
319                                 fprintf(fd,
320                                         "readmsg: discarding %d msgs\n",
321                                         msgcnt);
322                         msgcnt = 0;
323                         while ((ptr=head->p) != NULL) {
324                                 head->p = ptr->p;
325                                 free((char *)ptr);
326                         }
327                         tail = head;
328                 } else {
329                         tail->p = (struct tsplist *)
330                                     malloc(sizeof(struct tsplist));
331                         tail = tail->p;
332                         tail->p = NULL;
333                         tail->info = msgin;
334                         tail->addr = from;
335                         /* timestamp msgs so SETTIMEs are correct */
336                         tail->when = from_when;
337                 }
338         }
339 }
340
341 /*
342  * Send the necessary acknowledgements:
343  * only the type ACK is to be sent by a slave
344  */
345 void
346 slaveack()
347 {
348         switch(msgin.tsp_type) {
349
350         case TSP_ADJTIME:
351         case TSP_SETTIME:
352         case TSP_ACCEPT:
353         case TSP_REFUSE:
354         case TSP_TRACEON:
355         case TSP_TRACEOFF:
356         case TSP_QUIT:
357                 if (trace) {
358                         fprintf(fd, "Slaveack: ");
359                         print(&msgin, &from);
360                 }
361                 xmit(TSP_ACK,msgin.tsp_seq, &from);
362                 break;
363
364         default:
365                 if (trace) {
366                         fprintf(fd, "Slaveack: no ack: ");
367                         print(&msgin, &from);
368                 }
369                 break;
370         }
371 }
372
373 /*
374  * Certain packets may arrive from this machine on ignored networks.
375  * These packets should be acknowledged.
376  */
377 void
378 ignoreack()
379 {
380         switch(msgin.tsp_type) {
381
382         case TSP_TRACEON:
383         case TSP_TRACEOFF:
384         case TSP_QUIT:
385                 if (trace) {
386                         fprintf(fd, "Ignoreack: ");
387                         print(&msgin, &from);
388                 }
389                 xmit(TSP_ACK,msgin.tsp_seq, &from);
390                 break;
391
392         default:
393                 if (trace) {
394                         fprintf(fd, "Ignoreack: no ack: ");
395                         print(&msgin, &from);
396                 }
397                 break;
398         }
399 }
400
401 /*
402  * `masterack' sends the necessary acknowledgments
403  * to the messages received by a master
404  */
405 void
406 masterack()
407 {
408         struct tsp resp;
409
410         resp = msgin;
411         resp.tsp_vers = TSPVERSION;
412         (void)strcpy(resp.tsp_name, hostname);
413
414         switch(msgin.tsp_type) {
415
416         case TSP_QUIT:
417         case TSP_TRACEON:
418         case TSP_TRACEOFF:
419         case TSP_MSITEREQ:
420                 if (trace) {
421                         fprintf(fd, "Masterack: ");
422                         print(&msgin, &from);
423                 }
424                 xmit(TSP_ACK,msgin.tsp_seq, &from);
425                 break;
426
427         case TSP_RESOLVE:
428         case TSP_MASTERREQ:
429                 if (trace) {
430                         fprintf(fd, "Masterack: ");
431                         print(&msgin, &from);
432                 }
433                 xmit(TSP_MASTERACK,msgin.tsp_seq, &from);
434                 break;
435
436         default:
437                 if (trace) {
438                         fprintf(fd,"Masterack: no ack: ");
439                         print(&msgin, &from);
440                 }
441                 break;
442         }
443 }
444
445 /*
446  * Print a TSP message
447  */
448 void
449 print(msg, addr)
450         struct tsp *msg;
451         struct sockaddr_in *addr;
452 {
453         char tm[26];
454         time_t tsp_time_sec;
455
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));
459                 return;
460         }
461
462         switch (msg->tsp_type) {
463
464         case TSP_LOOP:
465                 fprintf(fd, "%s %d %-6u #%d %-15s %s\n",
466                         tsptype[msg->tsp_type],
467                         msg->tsp_vers,
468                         msg->tsp_seq,
469                         msg->tsp_hopcnt,
470                         inet_ntoa(addr->sin_addr),
471                         msg->tsp_name);
472                 break;
473
474         case TSP_SETTIME:
475         case TSP_SETDATE:
476         case TSP_SETDATEREQ:
477 #ifdef sgi
478                 (void)cftime(tm, "%D %T", &msg->tsp_time.tv_sec);
479 #else
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 */
483 #endif /* sgi */
484                 fprintf(fd, "%s %d %-6u %s %-15s %s\n",
485                         tsptype[msg->tsp_type],
486                         msg->tsp_vers,
487                         msg->tsp_seq,
488                         tm,
489                         inet_ntoa(addr->sin_addr),
490                         msg->tsp_name);
491                 break;
492
493         case TSP_ADJTIME:
494                 fprintf(fd, "%s %d %-6u (%ld,%ld) %-15s %s\n",
495                         tsptype[msg->tsp_type],
496                         msg->tsp_vers,
497                         msg->tsp_seq,
498                         msg->tsp_time.tv_sec,
499                         msg->tsp_time.tv_usec,
500                         inet_ntoa(addr->sin_addr),
501                         msg->tsp_name);
502                 break;
503
504         default:
505                 fprintf(fd, "%s %d %-6u %-15s %s\n",
506                         tsptype[msg->tsp_type],
507                         msg->tsp_vers,
508                         msg->tsp_seq,
509                         inet_ntoa(addr->sin_addr),
510                         msg->tsp_name);
511                 break;
512         }
513 }