Path: utzoo!attcan!uunet!husc6!rice!bcm!soma!masscomp-request
From: sob@cortex.neuro.bcm.tmc.edu (Stan Barber)
Newsgroups: comp.sys.masscomp
Subject: resolver library for MASSCOMP (part 6 of 7)
Message-ID: <1156@gazette.bcm.tmc.edu>
Date: 11 Jul 88 23:51:45 GMT
Sender: usenet@bcm.tmc.edu
Lines: 1158
Approved: masscomp@soma.neuro.bcm.tmc.edu

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	res/res_init.c
#	res/res_mkquery.c
#	res/res_query.c
#	res/res_send.c
# This archive created: Mon Jul  4 20:32:45 1988
export PATH; PATH=/bin:/usr/bin:$PATH
if test ! -d 'res'
then
	echo shar: "creating directory 'res'"
	mkdir 'res'
fi
echo shar: "entering directory 'res'"
cd 'res'
echo shar: "extracting 'res_init.c'" '(4721 characters)'
if test -f 'res_init.c'
then
	echo shar: "will not over-write existing file 'res_init.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'res_init.c'
	X/*
	X * Copyright (c) 1985 Regents of the University of California.
	X * All rights reserved.
	X *
	X * Redistribution and use in source and binary forms are permitted
	X * provided that this notice is preserved and that due credit is given
	X * to the University of California at Berkeley. The name of the University
	X * may not be used to endorse or promote products derived from this
	X * software without specific prior written permission. This software
	X * is provided ``as is'' without express or implied warranty.
	X */
	X
	X#if defined(LIBC_SCCS) && !defined(lint)
	Xstatic char sccsid[] = "@(#)res_init.c	6.8 (Berkeley) 3/7/88";
	X#endif /* LIBC_SCCS and not lint */
	X
	X#include 
	X#ifdef EXOS
	X#include 
	X#endif
	X#include 
	X#include 
	X#include 
	X#include 
	X#include 
	X
	X/*
	X * Resolver configuration file. Contains the address of the
	X * inital name server to query and the default domain for
	X * non fully qualified domain names.
	X */
	X
	X#ifndef	CONFFILE
	X#define	CONFFILE	"/etc/resolv.conf"
	X#endif
	X
	X/*
	X * Resolver state default settings
	X */
	X
	Xstruct state _res = {
	X    RES_TIMEOUT,               	/* retransmition time interval */
	X    4,                         	/* number of times to retransmit */
	X    RES_DEFAULT,		/* options flags */
	X    1,                         	/* number of name servers */
	X};
	X
	X/*
	X * Set up default settings.  If the configuration file exist, the values
	X * there will have precedence.  Otherwise, the server address is set to
	X * INADDR_ANY and the default domain name comes from the gethostname().
	X *
	X * The configuration file should only be used if you want to redefine your
	X * domain or run without a server on your machine.
	X *
	X * Return 0 if completes successfully, -1 on error
	X */
	Xres_init()
	X{
	X    register FILE *fp;
	X    register char *cp, **pp;
	X    char buf[BUFSIZ];
	X    extern u_long inet_addr();
	X    extern char *index();
	X    extern char *strcpy(), *strncpy();
	X    extern char *getenv();
	X    int n = 0;    /* number of nameserver records read from file */
	X
	X    _res.nsaddr.sin_addr.s_addr = INADDR_ANY;
	X    _res.nsaddr.sin_family = AF_INET;
	X    _res.nsaddr.sin_port = htons(NAMESERVER_PORT);
	X    _res.nscount = 1;
	X    _res.defdname[0] = '\0';
	X
	X    if ((fp = fopen(CONFFILE, "r")) != NULL) {
	X        /* read the config file */
	X        while (fgets(buf, sizeof(buf), fp) != NULL) {
	X            /* read default domain name */
	X            if (!strncmp(buf, "domain", sizeof("domain") - 1)) {
	X                cp = buf + sizeof("domain") - 1;
	X                while (*cp == ' ' || *cp == '\t')
	X                    cp++;
	X                if (*cp == '\0')
	X                    continue;
	X                (void)strncpy(_res.defdname, cp, sizeof(_res.defdname));
	X                _res.defdname[sizeof(_res.defdname) - 1] = '\0';
	X                if ((cp = index(_res.defdname, '\n')) != NULL)
	X                    *cp = '\0';
	X                continue;
	X            }
	X            /* read nameservers to query */
	X            if (!strncmp(buf, "nameserver", 
	X               sizeof("nameserver") - 1) && (n < MAXNS)) {
	X                cp = buf + sizeof("nameserver") - 1;
	X                while (*cp == ' ' || *cp == '\t')
	X                    cp++;
	X                if (*cp == '\0')
	X                    continue;
	X                _res.nsaddr_list[n].sin_addr.s_addr = inet_addr(cp);
	X                if (_res.nsaddr_list[n].sin_addr.s_addr == (unsigned)-1) 
	X                    _res.nsaddr_list[n].sin_addr.s_addr = INADDR_ANY;
	X                _res.nsaddr_list[n].sin_family = AF_INET;
	X                _res.nsaddr_list[n].sin_port = htons(NAMESERVER_PORT);
	X                if ( ++n >= MAXNS) { 
	X                    n = MAXNS;
	X#ifdef DEBUG
	X                    if ( _res.options & RES_DEBUG )
	X                        printf("MAXNS reached, reading resolv.conf\n");
	X#endif DEBUG
	X                }
	X                continue;
	X            }
	X        }
	X        if ( n > 1 ) 
	X            _res.nscount = n;
	X        (void) fclose(fp);
	X    }
	X    if (_res.defdname[0] == 0) {
	X        if (gethostname(buf, sizeof(_res.defdname)) == 0 &&
	X           (cp = index(buf, '.')))
	X             (void)strcpy(_res.defdname, cp + 1);
	X    }
	X
	X    /* Allow user to override the local domain definition */
	X    if ((cp = getenv("LOCALDOMAIN")) != NULL)
	X        (void)strncpy(_res.defdname, cp, sizeof(_res.defdname));
	X
	X    /* find components of local domain that might be searched */
	X    pp = _res.dnsrch;
	X    *pp++ = _res.defdname;
	X    for (cp = _res.defdname, n = 0; *cp; cp++)
	X	if (*cp == '.')
	X	    n++;
	X    cp = _res.defdname;
	X    for (; n >= LOCALDOMAINPARTS && pp < _res.dnsrch + MAXDNSRCH; n--) {
	X	cp = index(cp, '.');
	X	*pp++ = ++cp;
	X    }
	X    _res.options |= RES_INIT;
	X    return(0);
	X}
SHAR_EOF
if test 4721 -ne "`wc -c < 'res_init.c'`"
then
	echo shar: "error transmitting 'res_init.c'" '(should have been 4721 characters)'
fi
fi
echo shar: "extracting 'res_mkquery.c'" '(5477 characters)'
if test -f 'res_mkquery.c'
then
	echo shar: "will not over-write existing file 'res_mkquery.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'res_mkquery.c'
	X/*
	X * Copyright (c) 1985 Regents of the University of California.
	X * All rights reserved.
	X *
	X * Redistribution and use in source and binary forms are permitted
	X * provided that this notice is preserved and that due credit is given
	X * to the University of California at Berkeley. The name of the University
	X * may not be used to endorse or promote products derived from this
	X * software without specific prior written permission. This software
	X * is provided ``as is'' without express or implied warranty.
	X */
	X
	X#if defined(LIBC_SCCS) && !defined(lint)
	Xstatic char sccsid[] = "@(#)res_mkquery.c	6.7 (Berkeley) 3/7/88";
	X#endif /* LIBC_SCCS and not lint */
	X
	X#include 
	X#include 
	X#ifdef EXOS
	X#include 
	X#endif
	X#include 
	X#include 
	X#include 
	X
	X/*
	X * Form all types of queries.
	X * Returns the size of the result or -1.
	X */
	Xres_mkquery(op, dname, class, type, data, datalen, newrr, buf, buflen)
	X	int op;			/* opcode of query */
	X	char *dname;		/* domain name */
	X	int class, type;	/* class and type of query */
	X	char *data;		/* resource record data */
	X	int datalen;		/* length of data */
	X	struct rrec *newrr;	/* new rr for modify or append */
	X	char *buf;		/* buffer to put query */
	X	int buflen;		/* size of buffer */
	X{
	X	register HEADER *hp;
	X	register char *cp;
	X	register int n;
	X	char dnbuf[MAXDNAME];
	X	char *dnptrs[10], **dpp, **lastdnptr;
	X	extern char *index();
	X
	X#ifdef DEBUG
	X	if (_res.options & RES_DEBUG)
	X		printf("res_mkquery(%d, %s, %d, %d)\n", op, dname, class, type);
	X#endif DEBUG
	X	/*
	X	 * Initialize header fields.
	X	 */
	X	hp = (HEADER *) buf;
	X	hp->id = htons(++_res.id);
	X	hp->opcode = op;
	X	hp->qr = hp->aa = hp->tc = hp->ra = 0;
	X	hp->pr = (_res.options & RES_PRIMARY) != 0;
	X	hp->rd = (_res.options & RES_RECURSE) != 0;
	X	hp->rcode = NOERROR;
	X	hp->qdcount = 0;
	X	hp->ancount = 0;
	X	hp->nscount = 0;
	X	hp->arcount = 0;
	X	cp = buf + sizeof(HEADER);
	X	buflen -= sizeof(HEADER);
	X	dpp = dnptrs;
	X	*dpp++ = buf;
	X	*dpp++ = NULL;
	X	lastdnptr = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]);
	X	/*
	X	 * If the domain name contains no dots (single label), then
	X	 * append the default domain name to the one given.
	X	 */
	X	if ((_res.options & RES_DEFNAMES) && dname != 0 && dname[0] != '\0' &&
	X	    index(dname, '.') == NULL) {
	X		if (!(_res.options & RES_INIT))
	X			if (res_init() == -1)
	X				return(-1);
	X		if (_res.defdname[0] != '\0') {
	X			(void)sprintf(dnbuf, "%s.%s", dname, _res.defdname);
	X			dname = dnbuf;
	X		}
	X	}
	X	/*
	X	 * perform opcode specific processing
	X	 */
	X	switch (op) {
	X	case QUERY:
	X		buflen -= QFIXEDSZ;
	X		if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
	X			return (-1);
	X		cp += n;
	X		buflen -= n;
	X		putshort(type, cp);
	X		cp += sizeof(u_short);
	X		putshort(class, cp);
	X		cp += sizeof(u_short);
	X		hp->qdcount = htons(1);
	X		if (op == QUERY || data == NULL)
	X			break;
	X		/*
	X		 * Make an additional record for completion domain.
	X		 */
	X		buflen -= RRFIXEDSZ;
	X		if ((n = dn_comp(data, cp, buflen, dnptrs, lastdnptr)) < 0)
	X			return (-1);
	X		cp += n;
	X		buflen -= n;
	X		putshort(T_NULL, cp);
	X		cp += sizeof(u_short);
	X		putshort(class, cp);
	X		cp += sizeof(u_short);
	X		putlong(0, cp);
	X		cp += sizeof(u_long);
	X		putshort(0, cp);
	X		cp += sizeof(u_short);
	X		hp->arcount = htons(1);
	X		break;
	X
	X	case IQUERY:
	X		/*
	X		 * Initialize answer section
	X		 */
	X		if (buflen < 1 + RRFIXEDSZ + datalen)
	X			return (-1);
	X		*cp++ = '\0';	/* no domain name */
	X		putshort(type, cp);
	X		cp += sizeof(u_short);
	X		putshort(class, cp);
	X		cp += sizeof(u_short);
	X		putlong(0, cp);
	X		cp += sizeof(u_long);
	X		putshort(datalen, cp);
	X		cp += sizeof(u_short);
	X		if (datalen) {
	X#ifdef SYS5
	X			(void)memcpy(cp, data, datalen);
	X#else
	X			bcopy(data, cp, datalen);
	X#endif
	X			cp += datalen;
	X		}
	X		hp->ancount = htons(1);
	X		break;
	X
	X#ifdef ALLOW_UPDATES
	X	/*
	X	 * For UPDATEM/UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA
	X	 * (Record to be modified is followed by its replacement in msg.)
	X	 */
	X	case UPDATEM:
	X	case UPDATEMA:
	X
	X	case UPDATED:
	X		/*
	X		 * The res code for UPDATED and UPDATEDA is the same; user
	X		 * calls them differently: specifies data for UPDATED; server
	X		 * ignores data if specified for UPDATEDA.
	X		 */
	X	case UPDATEDA:
	X		buflen -= RRFIXEDSZ + datalen;
	X		if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
	X			return (-1);
	X		cp += n;
	X		putshort(type, cp);
	X                cp += sizeof(u_short);
	X                putshort(class, cp);
	X                cp += sizeof(u_short);
	X		putlong(0, cp);
	X		cp += sizeof(u_long);
	X		putshort(datalen, cp);
	X                cp += sizeof(u_short);
	X		if (datalen) {
	X#ifdef SYS5
	X			(void)memcpy(cp, data, datalen);
	X#else
	X			bcopy(data, cp, datalen);
	X#endif
	X			cp += datalen;
	X		}
	X		if ( (op == UPDATED) || (op == UPDATEDA) ) {
	X			hp->ancount = htons(0);
	X			break;
	X		}
	X		/* Else UPDATEM/UPDATEMA, so drop into code for UPDATEA */
	X
	X	case UPDATEA:	/* Add new resource record */
	X		buflen -= RRFIXEDSZ + datalen;
	X		if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
	X			return (-1);
	X		cp += n;
	X		putshort(newrr->r_type, cp);
	X                cp += sizeof(u_short);
	X                putshort(newrr->r_class, cp);
	X                cp += sizeof(u_short);
	X		putlong(0, cp);
	X		cp += sizeof(u_long);
	X		putshort(newrr->r_size, cp);
	X                cp += sizeof(u_short);
	X		if (newrr->r_size) {
	X#ifdef SYS5
	X			(void)memcpy(cp, newrr->r_data, newrr->r_size);
	X#else
	X			bcopy(newrr->r_data, cp, newrr->r_size);
	X#endif
	X			cp += newrr->r_size;
	X		}
	X		hp->ancount = htons(0);
	X		break;
	X
	X#endif ALLOW_UPDATES
	X	}
	X	return (cp - buf);
	X}
SHAR_EOF
if test 5477 -ne "`wc -c < 'res_mkquery.c'`"
then
	echo shar: "error transmitting 'res_mkquery.c'" '(should have been 5477 characters)'
fi
fi
echo shar: "extracting 'res_query.c'" '(6927 characters)'
if test -f 'res_query.c'
then
	echo shar: "will not over-write existing file 'res_query.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'res_query.c'
	X/*
	X * Copyright (c) 1988 Regents of the University of California.
	X * All rights reserved.
	X *
	X * Redistribution and use in source and binary forms are permitted
	X * provided that this notice is preserved and that due credit is given
	X * to the University of California at Berkeley. The name of the University
	X * may not be used to endorse or promote products derived from this
	X * software without specific prior written permission. This software
	X * is provided ``as is'' without express or implied warranty.
	X */
	X
	X#if defined(LIBC_SCCS) && !defined(lint)
	Xstatic char sccsid[] = "@(#)res_query.c	5.4 (Berkeley) 4/21/88";
	X#endif /* LIBC_SCCS and not lint */
	X
	X#include 
	X#ifdef EXOS
	X#include 
	X#endif
	X#include 
	X#include 
	X#include 
	X#include 
	X#include 
	X#include 
	X#ifdef SYS5
	X#include 
	X#else
	X#include 
	X#endif
	X#ifndef EXOS
	X#include 
	X#endif
	X#include 
	X#include 
	X
	X#if PACKETSZ > 1024
	X#define MAXPACKET	PACKETSZ
	X#else
	X#define MAXPACKET	1024
	X#endif
	X
	Xextern int errno;
	Xint h_errno;
	X
	X/*
	X * Formulate a normal query, send, and await answer.
	X * Returned answer is placed in supplied buffer "answer".
	X * Perform preliminary check of answer, returning success only
	X * if no error is indicated and the answer count is nonzero.
	X * Return the size of the response on success, -1 on error.
	X * Error number is left in h_errno.
	X * Caller must parse answer and determine whether it answers the question.
	X */
	Xres_query(name, class, type, answer, anslen)
	X	char *name;		/* domain name */
	X	int class, type;	/* class and type of query */
	X	u_char *answer;		/* buffer to put answer */
	X	int anslen;		/* size of answer buffer */
	X{
	X	char buf[MAXPACKET];
	X	HEADER *hp;
	X	int n;
	X
	X	if ((_res.options & RES_INIT) == 0 && res_init() == -1)
	X		return (-1);
	X#ifdef DEBUG
	X	if (_res.options & RES_DEBUG)
	X		printf("res_query(%s, %d, %d)\n", name, class, type);
	X#endif
	X	n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0, NULL,
	X	    buf, sizeof(buf));
	X
	X	if (n <= 0) {
	X#ifdef DEBUG
	X		if (_res.options & RES_DEBUG)
	X			printf("res_query: mkquery failed\n");
	X#endif
	X		h_errno = NO_RECOVERY;
	X		return (n);
	X	}
	X	n = res_send(buf, n, answer, anslen);
	X	if (n < 0) {
	X#ifdef DEBUG
	X		if (_res.options & RES_DEBUG)
	X			printf("res_query: send error\n");
	X#endif
	X		h_errno = TRY_AGAIN;
	X		return(n);
	X	}
	X
	X	hp = (HEADER *) answer;
	X	if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
	X#ifdef DEBUG
	X		if (_res.options & RES_DEBUG)
	X			printf("rcode = %d, ancount=%d\n", hp->rcode,
	X			    ntohs(hp->ancount));
	X#endif
	X		switch (hp->rcode) {
	X			case NXDOMAIN:
	X				h_errno = HOST_NOT_FOUND;
	X				break;
	X			case SERVFAIL:
	X				h_errno = TRY_AGAIN;
	X				break;
	X			case NOERROR:
	X				h_errno = NO_DATA;
	X				break;
	X			case FORMERR:
	X			case NOTIMP:
	X			case REFUSED:
	X			default:
	X				h_errno = NO_RECOVERY;
	X				break;
	X		}
	X		return (-1);
	X	}
	X	return(n);
	X}
	X
	X/*
	X * Formulate a normal query, send, and retrieve answer in supplied buffer.
	X * Return the size of the response on success, -1 on error.
	X * If enabled, implement search rules until answer or unrecoverable failure
	X * is detected.  Error number is left in h_errno.
	X * Only useful for queries in the same name hierarchy as the local host
	X * (not, for example, for host address-to-name lookups in domain in-addr.arpa).
	X */
	Xres_search(name, class, type, answer, anslen)
	X	char *name;		/* domain name */
	X	int class, type;	/* class and type of query */
	X	u_char *answer;		/* buffer to put answer */
	X	int anslen;		/* size of answer */
	X{
	X	register char *cp, **domain;
	X	int n, ret, got_nodata = 0;
	X	char *hostalias();
	X
	X	if ((_res.options & RES_INIT) == 0 && res_init() == -1)
	X		return (-1);
	X
	X	errno = 0;
	X	h_errno = HOST_NOT_FOUND;		/* default, if we never query */
	X	for (cp = name, n = 0; *cp; cp++)
	X		if (*cp == '.')
	X			n++;
	X	if (n == 0 && (cp = hostalias(name)))
	X		return (res_query(cp, class, type, answer, anslen));
	X
	X	if ((n == 0 || *--cp != '.') && (_res.options & RES_DEFNAMES))
	X	    for (domain = _res.dnsrch; *domain; domain++) {
	X		ret = res_querydomain(name, *domain, class, type,
	X		    answer, anslen);
	X		if (ret > 0)
	X			return (ret);
	X		/*
	X		 * If no server present, give up.
	X		 * If name isn't found in this domain,
	X		 * keep trying higher domains in the search list
	X		 * (if that's enabled).
	X		 * On a NO_DATA error, keep trying, otherwise
	X		 * a wildcard entry of another type could keep us
	X		 * from finding this entry higher in the domain.
	X		 * If we get some other error (non-authoritative negative
	X		 * answer or server failure), then stop searching up,
	X		 * but try the input name below in case it's fully-qualified.
	X		 */
	X		if (errno == ECONNREFUSED) {
	X			h_errno = TRY_AGAIN;
	X			return (-1);
	X		}
	X		if (h_errno == NO_DATA)
	X			got_nodata++;
	X		if ((h_errno != HOST_NOT_FOUND && h_errno != NO_DATA) ||
	X		    (_res.options & RES_DNSRCH) == 0)
	X			break;
	X	}
	X	/*
	X	 * If the search/default failed, try the name as fully-qualified,
	X	 * but only if it contained at least one dot (even trailing).
	X	 */
	X	if (n)
	X		return (res_querydomain(name, (char *)NULL, class, type,
	X		    answer, anslen));
	X	if (got_nodata)
	X		h_errno = NO_DATA;
	X	else if (h_errno == 0)
	X		h_errno = HOST_NOT_FOUND;
	X	return (-1);
	X}
	X
	X/*
	X * Perform a call on res_query on the concatenation of name and domain,
	X * removing a trailing dot from name if domain is NULL.
	X */
	Xres_querydomain(name, domain, class, type, answer, anslen)
	X	char *name, *domain;
	X	int class, type;	/* class and type of query */
	X	u_char *answer;		/* buffer to put answer */
	X	int anslen;		/* size of answer */
	X{
	X	char nbuf[2*MAXDNAME+2];
	X	char *longname = nbuf;
	X	int n;
	X
	X#ifdef DEBUG
	X	if (_res.options & RES_DEBUG)
	X		printf("res_querydomain(%s, %s, %d, %d)\n",
	X		    name, domain, class, type);
	X#endif
	X	if (domain == NULL) {
	X		/*
	X		 * Check for trailing '.';
	X		 * copy without '.' if present.
	X		 */
	X		n = strlen(name) - 1;
	X		if (name[n] == '.' && n < sizeof(nbuf) - 1) {
	X#ifdef SYS5
	X			(void)memcpy(nbuf, name, n);
	X#else
	X			bcopy(name, nbuf, n);
	X#endif
	X			nbuf[n] = '\0';
	X		} else
	X			longname = name;
	X	} else
	X		(void)sprintf(nbuf, "%.*s.%.*s",
	X		    MAXDNAME, name, MAXDNAME, domain);
	X
	X	return (res_query(longname, class, type, answer, anslen));
	X}
	X
	Xchar *
	Xhostalias(name)
	X	register char *name;
	X{
	X	register char *C1, *C2;
	X	FILE *fp;
	X	char *file, *getenv(), *strcpy(), *strncpy();
	X	char buf[BUFSIZ];
	X	static char abuf[MAXDNAME];
	X
	X	file = getenv("HOSTALIASES");
	X	if (file == NULL || (fp = fopen(file, "r")) == NULL)
	X		return (NULL);
	X	buf[sizeof(buf) - 1] = '\0';
	X	while (fgets(buf, sizeof(buf), fp)) {
	X		for (C1 = buf; *C1 && !isspace(*C1); ++C1);
	X		if (!*C1)
	X			break;
	X		*C1 = '\0';
	X		if (!strcasecmp(buf, name)) {
	X			while (isspace(*++C1));
	X			if (!*C1)
	X				break;
	X			for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2);
	X			abuf[sizeof(abuf) - 1] = *C2 = '\0';
	X			(void)strncpy(abuf, C1, sizeof(abuf) - 1);
	X			fclose(fp);
	X			return (abuf);
	X		}
	X	}
	X	fclose(fp);
	X	return (NULL);
	X}
	X
	X
SHAR_EOF
if test 6927 -ne "`wc -c < 'res_query.c'`"
then
	echo shar: "error transmitting 'res_query.c'" '(should have been 6927 characters)'
fi
fi
echo shar: "extracting 'res_send.c'" '(9929 characters)'
if test -f 'res_send.c'
then
	echo shar: "will not over-write existing file 'res_send.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'res_send.c'
	X/*
	X * Copyright (c) 1985 Regents of the University of California.
	X * All rights reserved.
	X *
	X * Redistribution and use in source and binary forms are permitted
	X * provided that this notice is preserved and that due credit is given
	X * to the University of California at Berkeley. The name of the University
	X * may not be used to endorse or promote products derived from this
	X * software without specific prior written permission. This software
	X * is provided ``as is'' without express or implied warranty.
	X */
	X
	X#if defined(LIBC_SCCS) && !defined(lint)
	Xstatic char sccsid[] = "@(#)res_send.c	6.19 (Berkeley) 3/7/88";
	X#endif /* LIBC_SCCS and not lint */
	X
	X/*
	X * Send query to name server and wait for reply.
	X */
	X
	X#include 
	X#ifdef EXOS
	X#include 
	X#endif
	X#include 
	X#include 
	X#ifndef SYS5
	X#include 
	X#endif
	X#include 
	X#include 
	X#include 
	X#include 
	X#include 
	X
	Xextern int errno;
	X
	Xstatic int s = -1;	/* socket used for communications */
	Xstatic struct sockaddr no_addr;
	X  
	X#ifndef SYS5
	X#ifndef FD_SET
	X#define	NFDBITS		32
	X#define	FD_SETSIZE	32
	X#define	FD_SET(n, p)	((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
	X#define	FD_CLR(n, p)	((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
	X#define	FD_ISSET(n, p)	((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
	X#define FD_ZERO(p)	bzero((char *)(p), sizeof(*(p)))
	X#endif
	X#endif
	X
	X#define KEEPOPEN (RES_USEVC|RES_STAYOPEN)
	X
	Xres_send(buf, buflen, answer, anslen)
	X	char *buf;
	X	int buflen;
	X	char *answer;
	X	int anslen;
	X{
	X	register int n;
	X	int retry, v_circuit, resplen, ns;
	X	int gotsomewhere = 0, connected = 0;
	X	u_short id, len;
	X	char *cp;
	X	HEADER *hp = (HEADER *) buf;
	X	HEADER *anhp = (HEADER *) answer;
	X#if defined(EXOS) || defined(MASSCOMP)
	X	int timeout, dsmask;
	X	struct sockaddr_in there;
	X#endif
	X#ifndef SYS5
	X	struct timeval timeout;
	X	fd_set dsmask;
	X	struct iovec iov[2];
	X#endif
	X	int terrno = ETIMEDOUT;
	X	char junk[512];
	X#ifdef EXOS
	X	there.sin_family = (u_short)AF_INET;
	X	there.sin_port = htons(NAMESERVER_PORT);
	X#endif
	X#ifdef DEBUG
	X	if (_res.options & RES_DEBUG) {
	X		printf("res_send()\n");
	X		p_query(buf);
	X	}
	X#endif DEBUG
	X	if (!(_res.options & RES_INIT))
	X		if (res_init() == -1) {
	X			return(-1);
	X		}
	X	v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
	X	id = hp->id;
	X	/*
	X	 * Send request, RETRY times, or until successful
	X	 */
	X	for (retry = _res.retry; retry > 0; retry--) {
	X	   for (ns = 0; ns < _res.nscount; ns++) {
	X#ifdef DEBUG
	X		if (_res.options & RES_DEBUG)
	X			printf("Querying server (# %d) address = %s\n", ns+1,
	X			      inet_ntoa(_res.nsaddr_list[ns].sin_addr));
	X#endif DEBUG
	X		if (v_circuit) {
	X			int truncated = 0;
	X
	X			/*
	X			 * Use virtual circuit.
	X			 */
	X			if (s < 0) {
	X#ifdef EXOS
	X				s = socket(SOCK_STREAM, 0, 0, 0);
	X#else
	X				s = socket(AF_INET, SOCK_STREAM, 0);
	X#endif
	X				if (s < 0) {
	X					terrno = errno;
	X#ifdef DEBUG
	X					if (_res.options & RES_DEBUG)
	X					    perror("socket failed");
	X#endif DEBUG
	X					continue;
	X				}
	X#ifdef EXOS
	X				if (connect(s,&(_res.nsaddr_list[ns])) < 0){
	X#else
	X				if (connect(s, &(_res.nsaddr_list[ns]),
	X				   sizeof(struct sockaddr)) < 0) {
	X#endif
	X					terrno = errno;
	X#ifdef DEBUG
	X					if (_res.options & RES_DEBUG)
	X					    perror("connect failed");
	X#endif DEBUG
	X					(void) close(s);
	X					s = -1;
	X					continue;
	X				}
	X			}
	X			/*
	X			 * Send length & message
	X			 */
	X			len = htons((u_short)buflen);
	X#ifdef SYS5
	X			if (write(s,(char *)&len,sizeof(len)) < sizeof(len) ||
	X			    write(s,buf,buflen) < buflen) {
	X#else
	X			iov[0].iov_base = (caddr_t)&len;
	X			iov[0].iov_len = sizeof(len);
	X			iov[1].iov_base = buf;
	X			iov[1].iov_len = buflen;
	X			if (writev(s, iov, 2) != sizeof(len) + buflen) {
	X#endif
	X				terrno = errno;
	X#ifdef DEBUG
	X				if (_res.options & RES_DEBUG)
	X					perror("write failed");
	X#endif DEBUG
	X				(void) close(s);
	X				s = -1;
	X				continue;
	X			}
	X			/*
	X			 * Receive length & response
	X			 */
	X			cp = answer;
	X			len = sizeof(short);
	X			while (len != 0 &&
	X			    (n = read(s, (char *)cp, (int)len)) > 0) {
	X				cp += n;
	X				len -= n;
	X			}
	X			if (n <= 0) {
	X				terrno = errno;
	X#ifdef DEBUG
	X				if (_res.options & RES_DEBUG)
	X					perror("read failed");
	X#endif DEBUG
	X				(void) close(s);
	X				s = -1;
	X				continue;
	X			}
	X			cp = answer;
	X			if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
	X#ifdef DEBUG
	X				if (_res.options & RES_DEBUG)
	X					fprintf(stderr, "response truncated\n");
	X#endif DEBUG
	X				len = anslen;
	X				truncated = 1;
	X			} else
	X				len = resplen;
	X			while (len != 0 &&
	X			   (n = read(s, (char *)cp, (int)len)) > 0) {
	X				cp += n;
	X				len -= n;
	X			}
	X			if (n <= 0) {
	X				terrno = errno;
	X#ifdef DEBUG
	X				if (_res.options & RES_DEBUG)
	X					perror("read failed");
	X#endif DEBUG
	X				(void) close(s);
	X				s = -1;
	X				continue;
	X			}
	X			if (truncated) {
	X				/*
	X				 * Flush rest of answer
	X				 * so connection stays in synch.
	X				 */
	X				anhp->tc = 1;
	X				len = resplen - anslen;
	X				while (len != 0) {
	X					n = (len > sizeof(junk) ?
	X					    sizeof(junk) : len);
	X					if ((n = read(s, junk, n)) > 0)
	X						len -= n;
	X					else
	X						break;
	X				}
	X			}
	X		} else {
	X			/*
	X			 * Use datagrams.
	X			 */
	X			if (s < 0)
	X#ifdef EXOS
	X				s = socket(SOCK_DGRAM, 0, 0, 0);
	X#else
	X				s = socket(AF_INET, SOCK_DGRAM, 0);
	X#endif
	X#if	BSD >= 43
	X			if (_res.nscount == 1 || retry == _res.retry) {
	X				/*
	X				 * Don't use connect if we might
	X				 * still receive a response
	X				 * from another server.
	X				 */
	X				if (connected == 0) {
	X#ifdef EXOS
	X				if (connect(s,&(_res.nsaddr_list[ns])) < 0){
	X#else
	X					if (connect(s, &_res.nsaddr_list[ns],
	X					    sizeof(struct sockaddr)) < 0) {
	X#endif
	X#ifdef DEBUG
	X						if (_res.options & RES_DEBUG)
	X							perror("connect");
	X#endif DEBUG
	X						continue;
	X					}
	X					connected = 1;
	X				}
	X#ifdef EXOS
	X				errno = 0;
	X#ifdef SYS5
	X			        (void)memcpy(&there,&_res.nsaddr_list[ns],
	X#else
	X			        bcopy(&_res.nsaddr_list[ns],&there,
	X#endif
	X							sizeof(there));
	X				send(s,&there, buf, buflen);
	X				if (errno != 0) {
	X#else
	X				if (send(s, buf, buflen, 0) != buflen) {
	X#endif
	X#ifdef DEBUG
	X					if (_res.options & RES_DEBUG)
	X						perror("send");
	X#endif DEBUG
	X					continue;
	X				}
	X			} else
	X#endif BSD
	X#ifdef EXOS
	X			errno = 0;
	X#ifdef SYS5
	X			(void)memcpy(&there,&_res.nsaddr_list[ns],
	X								sizeof(there));
	X#else
	X			bcopy(&_res.nsaddr_list[ns],&there,sizeof(there));
	X#endif
	X			send(s,&there, buf, buflen);
	X			if (errno != 0){
	X#else
	X			if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns],
	X			    sizeof(struct sockaddr)) != buflen) {
	X#endif
	X#ifdef DEBUG
	X				if (_res.options & RES_DEBUG)
	X#ifdef EXOS
	X					perror("send");
	X#else
	X					perror("sendto");
	X#endif
	X#endif DEBUG
	X				continue;
	X			}
	X
	X			/*
	X			 * Wait for reply
	X			 */
	X#if defined(EXOS) || defined(MASSCOMP)
	X			timeout = ((_res.retrans << (_res.retry - retry))
	X				/ _res.nscount) * 1000;
	X			if (timeout <= 0) timeout = 1000;
	X#else
	X			timeout.tv_sec = (_res.retrans << (_res.retry - retry))
	X				/ _res.nscount;
	X			if (timeout.tv_sec <= 0)
	X				timeout.tv_sec = 1;
	X			timeout.tv_usec = 0;
	X#endif
	Xwait:
	X#if defined(EXOS) || defined(MASSCOMP)
	X			dsmask = (1 << s) ;
	X			n = select(32,&dsmask,NULL,timeout);
	X#else
	X			FD_ZERO(&dsmask);
	X			FD_SET(s, &dsmask);
	X			n = select(s+1, &dsmask, (fd_set *)NULL,
	X						(fd_set *)NULL, &timeout);
	X#endif
	X			if (n < 0) {
	X#ifdef DEBUG
	X				if (_res.options & RES_DEBUG)
	X					perror("select");
	X#endif DEBUG
	X				continue;
	X			}
	X			if (n == 0) {
	X				/*
	X				 * timeout
	X				 */
	X#ifdef DEBUG
	X				if (_res.options & RES_DEBUG)
	X					printf("timeout\n");
	X#endif DEBUG
	X				/*
	X				 * Disconnect if we want to listen
	X				 * for responses from more than one server.
	X				 */
	X				if (_res.nscount > 1 && connected) {
	X#ifdef EXOS
	X#ifdef SYS5
	X					memset(&no_addr,'\0',sizeof(no_addr));
	X#else
	X					bzero(&no_addr,sizeof(no_addr));
	X#endif
	X					(void) connect(s, &no_addr);
	X#else
	X					(void) connect(s, &no_addr,
	X					    sizeof(no_addr));
	X#endif
	X					connected = 0;
	X				}
	X				gotsomewhere = 1;
	X				continue;
	X			}
	X#ifdef EXOS
	X#ifdef SYS5
	X			(void) memcpy(&there,&_res.nsaddr_list[ns],
	X								sizeof(there));
	X#else
	X			bcopy(&_res.nsaddr_list[ns],&there,sizeof(there));
	X#endif
	X			if((resplen = receive(s,&there,answer,anslen)) <= 0) {
	X#else
	X			if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
	X#endif
	X#ifdef DEBUG
	X				if (_res.options & RES_DEBUG)
	X#ifdef EXOS
	X					perror("receive");
	X#else
	X					perror("recvfrom");
	X#endif
	X#endif DEBUG
	X				continue;
	X			}
	X			gotsomewhere = 1;
	X			if (id != anhp->id) {
	X				/*
	X				 * response from old query, ignore it
	X				 */
	X#ifdef DEBUG
	X				if (_res.options & RES_DEBUG) {
	X					printf("old answer:\n");
	X					p_query(answer);
	X				}
	X#endif DEBUG
	X				goto wait;
	X			}
	X			if (!(_res.options & RES_IGNTC) && anhp->tc) {
	X				/*
	X				 * get rest of answer
	X				 */
	X#ifdef DEBUG
	X				if (_res.options & RES_DEBUG)
	X					printf("truncated answer\n");
	X#endif DEBUG
	X				(void) close(s);
	X				s = -1;
	X				/*
	X				 * retry decremented on continue
	X				 * to desired starting value
	X				 */
	X				retry = _res.retry + 1;
	X				v_circuit = 1;
	X				continue;
	X			}
	X		}
	X#ifdef DEBUG
	X		if (_res.options & RES_DEBUG) {
	X			printf("got answer:\n");
	X			p_query(answer);
	X		}
	X#endif DEBUG
	X		/*
	X		 * We are going to assume that the first server is preferred
	X		 * over the rest (i.e. it is on the local machine) and only
	X		 * keep that one open.
	X		 */
	X		if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) {
	X			return (resplen);
	X		} else {
	X			(void) close(s);
	X			s = -1;
	X			return (resplen);
	X		}
	X	   }
	X	}
	X	if (s >= 0) {
	X		(void) close(s);
	X		s = -1;
	X	}
	X	if (v_circuit == 0)
	X		if (gotsomewhere == 0)
	X			errno = ECONNREFUSED;
	X		else
	X			errno = ETIMEDOUT;
	X	else
	X		errno = terrno;
	X	return (-1);
	X}
	X
	X/*
	X * This routine is for closing the socket if a virtual circuit is used and
	X * the program wants to close it.  This provides support for endhostent()
	X * which expects to close the socket.
	X *
	X * This routine is not expected to be user visible.
	X */
	X_res_close()
	X{
	X	if (s != -1) {
	X		(void) close(s);
	X		s = -1;
	X	}
	X}
SHAR_EOF
if test 9929 -ne "`wc -c < 'res_send.c'`"
then
	echo shar: "error transmitting 'res_send.c'" '(should have been 9929 characters)'
fi
fi
exit 0
#	End of shell archive
The MASSCOMP USERS' SOCIETY newsgroup is comp.sys.masscomp.
Articles to: masscomp@soma.bcm.tmc.edu or uunet!soma.bcm.tmc.edu!masscomp
Administrative stuff: masscomp-request@soma.bcm.tmc.edu
Stan Barber, Moderator