Home | History | Annotate | Line # | Download | only in timed
      1 /*	$NetBSD: readmsg.c,v 1.23 2017/08/11 16:47:42 ginsbach Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1985, 1993 The Regents of the University of California.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #ifndef lint
     34 #if 0
     35 static char sccsid[] = "@(#)readmsg.c	8.1 (Berkeley) 6/6/93";
     36 #else
     37 __RCSID("$NetBSD: readmsg.c,v 1.23 2017/08/11 16:47:42 ginsbach Exp $");
     38 #endif
     39 #endif /* not lint */
     40 
     41 #include "globals.h"
     42 
     43 extern const char * const tsptype[];
     44 
     45 /*
     46  * LOOKAT checks if the message is of the requested type and comes from
     47  * the right machine, returning 1 in case of affirmative answer
     48  */
     49 #define LOOKAT(msg, mtype, mfrom, netp, froms) \
     50 	(((mtype) == TSP_ANY || (mtype) == (msg).tsp_type) &&		\
     51 	 ((mfrom) == 0 || !strcmp((mfrom), (msg).tsp_name)) &&		\
     52 	 ((netp) == 0 || 						\
     53 	  ((netp)->mask & (froms).sin_addr.s_addr) == (netp)->net.s_addr))
     54 
     55 struct timeval rtime, rwait, rtout;
     56 struct tsp msgin;
     57 static struct tsplist {
     58 	struct tsp info;
     59 	struct timeval when;
     60 	struct sockaddr_in addr;
     61 	struct tsplist *p;
     62 } msgslist;
     63 struct sockaddr_in from;
     64 struct netinfo *fromnet;
     65 struct timeval from_when;
     66 
     67 /*
     68  * `readmsg' returns message `type' sent by `machfrom' if it finds it
     69  * either in the receive queue, or in a linked list of previously received
     70  * messages that it maintains.
     71  * Otherwise it waits to see if the appropriate message arrives within
     72  * `intvl' seconds. If not, it returns NULL.
     73  */
     74 
     75 struct tsp *
     76 readmsg(int type, char *machfrom, struct timeval *intvl,
     77 	struct netinfo *netfrom)
     78 {
     79 	socklen_t length;
     80 	struct pollfd set[1];
     81 	static struct tsplist *head = &msgslist;
     82 	static struct tsplist *tail = &msgslist;
     83 	static int msgcnt = 0;
     84 	struct tsplist *prev;
     85 	struct netinfo *ntp;
     86 	struct tsplist *ptr;
     87 	ssize_t n;
     88 
     89 	if (trace) {
     90 		fprintf(fd, "readmsg: looking for %s from %s, %s\n",
     91 			tsptype[type], machfrom == NULL ? "ANY" : machfrom,
     92 			netfrom == NULL ? "ANYNET" : inet_ntoa(netfrom->net));
     93 		if (head->p != 0) {
     94 			length = 1;
     95 			for (ptr = head->p; ptr != 0; ptr = ptr->p) {
     96 				/* do not repeat the hundreds of messages */
     97 				if (++length > 3) {
     98 					if (ptr == tail) {
     99 						fprintf(fd,"\t ...%d skipped\n",
    100 							length);
    101 					} else {
    102 						continue;
    103 					}
    104 				}
    105 				fprintf(fd, length > 1 ? "\t" : "queue:\t");
    106 				print(&ptr->info, &ptr->addr);
    107 			}
    108 		}
    109 	}
    110 
    111 	ptr = head->p;
    112 	prev = head;
    113 
    114 	/*
    115 	 * Look for the requested message scanning through the
    116 	 * linked list. If found, return it and free the space
    117 	 */
    118 
    119 	while (ptr != NULL) {
    120 		if (LOOKAT(ptr->info, type, machfrom, netfrom, ptr->addr)) {
    121 again:
    122 			msgin = ptr->info;
    123 			from = ptr->addr;
    124 			from_when = ptr->when;
    125 			prev->p = ptr->p;
    126 			if (ptr == tail)
    127 				tail = prev;
    128 			free(ptr);
    129 			fromnet = NULL;
    130 			if (netfrom == NULL)
    131 			    for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
    132 				    if ((ntp->mask & from.sin_addr.s_addr) ==
    133 					ntp->net.s_addr) {
    134 					    fromnet = ntp;
    135 					    break;
    136 				    }
    137 			    }
    138 			else
    139 			    fromnet = netfrom;
    140 			if (trace) {
    141 				fprintf(fd, "readmsg: found ");
    142 				print(&msgin, &from);
    143 			}
    144 
    145 /* The protocol can get far behind.  When it does, it gets
    146  *	hopelessly confused.  So delete duplicate messages.
    147  */
    148 			for (ptr = prev; (ptr = ptr->p) != NULL; prev = ptr) {
    149 				if (ptr->addr.sin_addr.s_addr
    150 					== from.sin_addr.s_addr
    151 				    && ptr->info.tsp_type == msgin.tsp_type) {
    152 					if (trace)
    153 						fprintf(fd, "\tdup ");
    154 					goto again;
    155 				}
    156 			}
    157 			msgcnt--;
    158 			return(&msgin);
    159 		} else {
    160 			prev = ptr;
    161 			ptr = ptr->p;
    162 		}
    163 	}
    164 
    165 	/*
    166 	 * If the message was not in the linked list, it may still be
    167 	 * coming from the network. Set the timer and wait
    168 	 * on a select to read the next incoming message: if it is the
    169 	 * right one, return it, otherwise insert it in the linked list.
    170 	 */
    171 
    172 	(void)gettimeofday(&rtout, 0);
    173 	timeradd(&rtout, intvl, &rtout);
    174 	set[0].fd = sock;
    175 	set[0].events = POLLIN;
    176 	for (;;) {
    177 		(void)gettimeofday(&rtime, 0);
    178 		timersub(&rtout, &rtime, &rwait);
    179 		if (rwait.tv_sec < 0)
    180 			rwait.tv_sec = rwait.tv_usec = 0;
    181 		else if (rwait.tv_sec == 0
    182 			 && rwait.tv_usec < 1000000/CLK_TCK)
    183 			rwait.tv_usec = 1000000/CLK_TCK;
    184 
    185 		if (trace) {
    186 			fprintf(fd, "readmsg: wait %ld.%6ld at %s\n",
    187 			    (long int)rwait.tv_sec, (long int)rwait.tv_usec,
    188 			    date());
    189 			/* Notice a full disk, as we flush trace info.
    190 			 * It is better to flush periodically than at
    191 			 * every line because the tracing consists of bursts
    192 			 * of many lines.  Without care, tracing slows
    193 			 * down the code enough to break the protocol.
    194 			 */
    195 			if (rwait.tv_sec != 0
    196 			    && EOF == fflush(fd))
    197 				traceoff("Tracing ended for cause");
    198 		}
    199 
    200 		if (!poll(set, 1, (int)(rwait.tv_sec * 1000 + rwait.tv_usec / 1000))) {
    201 			if (rwait.tv_sec == 0 && rwait.tv_usec == 0)
    202 				return(0);
    203 			continue;
    204 		}
    205 		length = sizeof(from);
    206 		memset(&msgin, 0, sizeof(msgin));
    207 		if ((n = recvfrom(sock, &msgin, sizeof(struct tsp), 0,
    208 			     (struct sockaddr*)(void *)&from, &length)) < 0) {
    209 			syslog(LOG_ERR, "recvfrom: %m");
    210 			exit(EXIT_FAILURE);
    211 		}
    212 		/*
    213 		 * The 4.3BSD protocol spec had a 32-byte tsp_name field, and
    214 		 * this is still OS-dependent.  Demand that the packet is at
    215 		 * least long enough to hold a 4.3BSD packet.
    216 		 */
    217 		if (n < (ssize_t)(sizeof(struct tsp) - MAXHOSTNAMELEN + 32)) {
    218 			syslog(LOG_NOTICE,
    219 			    "short packet (%lu/%lu bytes) from %s",
    220 			      (u_long)n,
    221 			      (u_long)(sizeof(struct tsp) - MAXHOSTNAMELEN + 32),
    222 			      inet_ntoa(from.sin_addr));
    223 			continue;
    224 		}
    225 		(void)gettimeofday(&from_when, (struct timezone *)0);
    226 		bytehostorder(&msgin);
    227 
    228 		if (msgin.tsp_vers > TSPVERSION) {
    229 			if (trace) {
    230 			    fprintf(fd,"readmsg: version mismatch\n");
    231 			    /* should do a dump of the packet */
    232 			}
    233 			continue;
    234 		}
    235 
    236 		if (memchr(msgin.tsp_name,
    237 		    '\0', sizeof msgin.tsp_name) == NULL) {
    238 			syslog(LOG_NOTICE, "hostname field not NUL terminated "
    239 			    "in packet from %s", inet_ntoa(from.sin_addr));
    240 			continue;
    241 		}
    242 
    243 		fromnet = NULL;
    244 		for (ntp = nettab; ntp != NULL; ntp = ntp->next)
    245 			if ((ntp->mask & from.sin_addr.s_addr) ==
    246 			    ntp->net.s_addr) {
    247 				fromnet = ntp;
    248 				break;
    249 			}
    250 
    251 		/*
    252 		 * drop packets from nets we are ignoring permanently
    253 		 */
    254 		if (fromnet == NULL) {
    255 			/*
    256 			 * The following messages may originate on
    257 			 * this host with an ignored network address
    258 			 */
    259 			if (msgin.tsp_type != TSP_TRACEON &&
    260 			    msgin.tsp_type != TSP_SETDATE &&
    261 			    msgin.tsp_type != TSP_MSITE &&
    262 			    msgin.tsp_type != TSP_TEST &&
    263 			    msgin.tsp_type != TSP_TRACEOFF) {
    264 				if (trace) {
    265 				    fprintf(fd,"readmsg: discard null net ");
    266 				    print(&msgin, &from);
    267 				}
    268 				continue;
    269 			}
    270 		}
    271 
    272 		/*
    273 		 * Throw away messages coming from this machine,
    274 		 * unless they are of some particular type.
    275 		 * This gets rid of broadcast messages and reduces
    276 		 * master processing time.
    277 		 */
    278 		if (!strcmp(msgin.tsp_name, hostname)
    279 		    && msgin.tsp_type != TSP_SETDATE
    280 		    && msgin.tsp_type != TSP_TEST
    281 		    && msgin.tsp_type != TSP_MSITE
    282 		    && msgin.tsp_type != TSP_TRACEON
    283 		    && msgin.tsp_type != TSP_TRACEOFF
    284 		    && msgin.tsp_type != TSP_LOOP) {
    285 			if (trace) {
    286 				fprintf(fd, "readmsg: discard own ");
    287 				print(&msgin, &from);
    288 			}
    289 			continue;
    290 		}
    291 
    292 		/*
    293 		 * Send acknowledgements here; this is faster and
    294 		 * avoids deadlocks that would occur if acks were
    295 		 * sent from a higher level routine.  Different
    296 		 * acknowledgements are necessary, depending on
    297 		 * status.
    298 		 */
    299 		if (fromnet == NULL)	/* do not de-reference 0 */
    300 			ignoreack();
    301 		else if (fromnet->status == MASTER)
    302 			masterack();
    303 		else if (fromnet->status == SLAVE)
    304 			slaveack();
    305 		else
    306 			ignoreack();
    307 
    308 		if (LOOKAT(msgin, type, machfrom, netfrom, from)) {
    309 			if (trace) {
    310 				fprintf(fd, "readmsg: ");
    311 				print(&msgin, &from);
    312 			}
    313 			return(&msgin);
    314 		} else if (++msgcnt > NHOSTS*3) {
    315 
    316 /* The protocol gets hopelessly confused if it gets too far
    317 *	behind.  However, it seems able to recover from all cases of lost
    318 *	packets.  Therefore, if we are swamped, throw everything away.
    319 */
    320 			if (trace)
    321 				fprintf(fd,
    322 					"readmsg: discarding %d msgs\n",
    323 					msgcnt);
    324 			msgcnt = 0;
    325 			while ((ptr = head->p) != NULL) {
    326 				head->p = ptr->p;
    327 				free(ptr);
    328 			}
    329 			tail = head;
    330 		} else {
    331 			tail->p = malloc(sizeof(struct tsplist));
    332 			tail = tail->p;
    333 			tail->p = NULL;
    334 			tail->info = msgin;
    335 			tail->addr = from;
    336 			/* timestamp msgs so SETTIMEs are correct */
    337 			tail->when = from_when;
    338 		}
    339 	}
    340 }
    341 
    342 /*
    343  * Send the necessary acknowledgements:
    344  * only the type ACK is to be sent by a slave
    345  */
    346 void
    347 slaveack(void)
    348 {
    349 	switch(msgin.tsp_type) {
    350 
    351 	case TSP_ADJTIME:
    352 	case TSP_SETTIME:
    353 	case TSP_ACCEPT:
    354 	case TSP_REFUSE:
    355 	case TSP_TRACEON:
    356 	case TSP_TRACEOFF:
    357 	case TSP_QUIT:
    358 		if (trace) {
    359 			fprintf(fd, "Slaveack: ");
    360 			print(&msgin, &from);
    361 		}
    362 		xmit(TSP_ACK,msgin.tsp_seq, &from);
    363 		break;
    364 
    365 	default:
    366 		if (trace) {
    367 			fprintf(fd, "Slaveack: no ack: ");
    368 			print(&msgin, &from);
    369 		}
    370 		break;
    371 	}
    372 }
    373 
    374 /*
    375  * Certain packets may arrive from this machine on ignored networks.
    376  * These packets should be acknowledged.
    377  */
    378 void
    379 ignoreack(void)
    380 {
    381 	switch(msgin.tsp_type) {
    382 
    383 	case TSP_TRACEON:
    384 	case TSP_TRACEOFF:
    385 	case TSP_QUIT:
    386 		if (trace) {
    387 			fprintf(fd, "Ignoreack: ");
    388 			print(&msgin, &from);
    389 		}
    390 		xmit(TSP_ACK,msgin.tsp_seq, &from);
    391 		break;
    392 
    393 	default:
    394 		if (trace) {
    395 			fprintf(fd, "Ignoreack: no ack: ");
    396 			print(&msgin, &from);
    397 		}
    398 		break;
    399 	}
    400 }
    401 
    402 /*
    403  * `masterack' sends the necessary acknowledgements
    404  * to the messages received by a master
    405  */
    406 void
    407 masterack(void)
    408 {
    409 	struct tsp resp;
    410 
    411 	resp = msgin;
    412 	resp.tsp_vers = TSPVERSION;
    413 	set_tsp_name(&resp, hostname);
    414 
    415 	switch(msgin.tsp_type) {
    416 
    417 	case TSP_QUIT:
    418 	case TSP_TRACEON:
    419 	case TSP_TRACEOFF:
    420 	case TSP_MSITEREQ:
    421 		if (trace) {
    422 			fprintf(fd, "Masterack: ");
    423 			print(&msgin, &from);
    424 		}
    425 		xmit(TSP_ACK,msgin.tsp_seq, &from);
    426 		break;
    427 
    428 	case TSP_RESOLVE:
    429 	case TSP_MASTERREQ:
    430 		if (trace) {
    431 			fprintf(fd, "Masterack: ");
    432 			print(&msgin, &from);
    433 		}
    434 		xmit(TSP_MASTERACK,msgin.tsp_seq, &from);
    435 		break;
    436 
    437 	default:
    438 		if (trace) {
    439 			fprintf(fd,"Masterack: no ack: ");
    440 			print(&msgin, &from);
    441 		}
    442 		break;
    443 	}
    444 }
    445 
    446 /*
    447  * Print a TSP message
    448  */
    449 void
    450 print(struct tsp *msg, struct sockaddr_in *addr)
    451 {
    452 	char tm[26];
    453 	time_t msgtime;
    454 
    455 	if (msg->tsp_type >= TSPTYPENUMBER) {
    456 		fprintf(fd, "bad type (%u) on packet from %s\n",
    457 		  msg->tsp_type, inet_ntoa(addr->sin_addr));
    458 		return;
    459 	}
    460 
    461 	switch (msg->tsp_type) {
    462 
    463 	case TSP_LOOP:
    464 		fprintf(fd, "%s %d %-6u #%d %-15s %s\n",
    465 			tsptype[msg->tsp_type],
    466 			msg->tsp_vers,
    467 			msg->tsp_seq,
    468 			msg->tsp_hopcnt,
    469 			inet_ntoa(addr->sin_addr),
    470 			msg->tsp_name);
    471 		break;
    472 
    473 	case TSP_SETTIME:
    474 	case TSP_SETDATE:
    475 	case TSP_SETDATEREQ:
    476 		msgtime = msg->tsp_time.tv_sec;
    477 		strlcpy(tm, ctime(&msgtime)+3+1, sizeof(tm));
    478 		tm[15] = '\0';		/* ugh */
    479 		fprintf(fd, "%s %d %-6u %s %-15s %s\n",
    480 			tsptype[msg->tsp_type],
    481 			msg->tsp_vers,
    482 			msg->tsp_seq,
    483 			tm,
    484 			inet_ntoa(addr->sin_addr),
    485 			msg->tsp_name);
    486 		break;
    487 
    488 	case TSP_ADJTIME:
    489 		fprintf(fd, "%s %d %-6u (%ld,%ld) %-15s %s\n",
    490 			tsptype[msg->tsp_type],
    491 			msg->tsp_vers,
    492 			msg->tsp_seq,
    493 			(long)msg->tsp_time.tv_sec,
    494 			(long)msg->tsp_time.tv_usec,
    495 			inet_ntoa(addr->sin_addr),
    496 			msg->tsp_name);
    497 		break;
    498 
    499 	default:
    500 		fprintf(fd, "%s %d %-6u %-15s %s\n",
    501 			tsptype[msg->tsp_type],
    502 			msg->tsp_vers,
    503 			msg->tsp_seq,
    504 			inet_ntoa(addr->sin_addr),
    505 			msg->tsp_name);
    506 		break;
    507 	}
    508 }
    509