]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - usr.sbin/timed/timed/readmsg.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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
34 #ifndef lint
35 #if 0
36 static char sccsid[] = "@(#)readmsg.c   8.1 (Berkeley) 6/6/93";
37 #endif
38 static const char rcsid[] =
39   "$FreeBSD$";
40 #endif /* not lint */
41
42 #include "globals.h"
43
44 extern char *tsptype[];
45
46 /*
47  * LOOKAT checks if the message is of the requested type and comes from
48  * the right machine, returning 1 in case of affirmative answer
49  */
50 #define LOOKAT(msg, mtype, mfrom, netp, froms) \
51         (((mtype) == TSP_ANY || (mtype) == (msg).tsp_type) &&           \
52          ((mfrom) == 0 || !strcmp((mfrom), (msg).tsp_name)) &&          \
53          ((netp) == 0 ||                                                \
54           ((netp)->mask & (froms).sin_addr.s_addr) == (netp)->net.s_addr))
55
56 struct timeval rtime, rwait, rtout;
57 struct tsp msgin;
58 static struct tsplist {
59         struct tsp info;
60         struct timeval when;
61         struct sockaddr_in addr;
62         struct tsplist *p;
63 } msgslist;
64 struct sockaddr_in from;
65 struct netinfo *fromnet;
66 struct timeval from_when;
67
68 /*
69  * `readmsg' returns message `type' sent by `machfrom' if it finds it
70  * either in the receive queue, or in a linked list of previously received
71  * messages that it maintains.
72  * Otherwise it waits to see if the appropriate message arrives within
73  * `intvl' seconds. If not, it returns NULL.
74  */
75
76 struct tsp *
77 readmsg(type, machfrom, intvl, netfrom)
78         int type;
79         char *machfrom;
80         struct timeval *intvl;
81         struct netinfo *netfrom;
82 {
83         int length;
84         fd_set ready;
85         static struct tsplist *head = &msgslist;
86         static struct tsplist *tail = &msgslist;
87         static int msgcnt = 0;
88         struct tsplist *prev;
89         register struct netinfo *ntp;
90         register struct tsplist *ptr;
91         ssize_t n;
92
93         if (trace) {
94                 fprintf(fd, "readmsg: looking for %s from %s, %s\n",
95                         tsptype[type], machfrom == NULL ? "ANY" : machfrom,
96                         netfrom == NULL ? "ANYNET" : inet_ntoa(netfrom->net));
97                 if (head->p != 0) {
98                         length = 1;
99                         for (ptr = head->p; ptr != 0; ptr = ptr->p) {
100                                 /* do not repeat the hundreds of messages */
101                                 if (++length > 3) {
102                                         if (ptr == tail) {
103                                                 fprintf(fd,"\t ...%d skipped\n",
104                                                         length);
105                                         } else {
106                                                 continue;
107                                         }
108                                 }
109                                 fprintf(fd, length > 1 ? "\t" : "queue:\t");
110                                 print(&ptr->info, &ptr->addr);
111                         }
112                 }
113         }
114
115         ptr = head->p;
116         prev = head;
117
118         /*
119          * Look for the requested message scanning through the
120          * linked list. If found, return it and free the space
121          */
122
123         while (ptr != NULL) {
124                 if (LOOKAT(ptr->info, type, machfrom, netfrom, ptr->addr)) {
125 again:
126                         msgin = ptr->info;
127                         from = ptr->addr;
128                         from_when = ptr->when;
129                         prev->p = ptr->p;
130                         if (ptr == tail)
131                                 tail = prev;
132                         free((char *)ptr);
133                         fromnet = NULL;
134                         if (netfrom == NULL)
135                             for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
136                                     if ((ntp->mask & from.sin_addr.s_addr) ==
137                                         ntp->net.s_addr) {
138                                             fromnet = ntp;
139                                             break;
140                                     }
141                             }
142                         else
143                             fromnet = netfrom;
144                         if (trace) {
145                                 fprintf(fd, "readmsg: found ");
146                                 print(&msgin, &from);
147                         }
148
149 /* The protocol can get far behind.  When it does, it gets
150  *      hopelessly confused.  So delete duplicate messages.
151  */
152                         for (ptr = prev; (ptr = ptr->p) != NULL; prev = ptr) {
153                                 if (ptr->addr.sin_addr.s_addr
154                                         == from.sin_addr.s_addr
155                                     && ptr->info.tsp_type == msgin.tsp_type) {
156                                         if (trace)
157                                                 fprintf(fd, "\tdup ");
158                                         goto again;
159                                 }
160                         }
161                         msgcnt--;
162                         return(&msgin);
163                 } else {
164                         prev = ptr;
165                         ptr = ptr->p;
166                 }
167         }
168
169         /*
170          * If the message was not in the linked list, it may still be
171          * coming from the network. Set the timer and wait
172          * on a select to read the next incoming message: if it is the
173          * right one, return it, otherwise insert it in the linked list.
174          */
175
176         (void)gettimeofday(&rtout, 0);
177         timevaladd(&rtout, intvl);
178         FD_ZERO(&ready);
179         for (;;) {
180                 (void)gettimeofday(&rtime, 0);
181                 timevalsub(&rwait, &rtout, &rtime);
182                 if (rwait.tv_sec < 0)
183                         rwait.tv_sec = rwait.tv_usec = 0;
184                 else if (rwait.tv_sec == 0
185                          && rwait.tv_usec < 1000000/CLK_TCK)
186                         rwait.tv_usec = 1000000/CLK_TCK;
187
188                 if (trace) {
189                         fprintf(fd, "readmsg: wait %ld.%6ld at %s\n",
190                                 rwait.tv_sec, rwait.tv_usec, date());
191                         /* Notice a full disk, as we flush trace info.
192                          * It is better to flush periodically than at
193                          * every line because the tracing consists of bursts
194                          * of many lines.  Without care, tracing slows
195                          * down the code enough to break the protocol.
196                          */
197                         if (rwait.tv_sec != 0
198                             && EOF == fflush(fd))
199                                 traceoff("Tracing ended for cause at %s\n");
200                 }
201
202                 FD_SET(sock, &ready);
203                 if (!select(sock+1, &ready, (fd_set *)0, (fd_set *)0,
204                            &rwait)) {
205                         if (rwait.tv_sec == 0 && rwait.tv_usec == 0)
206                                 return(0);
207                         continue;
208                 }
209                 length = sizeof(from);
210                 if ((n = recvfrom(sock, (char *)&msgin, sizeof(struct tsp), 0,
211                              (struct sockaddr*)&from, &length)) < 0) {
212                         syslog(LOG_ERR, "recvfrom: %m");
213                         exit(1);
214                 }
215                 /*
216                  * The 4.3BSD protocol spec had a 32-byte tsp_name field, and
217                  * this is still OS-dependent.  Demand that the packet is at
218                  * least long enough to hold a 4.3BSD packet.
219                  */
220                 if (n < (ssize_t)(sizeof(struct tsp) - MAXHOSTNAMELEN + 32)) {
221                         syslog(LOG_NOTICE,
222                             "short packet (%u/%u bytes) from %s",
223                               n, sizeof(struct tsp) - MAXHOSTNAMELEN + 32,
224                               inet_ntoa(from.sin_addr));
225                         continue;
226                 }
227                 (void)gettimeofday(&from_when, (struct timezone *)0);
228                 bytehostorder(&msgin);
229
230                 if (msgin.tsp_vers > TSPVERSION) {
231                         if (trace) {
232                             fprintf(fd,"readmsg: version mismatch\n");
233                             /* should do a dump of the packet */
234                         }
235                         continue;
236                 }
237
238                 if (memchr(msgin.tsp_name,
239                     '\0', sizeof msgin.tsp_name) == NULL) {
240                         syslog(LOG_NOTICE, "hostname field not NUL terminated "
241                             "in packet from %s", inet_ntoa(from.sin_addr));
242                         continue;
243                 }
244
245                 fromnet = NULL;
246                 for (ntp = nettab; ntp != NULL; ntp = ntp->next)
247                         if ((ntp->mask & from.sin_addr.s_addr) ==
248                             ntp->net.s_addr) {
249                                 fromnet = ntp;
250                                 break;
251                         }
252
253                 /*
254                  * drop packets from nets we are ignoring permanently
255                  */
256                 if (fromnet == NULL) {
257                         /*
258                          * The following messages may originate on
259                          * this host with an ignored network address
260                          */
261                         if (msgin.tsp_type != TSP_TRACEON &&
262                             msgin.tsp_type != TSP_SETDATE &&
263                             msgin.tsp_type != TSP_MSITE &&
264                             msgin.tsp_type != TSP_TEST &&
265                             msgin.tsp_type != TSP_TRACEOFF) {
266                                 if (trace) {
267                                     fprintf(fd,"readmsg: discard null net ");
268                                     print(&msgin, &from);
269                                 }
270                                 continue;
271                         }
272                 }
273
274                 /*
275                  * Throw away messages coming from this machine,
276                  * unless they are of some particular type.
277                  * This gets rid of broadcast messages and reduces
278                  * master processing time.
279                  */
280                 if (!strcmp(msgin.tsp_name, hostname)
281                     && msgin.tsp_type != TSP_SETDATE
282                     && msgin.tsp_type != TSP_TEST
283                     && msgin.tsp_type != TSP_MSITE
284                     && msgin.tsp_type != TSP_TRACEON
285                     && msgin.tsp_type != TSP_TRACEOFF
286                     && msgin.tsp_type != TSP_LOOP) {
287                         if (trace) {
288                                 fprintf(fd, "readmsg: discard own ");
289                                 print(&msgin, &from);
290                         }
291                         continue;
292                 }
293
294                 /*
295                  * Send acknowledgements here; this is faster and
296                  * avoids deadlocks that would occur if acks were
297                  * sent from a higher level routine.  Different
298                  * acknowledgements are necessary, depending on
299                  * status.
300                  */
301                 if (fromnet == NULL)    /* do not de-reference 0 */
302                         ignoreack();
303                 else if (fromnet->status == MASTER)
304                         masterack();
305                 else if (fromnet->status == SLAVE)
306                         slaveack();
307                 else
308                         ignoreack();
309
310                 if (LOOKAT(msgin, type, machfrom, netfrom, from)) {
311                         if (trace) {
312                                 fprintf(fd, "readmsg: ");
313                                 print(&msgin, &from);
314                         }
315                         return(&msgin);
316                 } else if (++msgcnt > NHOSTS*3) {
317
318 /* The protocol gets hopelessly confused if it gets too far
319 *       behind.  However, it seems able to recover from all cases of lost
320 *       packets.  Therefore, if we are swamped, throw everything away.
321 */
322                         if (trace)
323                                 fprintf(fd,
324                                         "readmsg: discarding %d msgs\n",
325                                         msgcnt);
326                         msgcnt = 0;
327                         while ((ptr=head->p) != NULL) {
328                                 head->p = ptr->p;
329                                 free((char *)ptr);
330                         }
331                         tail = head;
332                 } else {
333                         tail->p = (struct tsplist *)
334                                     malloc(sizeof(struct tsplist));
335                         tail = tail->p;
336                         tail->p = NULL;
337                         tail->info = msgin;
338                         tail->addr = from;
339                         /* timestamp msgs so SETTIMEs are correct */
340                         tail->when = from_when;
341                 }
342         }
343 }
344
345 /*
346  * Send the necessary acknowledgements:
347  * only the type ACK is to be sent by a slave
348  */
349 void
350 slaveack()
351 {
352         switch(msgin.tsp_type) {
353
354         case TSP_ADJTIME:
355         case TSP_SETTIME:
356         case TSP_ACCEPT:
357         case TSP_REFUSE:
358         case TSP_TRACEON:
359         case TSP_TRACEOFF:
360         case TSP_QUIT:
361                 if (trace) {
362                         fprintf(fd, "Slaveack: ");
363                         print(&msgin, &from);
364                 }
365                 xmit(TSP_ACK,msgin.tsp_seq, &from);
366                 break;
367
368         default:
369                 if (trace) {
370                         fprintf(fd, "Slaveack: no ack: ");
371                         print(&msgin, &from);
372                 }
373                 break;
374         }
375 }
376
377 /*
378  * Certain packets may arrive from this machine on ignored networks.
379  * These packets should be acknowledged.
380  */
381 void
382 ignoreack()
383 {
384         switch(msgin.tsp_type) {
385
386         case TSP_TRACEON:
387         case TSP_TRACEOFF:
388         case TSP_QUIT:
389                 if (trace) {
390                         fprintf(fd, "Ignoreack: ");
391                         print(&msgin, &from);
392                 }
393                 xmit(TSP_ACK,msgin.tsp_seq, &from);
394                 break;
395
396         default:
397                 if (trace) {
398                         fprintf(fd, "Ignoreack: no ack: ");
399                         print(&msgin, &from);
400                 }
401                 break;
402         }
403 }
404
405 /*
406  * `masterack' sends the necessary acknowledgments
407  * to the messages received by a master
408  */
409 void
410 masterack()
411 {
412         struct tsp resp;
413
414         resp = msgin;
415         resp.tsp_vers = TSPVERSION;
416         (void)strcpy(resp.tsp_name, hostname);
417
418         switch(msgin.tsp_type) {
419
420         case TSP_QUIT:
421         case TSP_TRACEON:
422         case TSP_TRACEOFF:
423         case TSP_MSITEREQ:
424                 if (trace) {
425                         fprintf(fd, "Masterack: ");
426                         print(&msgin, &from);
427                 }
428                 xmit(TSP_ACK,msgin.tsp_seq, &from);
429                 break;
430
431         case TSP_RESOLVE:
432         case TSP_MASTERREQ:
433                 if (trace) {
434                         fprintf(fd, "Masterack: ");
435                         print(&msgin, &from);
436                 }
437                 xmit(TSP_MASTERACK,msgin.tsp_seq, &from);
438                 break;
439
440         default:
441                 if (trace) {
442                         fprintf(fd,"Masterack: no ack: ");
443                         print(&msgin, &from);
444                 }
445                 break;
446         }
447 }
448
449 /*
450  * Print a TSP message
451  */
452 void
453 print(msg, addr)
454         struct tsp *msg;
455         struct sockaddr_in *addr;
456 {
457         char tm[26];
458         time_t tsp_time_sec;
459
460         if (msg->tsp_type >= TSPTYPENUMBER) {
461                 fprintf(fd, "bad type (%u) on packet from %s\n",
462                   msg->tsp_type, inet_ntoa(addr->sin_addr));
463                 return;
464         }
465
466         switch (msg->tsp_type) {
467
468         case TSP_LOOP:
469                 fprintf(fd, "%s %d %-6u #%d %-15s %s\n",
470                         tsptype[msg->tsp_type],
471                         msg->tsp_vers,
472                         msg->tsp_seq,
473                         msg->tsp_hopcnt,
474                         inet_ntoa(addr->sin_addr),
475                         msg->tsp_name);
476                 break;
477
478         case TSP_SETTIME:
479         case TSP_SETDATE:
480         case TSP_SETDATEREQ:
481                 tsp_time_sec = msg->tsp_time.tv_sec;
482                 strncpy(tm, ctime(&tsp_time_sec)+3+1, sizeof(tm));
483                 tm[15] = '\0';          /* ugh */
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 }