diff options
Diffstat (limited to 'arlib/arlib.c')
-rw-r--r-- | arlib/arlib.c | 1056 |
1 files changed, 1056 insertions, 0 deletions
diff --git a/arlib/arlib.c b/arlib/arlib.c new file mode 100644 index 000000000000..3d76e5749336 --- /dev/null +++ b/arlib/arlib.c @@ -0,0 +1,1056 @@ +/* + * arlib.c (C)opyright 1993 Darren Reed. All rights reserved. + * This file may not be distributed without the author's permission in any + * shape or form. The author takes no responsibility for any damage or loss + * of property which results from the use of this software. + */ +#ifndef lint +static char sccsid[] = "@(#)arlib.c 1.9 6/5/93 (C)opyright 1992 Darren \ +Reed. ASYNC DNS"; +#endif + +#include <stdio.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include "netdb.h" +#include "arpa/nameser.h" +#include <resolv.h> +#include "arlib.h" +#include "arplib.h" + +extern int errno, h_errno; +static char ar_hostbuf[65], ar_domainname[65]; +static char ar_dot[] = "."; +static int ar_resfd = -1, ar_vc = 0; +static struct reslist *ar_last, *ar_first; + +/* + * Statistics structure. + */ +static struct resstats { + int re_errors; + int re_nu_look; + int re_na_look; + int re_replies; + int re_requests; + int re_resends; + int re_sent; + int re_timeouts; +} ar_reinfo; + +static int do_query_name(/* struct resinfo *, char *, struct reslist * */); +static int do_query_number(/* struct resinfo *, char *, struct reslist * */); +static int ar_resend_query(/* struct reslist * */); + +/* + * ar_init + * + * Initializes the various ARLIB internal varilables and related DNS + * options for res_init(). + * + * Returns 0 or the socket opened for use with talking to name servers + * if 0 is passed or ARES_INITSOCK is set. + */ +int ar_init(op) +int op; +{ + int ret = 0; + + if (op & ARES_INITLIST) + { + bzero(&ar_reinfo, sizeof(ar_reinfo)); + ar_first = ar_last = NULL; + } + + if (op & ARES_CALLINIT && !(_res.options & RES_INIT)) + { + ret = res_init(); + (void)strcpy(ar_domainname, ar_dot); + (void)strncat(ar_domainname, _res.defdname, + sizeof(ar_domainname)-2); + } + + if (op & ARES_INITSOCK) + ret = ar_resfd = ar_open(); + + if (op & ARES_INITDEBG) + _res.options |= RES_DEBUG; + + if (op == 0) + ret = ar_resfd; + + return ret; +} + + +/* + * ar_open + * + * Open a socket to talk to a name server with. + * Check _res.options to see if we use a TCP or UDP socket. + */ +int ar_open() +{ + if (ar_resfd == -1) + { + if (_res.options & RES_USEVC) + { + struct sockaddr_in *sip; + int i; + + sip = _res.NS_ADDR_LIST; /* was _res.nsaddr_list */ + ar_vc = 1; + ar_resfd = socket(AF_INET, SOCK_STREAM, 0); + + /* + * Try each name server listed in sequence until we + * succeed or run out. + */ + while (connect(ar_resfd, (struct sockaddr *)sip++, + sizeof(struct sockaddr))) + { + (void)close(ar_resfd); + ar_resfd = -1; + if (i >= _res.nscount) + break; + ar_resfd = socket(AF_INET, SOCK_STREAM, 0); + } + } + else + ar_resfd = socket(AF_INET, SOCK_DGRAM, 0); + } + if (ar_resfd >= 0) + { /* Need one of these two here - and it MUST work!! */ + int flags; + + if ((flags = fcntl(ar_resfd, F_GETFL, 0)) != -1) +#ifdef O_NONBLOCK + if (fcntl(ar_resfd, F_SETFL, flags|O_NONBLOCK) == -1) +#else +# ifdef O_NDELAY + if (fcntl(ar_resfd, F_SETFL, flags|O_NDELAY) == -1) +# else +# ifdef FNDELAY + if (fcntl(ar_resfd, F_SETFL, flags|FNDELAY) == -1) +# endif +# endif +#endif + { + (void)close(ar_resfd); + ar_resfd = -1; + } + } + return ar_resfd; +} + + +/* + * ar_close + * + * Closes and flags the ARLIB socket as closed. + */ +void ar_close() +{ + (void)close(ar_resfd); + ar_resfd = -1; + return; +} + + +/* + * ar_add_request + * + * Add a new DNS query to the end of the query list. + */ +static int ar_add_request(new) +struct reslist *new; +{ + if (!new) + return -1; + if (!ar_first) + ar_first = ar_last = new; + else { + ar_last->re_next = new; + ar_last = new; + } + new->re_next = NULL; + ar_reinfo.re_requests++; + return 0; +} + + +/* + * ar_remrequest + * + * Remove a request from the list. This must also free any memory that has + * been allocated for temporary storage of DNS results. + * + * Returns -1 if there are anyy problems removing the requested structure + * or 0 if the remove is successful. + */ +static int ar_remrequest(old) +struct reslist *old; +{ + register struct reslist *rptr, *r2ptr; + register char **s; + + if (!old) + return -1; + for (rptr = ar_first, r2ptr = NULL; rptr; rptr = rptr->re_next) + { + if (rptr == old) + break; + r2ptr = rptr; + } + + if (!rptr) + return -1; + if (rptr == ar_first) + ar_first = ar_first->re_next; + else if (rptr == ar_last) + { + if (ar_last = r2ptr) + ar_last->re_next = NULL; + } + else + r2ptr->re_next = rptr->re_next; + + if (!ar_first) + ar_last = ar_first; + +#ifdef ARLIB_DEBUG + ar_dump_hostent("ar_remrequest:", rptr->re_he); +#endif + + if (rptr->re_he.h_name) + (void)free(rptr->re_he.h_name); + if (s = rptr->re_he.h_aliases) + for (; *s; s++) + (void)free(*s); + if (rptr->re_rinfo.ri_ptr) + (void)free(rptr->re_rinfo.ri_ptr); + (void)free(rptr); + + return 0; +} + + +/* + * ar_make_request + * + * Create a DNS query recorded for the request being made and place it on the + * current list awaiting replies. Initialization of the record with set + * values should also be done. + */ +static struct reslist *ar_make_request(resi) +register struct resinfo *resi; +{ + register struct reslist *rptr; + register struct resinfo *rp; + + rptr = (struct reslist *)calloc(1, sizeof(struct reslist)); + rp = &rptr->re_rinfo; + + rptr->re_next = NULL; /* where NULL is non-zero ;) */ + rptr->re_sentat = time(NULL); + rptr->re_retries = _res.retry; + rptr->re_sends = 1; + rptr->re_resend = 1; + rptr->re_timeout = rptr->re_sentat + _res.retrans; + rptr->re_he.h_name = NULL; + rptr->re_he.h_addrtype = AF_INET; + rptr->re_he.h_aliases[0] = NULL; + rp->ri_ptr = resi->ri_ptr; + rp->ri_size = resi->ri_size; + + (void)ar_add_request(rptr); + + return rptr; +} + + +/* + * ar_timeout + * + * Remove queries from the list which have been there too long without + * being resolved. + */ +long ar_timeout(now, info, size) +time_t now; +char *info; +int size; +{ + register struct reslist *rptr, *r2ptr; + register long next = 0; + + for (rptr = ar_first, r2ptr = NULL; rptr; rptr = r2ptr) + { + r2ptr = rptr->re_next; + if (now >= rptr->re_timeout) + { + /* + * If the timeout for the query has been exceeded, + * then resend the query if we still have some + * 'retry credit' and reset the timeout. If we have + * used it all up, then remove the request. + */ + if (--rptr->re_retries <= 0) + { + ar_reinfo.re_timeouts++; + if (info && rptr->re_rinfo.ri_ptr) + bcopy(rptr->re_rinfo.ri_ptr, info, + MIN(rptr->re_rinfo.ri_size, + size)); + (void)ar_remrequest(rptr); + return now; + } + else + { + rptr->re_sends++; + rptr->re_sentat = now; + rptr->re_timeout = now + _res.retrans; + (void)ar_resend_query(rptr); + } + } + if (!next || rptr->re_timeout < next) + next = rptr->re_timeout; + } + return next; +} + + +/* + * ar_send_res_msg + * + * When sending queries to nameservers listed in the resolv.conf file, + * don't send a query to every one, but increase the number sent linearly + * to match the number of resends. This increase only occurs if there are + * multiple nameserver entries in the resolv.conf file. + * The return value is the number of messages successfully sent to + * nameservers or -1 if no successful sends. + */ +static int ar_send_res_msg(msg, len, rcount) +char *msg; +int len, rcount; +{ + register int i; + int sent = 0; + + if (!msg) + return -1; + + rcount = (_res.nscount > rcount) ? rcount : _res.nscount; + if (_res.options & RES_PRIMARY) + rcount = 1; + + if (ar_vc) + { + ar_reinfo.re_sent++; + sent++; + if (write(ar_resfd, msg, len) == -1) + { + int errtmp = errno; + (void)close(ar_resfd); + errno = errtmp; + ar_resfd = -1; + } + } + else + for (i = 0; i < rcount; i++) + { + if (sendto(ar_resfd, msg, len, 0, + (struct sockaddr *)&(_res.NS_ADDR_LIST[i]), + sizeof(struct sockaddr_in)) == len) + { + ar_reinfo.re_sent++; + sent++; + } + } + return (sent) ? sent : -1; +} + + +/* + * ar_find_id + * + * find a dns query record by the id (id is determined by dn_mkquery) + */ +static struct reslist *ar_find_id(id) +int id; +{ + register struct reslist *rptr; + + for (rptr = ar_first; rptr; rptr = rptr->re_next) + if (rptr->re_id == id) + return rptr; + return NULL; +} + + +/* + * ar_delete + * + * Delete a request from the waiting list if it has a data pointer which + * matches the one passed. + */ +int ar_delete(ptr, size) +char *ptr; +int size; +{ + register struct reslist *rptr; + register struct reslist *r2ptr; + int removed = 0; + + for (rptr = ar_first; rptr; rptr = r2ptr) + { + r2ptr = rptr->re_next; + if (rptr->re_rinfo.ri_ptr && ptr && size && + bcmp(rptr->re_rinfo.ri_ptr, ptr, size) == 0) + { + (void)ar_remrequest(rptr); + removed++; + } + } + return removed; +} + + +/* + * ar_query_name + * + * generate a query based on class, type and name. + */ +static int ar_query_name(name, class, type, rptr) +char *name; +int class, type; +struct reslist *rptr; +{ + static char buf[MAXPACKET]; + int r,s,a; + HEADER *hptr; + + bzero(buf, sizeof(buf)); + r = res_mkquery(QUERY, name, class, type, NULL, 0, NULL, + buf, sizeof(buf)); + if (r <= 0) + { + h_errno = NO_RECOVERY; + return r; + } + hptr = (HEADER *)buf; + rptr->re_id = ntohs(hptr->id); + + s = ar_send_res_msg(buf, r, rptr->re_sends); + + if (s == -1) + { + h_errno = TRY_AGAIN; + return -1; + } + else + rptr->re_sent += s; + return 0; +} + + +/* + * ar_gethostbyname + * + * Replacement library function call to gethostbyname(). This one, however, + * doesn't return the record being looked up but just places the query in the + * queue to await answers. + */ +int ar_gethostbyname(name, info, size) +char *name; +char *info; +int size; +{ + char host[65]; + struct resinfo resi; + register struct resinfo *rp = &resi; + + if (size && info) + { + rp->ri_ptr = (char *)malloc(size); + bcopy(info, rp->ri_ptr, size); + rp->ri_size = size; + } + else + bzero((char *)rp, sizeof(resi)); + ar_reinfo.re_na_look++; + (void)strncpy(host, name, 64); + host[64] = '\0'; + + return (do_query_name(rp, host, NULL)); +} + + +static int do_query_name(resi, name, rptr) +struct resinfo *resi; +char *name; +register struct reslist *rptr; +{ + char hname[65]; + int len; + + len = strlen((char *)strncpy(hname, name, sizeof(hname)-1)); + + if (rptr && (hname[len-1] != '.')) + { + (void)strncat(hname, ar_dot, sizeof(hname)-len-1); + /* + * NOTE: The logical relationship between DNSRCH and DEFNAMES + * is implies. ie no DEFNAES, no DNSRCH. + */ + if (_res.options & (RES_DEFNAMES|RES_DNSRCH) == + (RES_DEFNAMES|RES_DNSRCH)) + { + if (_res.dnsrch[rptr->re_srch]) + (void)strncat(hname, _res.dnsrch[rptr->re_srch], + sizeof(hname) - ++len -1); + } + else if (_res.options & RES_DEFNAMES) + (void)strncat(hname, ar_domainname, sizeof(hname) - len -1); + } + + /* + * Store the name passed as the one to lookup and generate other host + * names to pass onto the nameserver(s) for lookups. + */ + if (!rptr) + { + rptr = ar_make_request(resi); + rptr->re_type = T_A; + (void)strncpy(rptr->re_name, name, sizeof(rptr->re_name)-1); + } + return (ar_query_name(hname, C_IN, T_A, rptr)); +} + + +/* + * ar_gethostbyaddr + * + * Generates a query for a given IP address. + */ +int ar_gethostbyaddr(addr, info, size) +char *addr; +char *info; +int size; +{ + struct resinfo resi; + register struct resinfo *rp = &resi; + + if (size && info) + { + rp->ri_ptr = (char *)malloc(size); + bcopy(info, rp->ri_ptr, size); + rp->ri_size = size; + } + else + bzero((char *)rp, sizeof(resi)); + ar_reinfo.re_nu_look++; + return (do_query_number(rp, addr, NULL)); +} + + +/* + * do_query_number + * + * Use this to do reverse IP# lookups. + */ +static int do_query_number(resi, numb, rptr) +struct resinfo *resi; +char *numb; +register struct reslist *rptr; +{ + register unsigned char *cp; + static char ipbuf[32]; + + /* + * Generate name in the "in-addr.arpa" domain. No addings bits to this + * name to get more names to query!. + */ + cp = (unsigned char *)numb; + (void)sprintf(ipbuf,"%u.%u.%u.%u.in-addr.arpa.", + (unsigned int)(cp[3]), (unsigned int)(cp[2]), + (unsigned int)(cp[1]), (unsigned int)(cp[0])); + + if (!rptr) + { + rptr = ar_make_request(resi); + rptr->re_type = T_PTR; + rptr->re_he.h_length = sizeof(struct in_addr); + bcopy(numb, (char *)&rptr->re_addr, rptr->re_he.h_length); + bcopy(numb, (char *)&rptr->re_he.h_addr_list[0].s_addr, + rptr->re_he.h_length); + } + return (ar_query_name(ipbuf, C_IN, T_PTR, rptr)); +} + + +/* + * ar_resent_query + * + * resends a query. + */ +static int ar_resend_query(rptr) +struct reslist *rptr; +{ + if (!rptr->re_resend) + return -1; + + switch(rptr->re_type) + { + case T_PTR: + ar_reinfo.re_resends++; + return do_query_number(NULL, &rptr->re_addr, rptr); + case T_A: + ar_reinfo.re_resends++; + return do_query_name(NULL, rptr->re_name, rptr); + default: + break; + } + + return -1; +} + + +/* + * ar_procanswer + * + * process an answer received from a nameserver. + */ +static int ar_procanswer(rptr, hptr, buf, eob) +struct reslist *rptr; +char *buf, *eob; +HEADER *hptr; +{ + char *cp, **alias, *s; + int class, type, dlen, len, ans = 0, n, i; + u_int32_t ttl, dr, *adr; + struct hent *hp; + + cp = buf + sizeof(HEADER); + adr = (u_int32_t *)rptr->re_he.h_addr_list; + + while (*adr) + adr++; + + alias = rptr->re_he.h_aliases; + while (*alias) + alias++; + + hp = &rptr->re_he; + + + /* + * Skip over the original question. + */ + while (hptr->qdcount-- > 0) + cp += dn_skipname(cp, eob) + QFIXEDSZ; + /* + * proccess each answer sent to us. blech. + */ + while (hptr->ancount-- > 0 && cp < eob) { + n = dn_expand(buf, eob, cp, ar_hostbuf, sizeof(ar_hostbuf)); + cp += n; + if (n <= 0) + return ans; + + ans++; + /* + * 'skip' past the general dns crap (ttl, class, etc) to get + * the pointer to the right spot. Some of thse are actually + * useful so its not a good idea to skip past in one big jump. + */ + type = (int)_getshort(cp); + cp += sizeof(short); + class = (int)_getshort(cp); + cp += sizeof(short); + ttl = (u_int32_t)_getlong(cp); + cp += sizeof(u_int32_t); + dlen = (int)_getshort(cp); + cp += sizeof(short); + rptr->re_type = type; + + switch(type) + { + case T_A : + rptr->re_he.h_length = dlen; + if (ans == 1) + rptr->re_he.h_addrtype=(class == C_IN) ? + AF_INET : AF_UNSPEC; + if (dlen != sizeof(dr)) + { + h_errno = TRY_AGAIN; + continue; + } + bcopy(cp, &dr, dlen); + *adr++ = dr; + *adr = 0; + cp += dlen; + len = strlen(ar_hostbuf); + if (!rptr->re_he.h_name) + { + rptr->re_he.h_name = (char *)malloc(len+1); + if (!rptr->re_he.h_name) + break; + (void)strcpy(rptr->re_he.h_name, ar_hostbuf); + } + break; + case T_PTR : + if ((n = dn_expand(buf, eob, cp, ar_hostbuf, + sizeof(ar_hostbuf) )) < 0) + { + cp += n; + continue; + } + cp += n; + len = strlen(ar_hostbuf)+1; + /* + * copy the returned hostname into the host name + * or alias field if there is a known hostname + * already. + */ + if (!rptr->re_he.h_name) + { + rptr->re_he.h_name = (char *)malloc(len); + if (!rptr->re_he.h_name) + break; + (void)strcpy(rptr->re_he.h_name, ar_hostbuf); + } + else + { + *alias = (char *)malloc(len); + if (!*alias) + return -1; + (void)strcpy(*alias++, ar_hostbuf); + *alias = NULL; + } + break; + case T_CNAME : + cp += dlen; + if (alias >= &(rptr->re_he.h_aliases[MAXALIASES-1])) + continue; + n = strlen(ar_hostbuf)+1; + *alias = (char *)malloc(n); + if (!*alias) + return -1; + (void)strcpy(*alias++, ar_hostbuf); + *alias = NULL; + break; + default : + break; + } + } + + return ans; +} + + +/* + * ar_answer + * + * Get an answer from a DNS server and process it. If a query is found to + * which no answer has been given to yet, copy its 'info' structure back + * to where "reip" points and return a pointer to the hostent structure. + */ +struct hostent *ar_answer(reip, size) +char *reip; +int size; +{ + static char ar_rcvbuf[sizeof(HEADER) + MAXPACKET]; + static struct hostent ar_host; + + register HEADER *hptr; + register struct reslist *rptr = NULL; + register struct hostent *hp; + register char **s; + unsigned long *adr; + int rc, i, n, a; + + rc = recv(ar_resfd, ar_rcvbuf, sizeof(ar_rcvbuf), 0); + if (rc <= 0) + goto getres_err; + + ar_reinfo.re_replies++; + hptr = (HEADER *)ar_rcvbuf; + /* + * convert things to be in the right order. + */ + hptr->id = ntohs(hptr->id); + hptr->ancount = ntohs(hptr->ancount); + hptr->arcount = ntohs(hptr->arcount); + hptr->nscount = ntohs(hptr->nscount); + hptr->qdcount = ntohs(hptr->qdcount); + /* + * response for an id which we have already received an answer for + * just ignore this response. + */ + rptr = ar_find_id(hptr->id); + if (!rptr) + goto getres_err; + + if ((hptr->rcode != NOERROR) || (hptr->ancount == 0)) + { + switch (hptr->rcode) + { + case NXDOMAIN: + h_errno = HOST_NOT_FOUND; + break; + case SERVFAIL: + h_errno = TRY_AGAIN; + break; + case NOERROR: + h_errno = NO_DATA; + break; + case FORMERR: + case NOTIMP: + case REFUSED: + default: + h_errno = NO_RECOVERY; + break; + } + ar_reinfo.re_errors++; + /* + ** If a bad error was returned, we stop here and dont send + ** send any more (no retries granted). + */ + if (h_errno != TRY_AGAIN) + { + rptr->re_resend = 0; + rptr->re_retries = 0; + } + goto getres_err; + } + + a = ar_procanswer(rptr, hptr, ar_rcvbuf, ar_rcvbuf+rc); + + if ((rptr->re_type == T_PTR) && (_res.options & RES_CHECKPTR)) + { + /* + * For reverse lookups on IP#'s, lookup the name that is given + * for the ip# and return with that as the official result. + * -avalon + */ + rptr->re_type = T_A; + /* + * Clean out the list of addresses already set, even though + * there should only be one :) + */ + adr = (unsigned long *)rptr->re_he.h_addr_list; + while (*adr) + *adr++ = 0L; + /* + * Lookup the name that we were given for the ip# + */ + ar_reinfo.re_na_look++; + (void)strncpy(rptr->re_name, rptr->re_he.h_name, + sizeof(rptr->re_name)-1); + rptr->re_he.h_name = NULL; + rptr->re_retries = _res.retry; + rptr->re_sends = 1; + rptr->re_resend = 1; + rptr->re_he.h_name = NULL; + ar_reinfo.re_na_look++; + (void)ar_query_name(rptr->re_name, C_IN, T_A, rptr); + return NULL; + } + + if (reip && rptr->re_rinfo.ri_ptr && size) + bcopy(rptr->re_rinfo.ri_ptr, reip, + MIN(rptr->re_rinfo.ri_size, size)); + /* + * Clean up structure from previous usage. + */ + hp = &ar_host; +#ifdef ARLIB_DEBUG + ar_dump_hostent("ar_answer: previous usage", hp); +#endif + + if (hp->h_name) + (void)free(hp->h_name); + if (s = hp->h_aliases) + { + while (*s) + (void)free(*s++); + (void)free(hp->h_aliases); + } + if (s = hp->h_addr_list) + { + /* + * Only free once since we allocated space for + * address in one big chunk. + */ + (void)free(*s); + (void)free(hp->h_addr_list); + } + bzero((char *)hp, sizeof(*hp)); + + /* + * Setup and copy details for the structure we return a pointer to. + */ + hp->h_addrtype = AF_INET; + hp->h_length = sizeof(struct in_addr); + if(rptr->re_he.h_name) + { + hp->h_name = (char *)malloc(strlen(rptr->re_he.h_name)+1); + if(!hp->h_name) + { +#ifdef ARLIB_DEBUG + fprintf(stderr, "no memory for hostname\n"); +#endif + h_errno = TRY_AGAIN; + goto getres_err; + } + (void)strcpy(hp->h_name, rptr->re_he.h_name); + } +#ifdef ARLIB_DEBUG + ar_dump_hostent("ar_answer: (snap) store name", hp); +#endif + + /* + * Count IP#'s. + */ + for (i = 0, n = 0; i < MAXADDRS; i++, n++) + if (!rptr->re_he.h_addr_list[i].s_addr) + break; + s = hp->h_addr_list = (char **)malloc((n + 1) * sizeof(char *)); + if (n) + { + *s = (char *)malloc(n * sizeof(struct in_addr)); + if(!*s) + { +#ifdef ARLIB_DEBUG + fprintf(stderr, "no memory for IP#'s (%d)\n", n); +#endif + h_errno = TRY_AGAIN; + goto getres_err; + } + bcopy((char *)&rptr->re_he.h_addr_list[0].s_addr, *s, + sizeof(struct in_addr)); + s++; + for (i = 1; i < n; i++, s++) + { + *s = hp->h_addr + i * sizeof(struct in_addr); + bcopy((char *)&rptr->re_he.h_addr_list[i].s_addr, *s, + sizeof(struct in_addr)); + } + } + *s = NULL; +#ifdef ARLIB_DEBUG + ar_dump_hostent("ar_answer: (snap) store IP#'s", hp); +#endif + + /* + * Count CNAMEs + */ + for (i = 0, n = 0; i < MAXADDRS; i++, n++) + if (!rptr->re_he.h_aliases[i]) + break; + s = hp->h_aliases = (char **)malloc((n + 1) * sizeof(char *)); + if (!s) + { +#ifdef ARLIB_DEBUG + fprintf(stderr, "no memory for aliases (%d)\n", n); +#endif + h_errno = TRY_AGAIN; + goto getres_err; + } + for (i = 0; i < n; i++) + { + *s++ = rptr->re_he.h_aliases[i]; + rptr->re_he.h_aliases[i] = NULL; + } + *s = NULL; +#ifdef ARLIB_DEBUG + ar_dump_hostent("ar_answer: (snap) store CNAMEs", hp); + ar_dump_hostent("ar_answer: new one", hp); +#endif + + if (a > 0) + (void)ar_remrequest(rptr); + else + if (!rptr->re_sent) + (void)ar_remrequest(rptr); + return hp; + +getres_err: + if (rptr) + { + if (reip && rptr->re_rinfo.ri_ptr && size) + bcopy(rptr->re_rinfo.ri_ptr, reip, + MIN(rptr->re_rinfo.ri_size, size)); + if ((h_errno != TRY_AGAIN) && + (_res.options & (RES_DNSRCH|RES_DEFNAMES) == + (RES_DNSRCH|RES_DEFNAMES) )) + if (_res.dnsrch[rptr->re_srch]) + { + rptr->re_retries = _res.retry; + rptr->re_sends = 1; + rptr->re_resend = 1; + (void)ar_resend_query(rptr); + rptr->re_srch++; + } + return NULL; + } + return NULL; +} + + +#ifdef ARLIB_DEBUG +void ar_dump_hostent(prefix, hp) +char *prefix; +struct hostent *hp; +{ + register char **s; + + fflush(stdout); + + fprintf(stderr, "%s\n", prefix); + fprintf(stderr, " hp %p\n", hp); + fprintf(stderr, " h_name %p '%s'\n", + hp->h_name, hp->h_name); + if (s = hp->h_aliases) + { + fprintf(stderr, " h_aliases %p\n", + hp->h_aliases); + while (*s) + { + fprintf(stderr, " element %p\n", *s); + s++; + } + } + if (s = hp->h_addr_list) + { + fprintf(stderr, " h_addr_list %p\n", + hp->h_addr_list); + while (*s) + { + fprintf(stderr, " element %p\n", *s); + s++; + } + } + + fflush(stderr); +} + + +void ar_dump_reslist(FILE* fp) +{ + register struct reslist *rptr; + int c; + + c = 0; + for (rptr = ar_first; rptr; rptr = rptr->re_next) + { + fprintf(fp, "%4d [%p] %4d [%p]: %s\n", rptr->re_id, rptr, + *(rptr->re_rinfo.ri_ptr), rptr->re_rinfo.ri_ptr, + rptr->re_name); + } +} +#endif |