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