File:  [DragonFly] / src / usr.sbin / timed / timed / readmsg.c
Revision 1.3: download - view: text, annotated - select for diffs
Sat Mar 13 21:08:38 2004 UTC (10 years, 7 months ago) by eirikn
Branches: MAIN
CVS tags: HEAD, DragonFly_1_0_REL, DragonFly_1_0_RC1, DragonFly_1_0A_REL
 * Remove ``register'' keywords.
 * Convert K&R-style function declarations to ANSI-style.

Submitted by: Chris Pressey <cpressey@catseye.mine.nu>

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