xref: /original-bsd/usr.sbin/timed/timed/readmsg.c (revision f0203ecd)
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.12 (Berkeley) 06/01/90";
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, &from, &length) < 0) {
156 				syslog(LOG_ERR, "receiving datagram packet: %m");
157 				exit(1);
158 			}
159 
160 			bytehostorder(&msgin);
161 
162 			if (msgin.tsp_vers > TSPVERSION) {
163 				if (trace) {
164 				    fprintf(fd, "readmsg: version mismatch\n");
165 				    /* should do a dump of the packet, but... */
166 				}
167 				continue;
168 			}
169 
170 			fromnet = NULL;
171 			for (ntp = nettab; ntp != NULL; ntp = ntp->next)
172 				if ((ntp->mask & from.sin_addr.s_addr) ==
173 				    ntp->net) {
174 					fromnet = ntp;
175 					break;
176 				}
177 
178 			/*
179 			 * drop packets from nets we are ignoring permanently
180 			 */
181 			if (fromnet == NULL) {
182 				/*
183 				 * The following messages may originate on
184 				 * this host with an ignored network address
185 				 */
186 				if (msgin.tsp_type != TSP_TRACEON &&
187 				    msgin.tsp_type != TSP_SETDATE &&
188 				    msgin.tsp_type != TSP_MSITE &&
189 #ifdef	TESTING
190 				    msgin.tsp_type != TSP_TEST &&
191 #endif
192 				    msgin.tsp_type != TSP_TRACEOFF) {
193 					if (trace) {
194 					    fprintf(fd, "readmsg: discarded: ");
195 					    print(&msgin, &from);
196 					}
197 					continue;
198 				}
199 			}
200 
201 			/*
202 			 * Throw away messages coming from this machine, unless
203 			 * they are of some particular type.
204 			 * This gets rid of broadcast messages and reduces
205 			 * master processing time.
206 			 */
207 			if ( !(strcmp(msgin.tsp_name, hostname) != 0 ||
208 					msgin.tsp_type == TSP_SETDATE ||
209 #ifdef TESTING
210 					msgin.tsp_type == TSP_TEST ||
211 #endif
212 					msgin.tsp_type == TSP_MSITE ||
213 					(msgin.tsp_type == TSP_LOOP &&
214 					msgin.tsp_hopcnt != 10) ||
215 					msgin.tsp_type == TSP_TRACEON ||
216 					msgin.tsp_type == TSP_TRACEOFF)) {
217 				if (trace) {
218 					fprintf(fd, "readmsg: discarded: ");
219 					print(&msgin, &from);
220 				}
221 				continue;
222 			}
223 
224 			/*
225 			 * Send acknowledgements here; this is faster and avoids
226 			 * deadlocks that would occur if acks were sent from a
227 			 * higher level routine.  Different acknowledgements are
228 			 * necessary, depending on status.
229 			 */
230 			if (fromnet->status == MASTER)
231 				masterack();
232 			else if (fromnet->status == SLAVE)
233 				slaveack();
234 			else
235 				ignoreack();
236 
237 			if (LOOKAT(msgin, type, machfrom, netfrom, from)) {
238 				if (trace) {
239 					fprintf(fd, "readmsg: ");
240 					print(&msgin, &from);
241 				}
242 				return(&msgin);
243 			} else {
244 				tail->p = (struct tsplist *)
245 						malloc(sizeof(struct tsplist));
246 				tail = tail->p;
247 				tail->p = NULL;
248 				tail->info = msgin;
249 				tail->addr = from;
250 			}
251 		} else {
252 			break;
253 		}
254 	}
255 	return((struct tsp *)NULL);
256 }
257 
258 /*
259  * `slaveack' sends the necessary acknowledgements:
260  * only the type ACK is to be sent by a slave
261  */
262 
263 slaveack()
264 {
265 	int length;
266 	struct tsp resp;
267 
268 	length = sizeof(struct sockaddr_in);
269 	switch(msgin.tsp_type) {
270 
271 	case TSP_ADJTIME:
272 	case TSP_SETTIME:
273 	case TSP_ACCEPT:
274 	case TSP_REFUSE:
275 	case TSP_TRACEON:
276 	case TSP_TRACEOFF:
277 	case TSP_QUIT:
278 		resp = msgin;
279 		resp.tsp_type = TSP_ACK;
280 		resp.tsp_vers = TSPVERSION;
281 		(void)strcpy(resp.tsp_name, hostname);
282 		if (trace) {
283 			fprintf(fd, "Slaveack: ");
284 			print(&resp, &from);
285 		}
286 		bytenetorder(&resp);     /* this is not really necessary here */
287 		if (sendto(sock, (char *)&resp, sizeof(struct tsp), 0,
288 						&from, length) < 0) {
289 			syslog(LOG_ERR, "sendto: %m");
290 			exit(1);
291 		}
292 		break;
293 	default:
294 		break;
295 	}
296 }
297 
298 /*
299  * Certain packets may arrive from this machine on ignored networks.
300  * These packets should be acknowledged.
301  */
302 
303 ignoreack()
304 {
305 	int length;
306 	struct tsp resp;
307 
308 	length = sizeof(struct sockaddr_in);
309 	switch(msgin.tsp_type) {
310 
311 	case TSP_TRACEON:
312 	case TSP_TRACEOFF:
313 		resp = msgin;
314 		resp.tsp_type = TSP_ACK;
315 		resp.tsp_vers = TSPVERSION;
316 		(void)strcpy(resp.tsp_name, hostname);
317 		if (trace) {
318 			fprintf(fd, "Ignoreack: ");
319 			print(&resp, &from);
320 		}
321 		bytenetorder(&resp);     /* this is not really necessary here */
322 		if (sendto(sock, (char *)&resp, sizeof(struct tsp), 0,
323 						&from, length) < 0) {
324 			syslog(LOG_ERR, "sendto: %m");
325 			exit(1);
326 		}
327 		break;
328 	default:
329 		break;
330 	}
331 }
332 
333 /*
334  * `masterack' sends the necessary acknowledgments
335  * to the messages received by a master
336  */
337 
338 masterack()
339 {
340 	int length;
341 	struct tsp resp;
342 
343 	length = sizeof(struct sockaddr_in);
344 
345 	resp = msgin;
346 	resp.tsp_vers = TSPVERSION;
347 	(void)strcpy(resp.tsp_name, hostname);
348 
349 	switch(msgin.tsp_type) {
350 
351 	case TSP_QUIT:
352 	case TSP_TRACEON:
353 	case TSP_TRACEOFF:
354 	case TSP_MSITE:
355 	case TSP_MSITEREQ:
356 		resp.tsp_type = TSP_ACK;
357 		bytenetorder(&resp);
358 		if (trace) {
359 			fprintf(fd, "Masterack: ");
360 			print(&resp, &from);
361 		}
362 		if (sendto(sock, (char *)&resp, sizeof(struct tsp), 0,
363 						&from, length) < 0) {
364 			syslog(LOG_ERR, "sendto: %m");
365 			exit(1);
366 		}
367 		break;
368 	case TSP_RESOLVE:
369 	case TSP_MASTERREQ:
370 		resp.tsp_type = TSP_MASTERACK;
371 		bytenetorder(&resp);
372 		if (trace) {
373 			fprintf(fd, "Masterack: ");
374 			print(&resp, &from);
375 		}
376 		if (sendto(sock, (char *)&resp, sizeof(struct tsp), 0,
377 						&from, length) < 0) {
378 			syslog(LOG_ERR, "sendto: %m");
379 			exit(1);
380 		}
381 		break;
382 	case TSP_SETDATEREQ:
383 		resp.tsp_type = TSP_DATEACK;
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 						&from, length) < 0) {
391 			syslog(LOG_ERR, "sendto: %m");
392 			exit(1);
393 		}
394 		break;
395 	default:
396 		break;
397 	}
398 }
399 
400 /*
401  * Print a TSP message
402  */
403 print(msg, addr)
404 struct tsp *msg;
405 struct sockaddr_in *addr;
406 {
407 	switch (msg->tsp_type) {
408 
409 	case TSP_LOOP:
410 		fprintf(fd, "%s %d %d (#%d) %s %s\n",
411 			tsptype[msg->tsp_type],
412 			msg->tsp_vers,
413 			msg->tsp_seq,
414 			msg->tsp_hopcnt,
415 			msg->tsp_name,
416 			inet_ntoa(addr->sin_addr));
417 		break;
418 
419 	case TSP_SETTIME:
420 	case TSP_ADJTIME:
421 	case TSP_SETDATE:
422 	case TSP_SETDATEREQ:
423 		fprintf(fd, "%s %d %d (%d, %d) %s %s\n",
424 			tsptype[msg->tsp_type],
425 			msg->tsp_vers,
426 			msg->tsp_seq,
427 			msg->tsp_time.tv_sec,
428 			msg->tsp_time.tv_usec,
429 			msg->tsp_name,
430 			inet_ntoa(addr->sin_addr));
431 		break;
432 
433 	default:
434 		fprintf(fd, "%s %d %d %s %s\n",
435 			tsptype[msg->tsp_type],
436 			msg->tsp_vers,
437 			msg->tsp_seq,
438 			msg->tsp_name,
439 			inet_ntoa(addr->sin_addr));
440 		break;
441 	}
442 }
443