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#includeX#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