summaryrefslogtreecommitdiffstats
path: root/contrib/ntp/arlib/arlib.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ntp/arlib/arlib.c')
-rw-r--r--contrib/ntp/arlib/arlib.c1056
1 files changed, 1056 insertions, 0 deletions
diff --git a/contrib/ntp/arlib/arlib.c b/contrib/ntp/arlib/arlib.c
new file mode 100644
index 0000000..3d76e57
--- /dev/null
+++ b/contrib/ntp/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
OpenPOWER on IntegriCloud