Article View: comp.sys.masscomp
Article #157resolver library for MASSCOMP (part 6 of 7)
From: Stan Barber
Date: Mon, 11 Jul 1988 23:51
Date: Mon, 11 Jul 1988 23:51
1158 lines
32839 bytes
32839 bytes
#! /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 <sys/types.h>
X#ifdef EXOS
X#include <exos/misc.h>
X#endif
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <stdio.h>
X#include <arpa/nameser.h>
X#include <resolv.h>
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 <stdio.h>
X#include <sys/types.h>
X#ifdef EXOS
X#include <exos/misc.h>
X#endif
X#include <netinet/in.h>
X#include <arpa/nameser.h>
X#include <resolv.h>
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 <sys/param.h>
X#ifdef EXOS
X#include <exos/misc.h>
X#endif
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <ctype.h>
X#include <netdb.h>
X#include <stdio.h>
X#include <errno.h>
X#ifdef SYS5
X#include <string.h>
X#else
X#include <strings.h>
X#endif
X#ifndef EXOS
X#include <arpa/inet.h>
X#endif
X#include <arpa/nameser.h>
X#include <resolv.h>
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 <sys/param.h>
X#ifdef EXOS
X#include <exos/misc.h>
X#endif
X#include <sys/time.h>
X#include <sys/socket.h>
X#ifndef SYS5
X#include <sys/uio.h>
X#endif
X#include <netinet/in.h>
X#include <stdio.h>
X#include <errno.h>
X#include <arpa/nameser.h>
X#include <resolv.h>
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
Technical Details
Message-ID:
<1156@gazette.bcm.tmc.edu>Path:
arc1-ca.pugleaf.net!utzoo!attcan!uunet!husc6!rice!bcm!soma!masscomp-requestShow Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!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