Sync usage with man page.
[netbsd-mini2440.git] / dist / ntp / arlib / arlib.c
blobde35c7e508c2b00fee89ad837e82f3a47eb468b7
1 /* $NetBSD$ */
3 /*
4 * arlib.c (C)opyright 1993 Darren Reed. All rights reserved.
5 * This file may not be distributed without the author's permission in any
6 * shape or form. The author takes no responsibility for any damage or loss
7 * of property which results from the use of this software.
8 */
9 #ifndef lint
10 static char sccsid[] = "@(#)arlib.c 1.9 6/5/93 (C)opyright 1992 Darren \
11 Reed. ASYNC DNS";
12 #endif
14 #include <stdio.h>
15 #include <fcntl.h>
16 #include <signal.h>
17 #include <sys/types.h>
18 #include <sys/time.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include "netdb.h"
22 #include "arpa/nameser.h"
23 #include <resolv.h>
24 #include "arlib.h"
25 #include "arplib.h"
27 extern int errno, h_errno;
28 static char ar_hostbuf[65], ar_domainname[65];
29 static char ar_dot[] = ".";
30 static int ar_resfd = -1, ar_vc = 0;
31 static struct reslist *ar_last, *ar_first;
34 * Statistics structure.
36 static struct resstats {
37 int re_errors;
38 int re_nu_look;
39 int re_na_look;
40 int re_replies;
41 int re_requests;
42 int re_resends;
43 int re_sent;
44 int re_timeouts;
45 } ar_reinfo;
47 static int do_query_name(/* struct resinfo *, char *, struct reslist * */);
48 static int do_query_number(/* struct resinfo *, char *, struct reslist * */);
49 static int ar_resend_query(/* struct reslist * */);
52 * ar_init
54 * Initializes the various ARLIB internal varilables and related DNS
55 * options for res_init().
57 * Returns 0 or the socket opened for use with talking to name servers
58 * if 0 is passed or ARES_INITSOCK is set.
60 int ar_init(op)
61 int op;
63 int ret = 0;
65 if (op & ARES_INITLIST)
67 bzero(&ar_reinfo, sizeof(ar_reinfo));
68 ar_first = ar_last = NULL;
71 if (op & ARES_CALLINIT && !(_res.options & RES_INIT))
73 ret = res_init();
74 (void)strcpy(ar_domainname, ar_dot);
75 (void)strncat(ar_domainname, _res.defdname,
76 sizeof(ar_domainname)-2);
79 if (op & ARES_INITSOCK)
80 ret = ar_resfd = ar_open();
82 if (op & ARES_INITDEBG)
83 _res.options |= RES_DEBUG;
85 if (op == 0)
86 ret = ar_resfd;
88 return ret;
93 * ar_open
95 * Open a socket to talk to a name server with.
96 * Check _res.options to see if we use a TCP or UDP socket.
98 int ar_open()
100 if (ar_resfd == -1)
102 if (_res.options & RES_USEVC)
104 struct sockaddr_in *sip;
105 int i;
107 sip = _res.NS_ADDR_LIST; /* was _res.nsaddr_list */
108 ar_vc = 1;
109 ar_resfd = socket(AF_INET, SOCK_STREAM, 0);
112 * Try each name server listed in sequence until we
113 * succeed or run out.
115 while (connect(ar_resfd, (struct sockaddr *)sip++,
116 sizeof(struct sockaddr)))
118 (void)close(ar_resfd);
119 ar_resfd = -1;
120 if (i >= _res.nscount)
121 break;
122 ar_resfd = socket(AF_INET, SOCK_STREAM, 0);
125 else
126 ar_resfd = socket(AF_INET, SOCK_DGRAM, 0);
128 if (ar_resfd >= 0)
129 { /* Need one of these two here - and it MUST work!! */
130 int flags;
132 if ((flags = fcntl(ar_resfd, F_GETFL, 0)) != -1)
133 #ifdef O_NONBLOCK
134 if (fcntl(ar_resfd, F_SETFL, flags|O_NONBLOCK) == -1)
135 #else
136 # ifdef O_NDELAY
137 if (fcntl(ar_resfd, F_SETFL, flags|O_NDELAY) == -1)
138 # else
139 # ifdef FNDELAY
140 if (fcntl(ar_resfd, F_SETFL, flags|FNDELAY) == -1)
141 # endif
142 # endif
143 #endif
145 (void)close(ar_resfd);
146 ar_resfd = -1;
149 return ar_resfd;
154 * ar_close
156 * Closes and flags the ARLIB socket as closed.
158 void ar_close()
160 (void)close(ar_resfd);
161 ar_resfd = -1;
162 return;
167 * ar_add_request
169 * Add a new DNS query to the end of the query list.
171 static int ar_add_request(new)
172 struct reslist *new;
174 if (!new)
175 return -1;
176 if (!ar_first)
177 ar_first = ar_last = new;
178 else {
179 ar_last->re_next = new;
180 ar_last = new;
182 new->re_next = NULL;
183 ar_reinfo.re_requests++;
184 return 0;
189 * ar_remrequest
191 * Remove a request from the list. This must also free any memory that has
192 * been allocated for temporary storage of DNS results.
194 * Returns -1 if there are anyy problems removing the requested structure
195 * or 0 if the remove is successful.
197 static int ar_remrequest(old)
198 struct reslist *old;
200 register struct reslist *rptr, *r2ptr;
201 register char **s;
203 if (!old)
204 return -1;
205 for (rptr = ar_first, r2ptr = NULL; rptr; rptr = rptr->re_next)
207 if (rptr == old)
208 break;
209 r2ptr = rptr;
212 if (!rptr)
213 return -1;
214 if (rptr == ar_first)
215 ar_first = ar_first->re_next;
216 else if (rptr == ar_last)
218 if (ar_last = r2ptr)
219 ar_last->re_next = NULL;
221 else
222 r2ptr->re_next = rptr->re_next;
224 if (!ar_first)
225 ar_last = ar_first;
227 #ifdef ARLIB_DEBUG
228 ar_dump_hostent("ar_remrequest:", rptr->re_he);
229 #endif
231 if (rptr->re_he.h_name)
232 (void)free(rptr->re_he.h_name);
233 if (s = rptr->re_he.h_aliases)
234 for (; *s; s++)
235 (void)free(*s);
236 if (rptr->re_rinfo.ri_ptr)
237 (void)free(rptr->re_rinfo.ri_ptr);
238 (void)free(rptr);
240 return 0;
245 * ar_make_request
247 * Create a DNS query recorded for the request being made and place it on the
248 * current list awaiting replies. Initialization of the record with set
249 * values should also be done.
251 static struct reslist *ar_make_request(resi)
252 register struct resinfo *resi;
254 register struct reslist *rptr;
255 register struct resinfo *rp;
257 rptr = (struct reslist *)calloc(1, sizeof(struct reslist));
258 rp = &rptr->re_rinfo;
260 rptr->re_next = NULL; /* where NULL is non-zero ;) */
261 rptr->re_sentat = time(NULL);
262 rptr->re_retries = _res.retry;
263 rptr->re_sends = 1;
264 rptr->re_resend = 1;
265 rptr->re_timeout = rptr->re_sentat + _res.retrans;
266 rptr->re_he.h_name = NULL;
267 rptr->re_he.h_addrtype = AF_INET;
268 rptr->re_he.h_aliases[0] = NULL;
269 rp->ri_ptr = resi->ri_ptr;
270 rp->ri_size = resi->ri_size;
272 (void)ar_add_request(rptr);
274 return rptr;
279 * ar_timeout
281 * Remove queries from the list which have been there too long without
282 * being resolved.
284 long ar_timeout(now, info, size)
285 time_t now;
286 char *info;
287 int size;
289 register struct reslist *rptr, *r2ptr;
290 register long next = 0;
292 for (rptr = ar_first, r2ptr = NULL; rptr; rptr = r2ptr)
294 r2ptr = rptr->re_next;
295 if (now >= rptr->re_timeout)
298 * If the timeout for the query has been exceeded,
299 * then resend the query if we still have some
300 * 'retry credit' and reset the timeout. If we have
301 * used it all up, then remove the request.
303 if (--rptr->re_retries <= 0)
305 ar_reinfo.re_timeouts++;
306 if (info && rptr->re_rinfo.ri_ptr)
307 bcopy(rptr->re_rinfo.ri_ptr, info,
308 MIN(rptr->re_rinfo.ri_size,
309 size));
310 (void)ar_remrequest(rptr);
311 return now;
313 else
315 rptr->re_sends++;
316 rptr->re_sentat = now;
317 rptr->re_timeout = now + _res.retrans;
318 (void)ar_resend_query(rptr);
321 if (!next || rptr->re_timeout < next)
322 next = rptr->re_timeout;
324 return next;
329 * ar_send_res_msg
331 * When sending queries to nameservers listed in the resolv.conf file,
332 * don't send a query to every one, but increase the number sent linearly
333 * to match the number of resends. This increase only occurs if there are
334 * multiple nameserver entries in the resolv.conf file.
335 * The return value is the number of messages successfully sent to
336 * nameservers or -1 if no successful sends.
338 static int ar_send_res_msg(msg, len, rcount)
339 char *msg;
340 int len, rcount;
342 register int i;
343 int sent = 0;
345 if (!msg)
346 return -1;
348 rcount = (_res.nscount > rcount) ? rcount : _res.nscount;
349 if (_res.options & RES_PRIMARY)
350 rcount = 1;
352 if (ar_vc)
354 ar_reinfo.re_sent++;
355 sent++;
356 if (write(ar_resfd, msg, len) == -1)
358 int errtmp = errno;
359 (void)close(ar_resfd);
360 errno = errtmp;
361 ar_resfd = -1;
364 else
365 for (i = 0; i < rcount; i++)
367 if (sendto(ar_resfd, msg, len, 0,
368 (struct sockaddr *)&(_res.NS_ADDR_LIST[i]),
369 sizeof(struct sockaddr_in)) == len)
371 ar_reinfo.re_sent++;
372 sent++;
375 return (sent) ? sent : -1;
380 * ar_find_id
382 * find a dns query record by the id (id is determined by dn_mkquery)
384 static struct reslist *ar_find_id(id)
385 int id;
387 register struct reslist *rptr;
389 for (rptr = ar_first; rptr; rptr = rptr->re_next)
390 if (rptr->re_id == id)
391 return rptr;
392 return NULL;
397 * ar_delete
399 * Delete a request from the waiting list if it has a data pointer which
400 * matches the one passed.
402 int ar_delete(ptr, size)
403 char *ptr;
404 int size;
406 register struct reslist *rptr;
407 register struct reslist *r2ptr;
408 int removed = 0;
410 for (rptr = ar_first; rptr; rptr = r2ptr)
412 r2ptr = rptr->re_next;
413 if (rptr->re_rinfo.ri_ptr && ptr && size &&
414 bcmp(rptr->re_rinfo.ri_ptr, ptr, size) == 0)
416 (void)ar_remrequest(rptr);
417 removed++;
420 return removed;
425 * ar_query_name
427 * generate a query based on class, type and name.
429 static int ar_query_name(name, class, type, rptr)
430 char *name;
431 int class, type;
432 struct reslist *rptr;
434 static char buf[MAXPACKET];
435 int r,s,a;
436 HEADER *hptr;
438 bzero(buf, sizeof(buf));
439 r = res_mkquery(QUERY, name, class, type, NULL, 0, NULL,
440 buf, sizeof(buf));
441 if (r <= 0)
443 h_errno = NO_RECOVERY;
444 return r;
446 hptr = (HEADER *)buf;
447 rptr->re_id = ntohs(hptr->id);
449 s = ar_send_res_msg(buf, r, rptr->re_sends);
451 if (s == -1)
453 h_errno = TRY_AGAIN;
454 return -1;
456 else
457 rptr->re_sent += s;
458 return 0;
463 * ar_gethostbyname
465 * Replacement library function call to gethostbyname(). This one, however,
466 * doesn't return the record being looked up but just places the query in the
467 * queue to await answers.
469 int ar_gethostbyname(name, info, size)
470 char *name;
471 char *info;
472 int size;
474 char host[65];
475 struct resinfo resi;
476 register struct resinfo *rp = &resi;
478 if (size && info)
480 rp->ri_ptr = (char *)malloc(size);
481 bcopy(info, rp->ri_ptr, size);
482 rp->ri_size = size;
484 else
485 bzero((char *)rp, sizeof(resi));
486 ar_reinfo.re_na_look++;
487 (void)strncpy(host, name, 64);
488 host[64] = '\0';
490 return (do_query_name(rp, host, NULL));
494 static int do_query_name(resi, name, rptr)
495 struct resinfo *resi;
496 char *name;
497 register struct reslist *rptr;
499 char hname[65];
500 int len;
502 len = strlen((char *)strncpy(hname, name, sizeof(hname)-1));
504 if (rptr && (hname[len-1] != '.'))
506 (void)strncat(hname, ar_dot, sizeof(hname)-len-1);
508 * NOTE: The logical relationship between DNSRCH and DEFNAMES
509 * is implies. ie no DEFNAES, no DNSRCH.
511 if (_res.options & (RES_DEFNAMES|RES_DNSRCH) ==
512 (RES_DEFNAMES|RES_DNSRCH))
514 if (_res.dnsrch[rptr->re_srch])
515 (void)strncat(hname, _res.dnsrch[rptr->re_srch],
516 sizeof(hname) - ++len -1);
518 else if (_res.options & RES_DEFNAMES)
519 (void)strncat(hname, ar_domainname, sizeof(hname) - len -1);
523 * Store the name passed as the one to lookup and generate other host
524 * names to pass onto the nameserver(s) for lookups.
526 if (!rptr)
528 rptr = ar_make_request(resi);
529 rptr->re_type = T_A;
530 (void)strncpy(rptr->re_name, name, sizeof(rptr->re_name)-1);
532 return (ar_query_name(hname, C_IN, T_A, rptr));
537 * ar_gethostbyaddr
539 * Generates a query for a given IP address.
541 int ar_gethostbyaddr(addr, info, size)
542 char *addr;
543 char *info;
544 int size;
546 struct resinfo resi;
547 register struct resinfo *rp = &resi;
549 if (size && info)
551 rp->ri_ptr = (char *)malloc(size);
552 bcopy(info, rp->ri_ptr, size);
553 rp->ri_size = size;
555 else
556 bzero((char *)rp, sizeof(resi));
557 ar_reinfo.re_nu_look++;
558 return (do_query_number(rp, addr, NULL));
563 * do_query_number
565 * Use this to do reverse IP# lookups.
567 static int do_query_number(resi, numb, rptr)
568 struct resinfo *resi;
569 char *numb;
570 register struct reslist *rptr;
572 register unsigned char *cp;
573 static char ipbuf[32];
576 * Generate name in the "in-addr.arpa" domain. No addings bits to this
577 * name to get more names to query!.
579 cp = (unsigned char *)numb;
580 (void)sprintf(ipbuf,"%u.%u.%u.%u.in-addr.arpa.",
581 (unsigned int)(cp[3]), (unsigned int)(cp[2]),
582 (unsigned int)(cp[1]), (unsigned int)(cp[0]));
584 if (!rptr)
586 rptr = ar_make_request(resi);
587 rptr->re_type = T_PTR;
588 rptr->re_he.h_length = sizeof(struct in_addr);
589 bcopy(numb, (char *)&rptr->re_addr, rptr->re_he.h_length);
590 bcopy(numb, (char *)&rptr->re_he.h_addr_list[0].s_addr,
591 rptr->re_he.h_length);
593 return (ar_query_name(ipbuf, C_IN, T_PTR, rptr));
598 * ar_resent_query
600 * resends a query.
602 static int ar_resend_query(rptr)
603 struct reslist *rptr;
605 if (!rptr->re_resend)
606 return -1;
608 switch(rptr->re_type)
610 case T_PTR:
611 ar_reinfo.re_resends++;
612 return do_query_number(NULL, &rptr->re_addr, rptr);
613 case T_A:
614 ar_reinfo.re_resends++;
615 return do_query_name(NULL, rptr->re_name, rptr);
616 default:
617 break;
620 return -1;
625 * ar_procanswer
627 * process an answer received from a nameserver.
629 static int ar_procanswer(rptr, hptr, buf, eob)
630 struct reslist *rptr;
631 char *buf, *eob;
632 HEADER *hptr;
634 char *cp, **alias, *s;
635 int class, type, dlen, len, ans = 0, n, i;
636 u_int32_t ttl, dr, *adr;
637 struct hent *hp;
639 cp = buf + sizeof(HEADER);
640 adr = (u_int32_t *)rptr->re_he.h_addr_list;
642 while (*adr)
643 adr++;
645 alias = rptr->re_he.h_aliases;
646 while (*alias)
647 alias++;
649 hp = &rptr->re_he;
653 * Skip over the original question.
655 while (hptr->qdcount-- > 0)
656 cp += dn_skipname(cp, eob) + QFIXEDSZ;
658 * proccess each answer sent to us. blech.
660 while (hptr->ancount-- > 0 && cp < eob) {
661 n = dn_expand(buf, eob, cp, ar_hostbuf, sizeof(ar_hostbuf));
662 cp += n;
663 if (n <= 0)
664 return ans;
666 ans++;
668 * 'skip' past the general dns crap (ttl, class, etc) to get
669 * the pointer to the right spot. Some of thse are actually
670 * useful so its not a good idea to skip past in one big jump.
672 type = (int)_getshort(cp);
673 cp += sizeof(short);
674 class = (int)_getshort(cp);
675 cp += sizeof(short);
676 ttl = (u_int32_t)_getlong(cp);
677 cp += sizeof(u_int32_t);
678 dlen = (int)_getshort(cp);
679 cp += sizeof(short);
680 rptr->re_type = type;
682 switch(type)
684 case T_A :
685 rptr->re_he.h_length = dlen;
686 if (ans == 1)
687 rptr->re_he.h_addrtype=(class == C_IN) ?
688 AF_INET : AF_UNSPEC;
689 if (dlen != sizeof(dr))
691 h_errno = TRY_AGAIN;
692 continue;
694 bcopy(cp, &dr, dlen);
695 *adr++ = dr;
696 *adr = 0;
697 cp += dlen;
698 len = strlen(ar_hostbuf);
699 if (!rptr->re_he.h_name)
701 rptr->re_he.h_name = (char *)malloc(len+1);
702 if (!rptr->re_he.h_name)
703 break;
704 (void)strcpy(rptr->re_he.h_name, ar_hostbuf);
706 break;
707 case T_PTR :
708 if ((n = dn_expand(buf, eob, cp, ar_hostbuf,
709 sizeof(ar_hostbuf) )) < 0)
711 cp += n;
712 continue;
714 cp += n;
715 len = strlen(ar_hostbuf)+1;
717 * copy the returned hostname into the host name
718 * or alias field if there is a known hostname
719 * already.
721 if (!rptr->re_he.h_name)
723 rptr->re_he.h_name = (char *)malloc(len);
724 if (!rptr->re_he.h_name)
725 break;
726 (void)strcpy(rptr->re_he.h_name, ar_hostbuf);
728 else
730 *alias = (char *)malloc(len);
731 if (!*alias)
732 return -1;
733 (void)strcpy(*alias++, ar_hostbuf);
734 *alias = NULL;
736 break;
737 case T_CNAME :
738 cp += dlen;
739 if (alias >= &(rptr->re_he.h_aliases[MAXALIASES-1]))
740 continue;
741 n = strlen(ar_hostbuf)+1;
742 *alias = (char *)malloc(n);
743 if (!*alias)
744 return -1;
745 (void)strcpy(*alias++, ar_hostbuf);
746 *alias = NULL;
747 break;
748 default :
749 break;
753 return ans;
758 * ar_answer
760 * Get an answer from a DNS server and process it. If a query is found to
761 * which no answer has been given to yet, copy its 'info' structure back
762 * to where "reip" points and return a pointer to the hostent structure.
764 struct hostent *ar_answer(reip, size)
765 char *reip;
766 int size;
768 static char ar_rcvbuf[sizeof(HEADER) + MAXPACKET];
769 static struct hostent ar_host;
771 register HEADER *hptr;
772 register struct reslist *rptr = NULL;
773 register struct hostent *hp;
774 register char **s;
775 unsigned long *adr;
776 int rc, i, n, a;
778 rc = recv(ar_resfd, ar_rcvbuf, sizeof(ar_rcvbuf), 0);
779 if (rc <= 0)
780 goto getres_err;
782 ar_reinfo.re_replies++;
783 hptr = (HEADER *)ar_rcvbuf;
785 * convert things to be in the right order.
787 hptr->id = ntohs(hptr->id);
788 hptr->ancount = ntohs(hptr->ancount);
789 hptr->arcount = ntohs(hptr->arcount);
790 hptr->nscount = ntohs(hptr->nscount);
791 hptr->qdcount = ntohs(hptr->qdcount);
793 * response for an id which we have already received an answer for
794 * just ignore this response.
796 rptr = ar_find_id(hptr->id);
797 if (!rptr)
798 goto getres_err;
800 if ((hptr->rcode != NOERROR) || (hptr->ancount == 0))
802 switch (hptr->rcode)
804 case NXDOMAIN:
805 h_errno = HOST_NOT_FOUND;
806 break;
807 case SERVFAIL:
808 h_errno = TRY_AGAIN;
809 break;
810 case NOERROR:
811 h_errno = NO_DATA;
812 break;
813 case FORMERR:
814 case NOTIMP:
815 case REFUSED:
816 default:
817 h_errno = NO_RECOVERY;
818 break;
820 ar_reinfo.re_errors++;
822 ** If a bad error was returned, we stop here and dont send
823 ** send any more (no retries granted).
825 if (h_errno != TRY_AGAIN)
827 rptr->re_resend = 0;
828 rptr->re_retries = 0;
830 goto getres_err;
833 a = ar_procanswer(rptr, hptr, ar_rcvbuf, ar_rcvbuf+rc);
835 if ((rptr->re_type == T_PTR) && (_res.options & RES_CHECKPTR))
838 * For reverse lookups on IP#'s, lookup the name that is given
839 * for the ip# and return with that as the official result.
840 * -avalon
842 rptr->re_type = T_A;
844 * Clean out the list of addresses already set, even though
845 * there should only be one :)
847 adr = (unsigned long *)rptr->re_he.h_addr_list;
848 while (*adr)
849 *adr++ = 0L;
851 * Lookup the name that we were given for the ip#
853 ar_reinfo.re_na_look++;
854 (void)strncpy(rptr->re_name, rptr->re_he.h_name,
855 sizeof(rptr->re_name)-1);
856 rptr->re_he.h_name = NULL;
857 rptr->re_retries = _res.retry;
858 rptr->re_sends = 1;
859 rptr->re_resend = 1;
860 rptr->re_he.h_name = NULL;
861 ar_reinfo.re_na_look++;
862 (void)ar_query_name(rptr->re_name, C_IN, T_A, rptr);
863 return NULL;
866 if (reip && rptr->re_rinfo.ri_ptr && size)
867 bcopy(rptr->re_rinfo.ri_ptr, reip,
868 MIN(rptr->re_rinfo.ri_size, size));
870 * Clean up structure from previous usage.
872 hp = &ar_host;
873 #ifdef ARLIB_DEBUG
874 ar_dump_hostent("ar_answer: previous usage", hp);
875 #endif
877 if (hp->h_name)
878 (void)free(hp->h_name);
879 if (s = hp->h_aliases)
881 while (*s)
882 (void)free(*s++);
883 (void)free(hp->h_aliases);
885 if (s = hp->h_addr_list)
888 * Only free once since we allocated space for
889 * address in one big chunk.
891 (void)free(*s);
892 (void)free(hp->h_addr_list);
894 bzero((char *)hp, sizeof(*hp));
897 * Setup and copy details for the structure we return a pointer to.
899 hp->h_addrtype = AF_INET;
900 hp->h_length = sizeof(struct in_addr);
901 if(rptr->re_he.h_name)
903 hp->h_name = (char *)malloc(strlen(rptr->re_he.h_name)+1);
904 if(!hp->h_name)
906 #ifdef ARLIB_DEBUG
907 fprintf(stderr, "no memory for hostname\n");
908 #endif
909 h_errno = TRY_AGAIN;
910 goto getres_err;
912 (void)strcpy(hp->h_name, rptr->re_he.h_name);
914 #ifdef ARLIB_DEBUG
915 ar_dump_hostent("ar_answer: (snap) store name", hp);
916 #endif
919 * Count IP#'s.
921 for (i = 0, n = 0; i < MAXADDRS; i++, n++)
922 if (!rptr->re_he.h_addr_list[i].s_addr)
923 break;
924 s = hp->h_addr_list = (char **)malloc((n + 1) * sizeof(char *));
925 if (n)
927 *s = (char *)malloc(n * sizeof(struct in_addr));
928 if(!*s)
930 #ifdef ARLIB_DEBUG
931 fprintf(stderr, "no memory for IP#'s (%d)\n", n);
932 #endif
933 h_errno = TRY_AGAIN;
934 goto getres_err;
936 bcopy((char *)&rptr->re_he.h_addr_list[0].s_addr, *s,
937 sizeof(struct in_addr));
938 s++;
939 for (i = 1; i < n; i++, s++)
941 *s = hp->h_addr + i * sizeof(struct in_addr);
942 bcopy((char *)&rptr->re_he.h_addr_list[i].s_addr, *s,
943 sizeof(struct in_addr));
946 *s = NULL;
947 #ifdef ARLIB_DEBUG
948 ar_dump_hostent("ar_answer: (snap) store IP#'s", hp);
949 #endif
952 * Count CNAMEs
954 for (i = 0, n = 0; i < MAXADDRS; i++, n++)
955 if (!rptr->re_he.h_aliases[i])
956 break;
957 s = hp->h_aliases = (char **)malloc((n + 1) * sizeof(char *));
958 if (!s)
960 #ifdef ARLIB_DEBUG
961 fprintf(stderr, "no memory for aliases (%d)\n", n);
962 #endif
963 h_errno = TRY_AGAIN;
964 goto getres_err;
966 for (i = 0; i < n; i++)
968 *s++ = rptr->re_he.h_aliases[i];
969 rptr->re_he.h_aliases[i] = NULL;
971 *s = NULL;
972 #ifdef ARLIB_DEBUG
973 ar_dump_hostent("ar_answer: (snap) store CNAMEs", hp);
974 ar_dump_hostent("ar_answer: new one", hp);
975 #endif
977 if (a > 0)
978 (void)ar_remrequest(rptr);
979 else
980 if (!rptr->re_sent)
981 (void)ar_remrequest(rptr);
982 return hp;
984 getres_err:
985 if (rptr)
987 if (reip && rptr->re_rinfo.ri_ptr && size)
988 bcopy(rptr->re_rinfo.ri_ptr, reip,
989 MIN(rptr->re_rinfo.ri_size, size));
990 if ((h_errno != TRY_AGAIN) &&
991 (_res.options & (RES_DNSRCH|RES_DEFNAMES) ==
992 (RES_DNSRCH|RES_DEFNAMES) ))
993 if (_res.dnsrch[rptr->re_srch])
995 rptr->re_retries = _res.retry;
996 rptr->re_sends = 1;
997 rptr->re_resend = 1;
998 (void)ar_resend_query(rptr);
999 rptr->re_srch++;
1001 return NULL;
1003 return NULL;
1007 #ifdef ARLIB_DEBUG
1008 void ar_dump_hostent(prefix, hp)
1009 char *prefix;
1010 struct hostent *hp;
1012 register char **s;
1014 fflush(stdout);
1016 fprintf(stderr, "%s\n", prefix);
1017 fprintf(stderr, " hp %p\n", hp);
1018 fprintf(stderr, " h_name %p '%s'\n",
1019 hp->h_name, hp->h_name);
1020 if (s = hp->h_aliases)
1022 fprintf(stderr, " h_aliases %p\n",
1023 hp->h_aliases);
1024 while (*s)
1026 fprintf(stderr, " element %p\n", *s);
1027 s++;
1030 if (s = hp->h_addr_list)
1032 fprintf(stderr, " h_addr_list %p\n",
1033 hp->h_addr_list);
1034 while (*s)
1036 fprintf(stderr, " element %p\n", *s);
1037 s++;
1041 fflush(stderr);
1045 void ar_dump_reslist(FILE* fp)
1047 register struct reslist *rptr;
1048 int c;
1050 c = 0;
1051 for (rptr = ar_first; rptr; rptr = rptr->re_next)
1053 fprintf(fp, "%4d [%p] %4d [%p]: %s\n", rptr->re_id, rptr,
1054 *(rptr->re_rinfo.ri_ptr), rptr->re_rinfo.ri_ptr,
1055 rptr->re_name);
1058 #endif