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