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