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