xref: /386bsd/usr/src/usr.sbin/timed/timed/readmsg.c (revision a2142627)
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