Update.
[glibc.git] / resolv / res_send.c
blobe315383fa7a3a81ddc11f4f5c1bf6562fdd1fe28
1 /*
2 * ++Copyright++ 1985, 1989, 1993
3 * -
4 * Copyright (c) 1985, 1989, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 4. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 * -
31 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
33 * Permission to use, copy, modify, and distribute this software for any
34 * purpose with or without fee is hereby granted, provided that the above
35 * copyright notice and this permission notice appear in all copies, and that
36 * the name of Digital Equipment Corporation not be used in advertising or
37 * publicity pertaining to distribution of the document or software without
38 * specific, written prior permission.
40 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
41 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
42 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
43 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
44 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
45 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
46 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
47 * SOFTWARE.
48 * -
49 * --Copyright--
52 #if defined(LIBC_SCCS) && !defined(lint)
53 static char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93";
54 static char rcsid[] = "$Id$";
55 #endif /* LIBC_SCCS and not lint */
57 /* change this to "0"
58 * if you talk to a lot
59 * of multi-homed SunOS
60 * ("broken") name servers.
62 #define CHECK_SRVR_ADDR 1 /* XXX - should be in options.h */
65 * Send query to name server and wait for reply.
68 #include <sys/types.h>
69 #include <sys/param.h>
70 #include <sys/poll.h>
71 #include <sys/time.h>
72 #include <sys/socket.h>
73 #include <sys/uio.h>
74 #include <netinet/in.h>
75 #include <arpa/nameser.h>
76 #include <arpa/inet.h>
78 #include <stdio.h>
79 #include <netdb.h>
80 #include <errno.h>
81 #include <resolv.h>
82 #if defined(BSD) && (BSD >= 199306)
83 # include <stdlib.h>
84 # include <string.h>
85 # include <unistd.h>
86 #else
87 # include "../conf/portability.h"
88 #endif
90 #include <bits/libc-lock.h>
92 /* Lock to protect the connection use. */
93 __libc_lock_define_initialized (static, lock)
95 static void res_close_internal (void);
97 #if defined(USE_OPTIONS_H)
98 # include <../conf/options.h>
99 #endif
101 static int s = -1; /* socket used for communications */
102 static int connected = 0; /* is the socket connected */
103 static int vc = 0; /* is the socket a virtual circuit? */
105 /* XXX - this should be done in portability.h */
106 #if (defined(BSD) && (BSD >= 199103)) || defined(linux)
107 # define CAN_RECONNECT 1
108 #else
109 # define CAN_RECONNECT 0
110 #endif
112 #ifndef DEBUG
113 # define Dprint(cond, args) /*empty*/
114 # define DprintQ(cond, args, query, size) /*empty*/
115 # define Aerror(file, string, error, address) /*empty*/
116 # define Perror(file, string, error) /*empty*/
117 #else
118 # define Dprint(cond, args) if (cond) {fprintf args;} else {}
119 # define DprintQ(cond, args, query, size) if (cond) {\
120 fprintf args;\
121 __fp_nquery(query, size, stdout);\
122 } else {}
123 static void
124 Aerror(file, string, error, address)
125 FILE *file;
126 char *string;
127 int error;
128 struct sockaddr_in address;
130 int save = errno;
132 if (_res.options & RES_DEBUG) {
133 fprintf(file, "res_send: %s ([%s].%u): %s\n",
134 string,
135 inet_ntoa(address.sin_addr),
136 ntohs(address.sin_port),
137 strerror(error));
139 __set_errno (save);
141 static void
142 Perror(file, string, error)
143 FILE *file;
144 char *string;
145 int error;
147 int save = errno;
149 if (_res.options & RES_DEBUG) {
150 fprintf(file, "res_send: %s: %s\n",
151 string, strerror(error));
153 __set_errno (save);
155 #endif
157 static res_send_qhook Qhook = NULL;
158 static res_send_rhook Rhook = NULL;
160 void
161 res_send_setqhook(hook)
162 res_send_qhook hook;
165 Qhook = hook;
168 void
169 res_send_setrhook(hook)
170 res_send_rhook hook;
173 Rhook = hook;
176 /* int
177 * res_isourserver(ina)
178 * looks up "ina" in _res.ns_addr_list[]
179 * returns:
180 * 0 : not found
181 * >0 : found
182 * author:
183 * paul vixie, 29may94
186 res_isourserver(inp)
187 const struct sockaddr_in *inp;
189 struct sockaddr_in ina;
190 register int ns, ret;
192 ina = *inp;
193 ret = 0;
194 for (ns = 0; ns < _res.nscount; ns++) {
195 register const struct sockaddr_in *srv = &_res.nsaddr_list[ns];
197 if (srv->sin_family == ina.sin_family &&
198 srv->sin_port == ina.sin_port &&
199 (srv->sin_addr.s_addr == INADDR_ANY ||
200 srv->sin_addr.s_addr == ina.sin_addr.s_addr)) {
201 ret++;
202 break;
205 return (ret);
208 /* int
209 * res_nameinquery(name, type, class, buf, eom)
210 * look for (name,type,class) in the query section of packet (buf,eom)
211 * requires:
212 * buf + HFIXESDZ <= eom
213 * returns:
214 * -1 : format error
215 * 0 : not found
216 * >0 : found
217 * author:
218 * paul vixie, 29may94
221 res_nameinquery(name, type, class, buf, eom)
222 const char *name;
223 register int type, class;
224 const u_char *buf, *eom;
226 register const u_char *cp = buf + HFIXEDSZ;
227 int qdcount = ntohs(((HEADER*)buf)->qdcount);
229 while (qdcount-- > 0) {
230 char tname[MAXDNAME+1];
231 register int n, ttype, tclass;
233 n = dn_expand(buf, eom, cp, tname, sizeof tname);
234 if (n < 0)
235 return (-1);
236 cp += n;
237 if (cp + 2 * INT16SZ > eom)
238 return (-1);
239 ttype = _getshort(cp); cp += INT16SZ;
240 tclass = _getshort(cp); cp += INT16SZ;
241 if (ttype == type &&
242 tclass == class &&
243 strcasecmp(tname, name) == 0)
244 return (1);
246 return (0);
249 /* int
250 * res_queriesmatch(buf1, eom1, buf2, eom2)
251 * is there a 1:1 mapping of (name,type,class)
252 * in (buf1,eom1) and (buf2,eom2)?
253 * returns:
254 * -1 : format error
255 * 0 : not a 1:1 mapping
256 * >0 : is a 1:1 mapping
257 * author:
258 * paul vixie, 29may94
261 res_queriesmatch(buf1, eom1, buf2, eom2)
262 const u_char *buf1, *eom1;
263 const u_char *buf2, *eom2;
265 register const u_char *cp = buf1 + HFIXEDSZ;
266 int qdcount = ntohs(((HEADER*)buf1)->qdcount);
268 if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
269 return (-1);
271 if (qdcount != ntohs(((HEADER*)buf2)->qdcount))
272 return (0);
273 while (qdcount-- > 0) {
274 char tname[MAXDNAME+1];
275 register int n, ttype, tclass;
277 n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
278 if (n < 0)
279 return (-1);
280 cp += n;
281 if (cp + 2 * INT16SZ > eom1)
282 return (-1);
283 ttype = _getshort(cp); cp += INT16SZ;
284 tclass = _getshort(cp); cp += INT16SZ;
285 if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
286 return (0);
288 return (1);
292 res_send(buf, buflen, ans, anssiz)
293 const u_char *buf;
294 int buflen;
295 u_char *ans;
296 int anssiz;
298 HEADER *hp = (HEADER *) buf;
299 HEADER *anhp = (HEADER *) ans;
300 int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns;
301 register int n;
302 u_int badns; /* XXX NSMAX can't exceed #/bits in this var */
303 int result = -1;
305 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
306 /* errno should have been set by res_init() in this case. */
307 return (-1);
309 if (anssiz < HFIXEDSZ) {
310 __set_errno (EINVAL);
311 return (-1);
313 DprintQ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY),
314 (stdout, ";; res_send()\n"), buf, buflen);
315 v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
316 gotsomewhere = 0;
317 connreset = 0;
318 terrno = ETIMEDOUT;
319 badns = 0;
321 __libc_lock_lock (lock);
324 * Send request, RETRY times, or until successful
326 for (try = 0; try < _res.retry; try++) {
327 for (ns = 0; ns < _res.nscount; ns++) {
328 struct sockaddr_in *nsap = &_res.nsaddr_list[ns];
329 same_ns:
330 if (badns & (1 << ns)) {
331 res_close_internal();
332 goto next_ns;
335 if (Qhook) {
336 int done = 0, loops = 0;
338 do {
339 res_sendhookact act;
341 act = (*Qhook)(&nsap, &buf, &buflen,
342 ans, anssiz, &resplen);
343 switch (act) {
344 case res_goahead:
345 done = 1;
346 break;
347 case res_nextns:
348 res_close_internal();
349 goto next_ns;
350 case res_done:
351 result = resplen;
352 goto and_out;
353 case res_modified:
354 /* give the hook another try */
355 if (++loops < 42) /*doug adams*/
356 break;
357 /*FALLTHROUGH*/
358 case res_error:
359 /*FALLTHROUGH*/
360 default:
361 goto and_out;
363 } while (!done);
366 Dprint(_res.options & RES_DEBUG,
367 (stdout, ";; Querying server (# %d) address = %s\n",
368 ns + 1, inet_ntoa(nsap->sin_addr)));
370 if (v_circuit) {
371 int truncated;
372 struct iovec iov[2];
373 u_short len;
374 u_char *cp;
377 * Use virtual circuit;
378 * at most one attempt per server.
380 try = _res.retry;
381 truncated = 0;
382 if ((s < 0) || (!vc)) {
383 if (s >= 0)
384 res_close_internal();
386 s = socket(PF_INET, SOCK_STREAM, 0);
387 if (s < 0) {
388 terrno = errno;
389 Perror(stderr, "socket(vc)", errno);
390 goto and_out;
392 __set_errno (0);
393 if (connect(s, (struct sockaddr *)nsap,
394 sizeof(struct sockaddr)) < 0) {
395 terrno = errno;
396 Aerror(stderr, "connect/vc",
397 errno, *nsap);
398 badns |= (1 << ns);
399 res_close_internal();
400 goto next_ns;
402 vc = 1;
405 * Send length & message
407 putshort((u_short)buflen, (u_char*)&len);
408 iov[0].iov_base = (caddr_t)&len;
409 iov[0].iov_len = INT16SZ;
410 iov[1].iov_base = (caddr_t)buf;
411 iov[1].iov_len = buflen;
412 if (writev(s, iov, 2) != (INT16SZ + buflen)) {
413 terrno = errno;
414 Perror(stderr, "write failed", errno);
415 badns |= (1 << ns);
416 res_close_internal();
417 goto next_ns;
420 * Receive length & response
422 read_len:
423 cp = ans;
424 len = INT16SZ;
425 while ((n = read(s, (char *)cp, (int)len)) > 0) {
426 cp += n;
427 if ((len -= n) <= 0)
428 break;
430 if (n <= 0) {
431 terrno = errno;
432 Perror(stderr, "read failed", errno);
433 res_close_internal();
435 * A long running process might get its TCP
436 * connection reset if the remote server was
437 * restarted. Requery the server instead of
438 * trying a new one. When there is only one
439 * server, this means that a query might work
440 * instead of failing. We only allow one reset
441 * per query to prevent looping.
443 if (terrno == ECONNRESET && !connreset) {
444 connreset = 1;
445 res_close_internal();
446 goto same_ns;
448 res_close_internal();
449 goto next_ns;
451 resplen = _getshort(ans);
452 if (resplen > anssiz) {
453 Dprint(_res.options & RES_DEBUG,
454 (stdout, ";; response truncated\n")
456 truncated = 1;
457 len = anssiz;
458 } else
459 len = resplen;
460 if (len < HFIXEDSZ) {
462 * Undersized message.
464 Dprint(_res.options & RES_DEBUG,
465 (stdout, ";; undersized: %d\n", len));
466 terrno = EMSGSIZE;
467 badns |= (1 << ns);
468 res_close_internal();
469 goto next_ns;
471 cp = ans;
472 while (len != 0 &&
473 (n = read(s, (char *)cp, (int)len)) > 0) {
474 cp += n;
475 len -= n;
477 if (n <= 0) {
478 terrno = errno;
479 Perror(stderr, "read(vc)", errno);
480 res_close_internal();
481 goto next_ns;
483 if (truncated) {
485 * Flush rest of answer
486 * so connection stays in synch.
488 anhp->tc = 1;
489 len = resplen - anssiz;
490 while (len != 0) {
491 char junk[PACKETSZ];
493 n = ((size_t) len > sizeof(junk)
494 ? sizeof(junk)
495 : len);
496 if ((n = read(s, junk, n)) > 0)
497 len -= n;
498 else
499 break;
503 * The calling applicating has bailed out of
504 * a previous call and failed to arrange to have
505 * the circuit closed or the server has got
506 * itself confused. Anyway drop the packet and
507 * wait for the correct one.
509 if (hp->id != anhp->id) {
510 DprintQ((_res.options & RES_DEBUG) ||
511 (_res.pfcode & RES_PRF_REPLY),
512 (stdout, ";; old answer (unexpected):\n"),
513 ans, (resplen>anssiz)?anssiz:resplen);
514 goto read_len;
516 } else {
518 * Use datagrams.
520 int timeout;
521 struct pollfd pfd[1];
522 struct sockaddr_in from;
523 socklen_t fromlen;
524 time_t curtime;
525 time_t endtime;
527 if ((s < 0) || vc) {
528 if (vc)
529 res_close_internal();
530 s = socket(PF_INET, SOCK_DGRAM, 0);
531 if (s < 0) {
532 #if !CAN_RECONNECT
533 bad_dg_sock:
534 #endif
535 terrno = errno;
536 Perror(stderr, "socket(dg)", errno);
537 goto and_out;
539 connected = 0;
542 * On a 4.3BSD+ machine (client and server,
543 * actually), sending to a nameserver datagram
544 * port with no nameserver will cause an
545 * ICMP port unreachable message to be returned.
546 * If our datagram socket is "connected" to the
547 * server, we get an ECONNREFUSED error on the next
548 * socket operation, and select returns if the
549 * error message is received. We can thus detect
550 * the absence of a nameserver without timing out.
551 * If we have sent queries to at least two servers,
552 * however, we don't want to remain connected,
553 * as we wish to receive answers from the first
554 * server to respond.
556 if (_res.nscount == 1 || (try == 0 && ns == 0)) {
558 * Connect only if we are sure we won't
559 * receive a response from another server.
561 if (!connected) {
562 if (connect(s, (struct sockaddr *)nsap,
563 sizeof(struct sockaddr)
564 ) < 0) {
565 Aerror(stderr,
566 "connect(dg)",
567 errno, *nsap);
568 badns |= (1 << ns);
569 res_close_internal();
570 goto next_ns;
572 connected = 1;
574 if (send(s, (char*)buf, buflen, 0) != buflen) {
575 Perror(stderr, "send", errno);
576 badns |= (1 << ns);
577 res_close_internal();
578 goto next_ns;
580 } else {
582 * Disconnect if we want to listen
583 * for responses from more than one server.
585 if (connected) {
586 #if CAN_RECONNECT
587 struct sockaddr_in no_addr;
589 no_addr.sin_family = AF_INET;
590 no_addr.sin_addr.s_addr = INADDR_ANY;
591 no_addr.sin_port = 0;
592 (void) connect(s,
593 (struct sockaddr *)
594 &no_addr,
595 sizeof(no_addr));
596 #else
597 int s1 = socket(PF_INET, SOCK_DGRAM,0);
598 if (s1 < 0)
599 goto bad_dg_sock;
600 (void) dup2(s1, s);
601 (void) close(s1);
602 Dprint(_res.options & RES_DEBUG,
603 (stdout, ";; new DG socket\n"))
604 #endif
605 connected = 0;
606 __set_errno (0);
608 if (sendto(s, (char*)buf, buflen, 0,
609 (struct sockaddr *)nsap,
610 sizeof(struct sockaddr))
611 != buflen) {
612 Aerror(stderr, "sendto", errno, *nsap);
613 badns |= (1 << ns);
614 res_close_internal();
615 goto next_ns;
620 * Wait for reply
622 curtime = time (NULL);
623 if (try > 0)
624 endtime = (_res.retrans << try) / _res.nscount;
625 else {
626 endtime = _res.retrans;
627 if (endtime <= 0)
628 endtime = 1;
630 endtime += curtime;
631 wait:
632 timeout = MAX (endtime - curtime, 0) * 1000;
633 #if 0
634 if (s < 0 || s >= FD_SETSIZE) {
635 Perror(stderr, "s out-of-bounds", EMFILE);
636 res_close_internal();
637 goto next_ns;
639 #endif
640 pfd[0].fd = s;
641 pfd[0].events = POLLIN;
642 n = __poll(pfd, 1, timeout);
643 if (n < 0) {
644 if (errno == EINTR) {
645 curtime = time (NULL);
646 goto wait;
648 Perror(stderr, "poll", errno);
649 res_close_internal();
650 goto next_ns;
652 if (n == 0) {
654 * timeout
656 Dprint(_res.options & RES_DEBUG,
657 (stdout, ";; timeout\n"));
658 gotsomewhere = 1;
659 res_close_internal();
660 goto next_ns;
662 __set_errno (0);
663 fromlen = sizeof(struct sockaddr_in);
664 resplen = recvfrom(s, (char*)ans, anssiz, 0,
665 (struct sockaddr *)&from, &fromlen);
666 if (resplen <= 0) {
667 Perror(stderr, "recvfrom", errno);
668 res_close_internal();
669 goto next_ns;
671 gotsomewhere = 1;
672 if (resplen < HFIXEDSZ) {
674 * Undersized message.
676 Dprint(_res.options & RES_DEBUG,
677 (stdout, ";; undersized: %d\n",
678 resplen));
679 terrno = EMSGSIZE;
680 badns |= (1 << ns);
681 res_close_internal();
682 goto next_ns;
684 if (hp->id != anhp->id) {
686 * response from old query, ignore it.
687 * XXX - potential security hazard could
688 * be detected here.
690 DprintQ((_res.options & RES_DEBUG) ||
691 (_res.pfcode & RES_PRF_REPLY),
692 (stdout, ";; old answer:\n"),
693 ans, (resplen>anssiz)?anssiz:resplen);
694 curtime = time (NULL);
695 goto wait;
697 #if CHECK_SRVR_ADDR
698 if (!(_res.options & RES_INSECURE1) &&
699 !res_isourserver(&from)) {
701 * response from wrong server? ignore it.
702 * XXX - potential security hazard could
703 * be detected here.
705 DprintQ((_res.options & RES_DEBUG) ||
706 (_res.pfcode & RES_PRF_REPLY),
707 (stdout, ";; not our server:\n"),
708 ans, (resplen>anssiz)?anssiz:resplen);
709 curtime = time (NULL);
710 goto wait;
712 #endif
713 if (!(_res.options & RES_INSECURE2) &&
714 !res_queriesmatch(buf, buf + buflen,
715 ans, ans + anssiz)) {
717 * response contains wrong query? ignore it.
718 * XXX - potential security hazard could
719 * be detected here.
721 DprintQ((_res.options & RES_DEBUG) ||
722 (_res.pfcode & RES_PRF_REPLY),
723 (stdout, ";; wrong query name:\n"),
724 ans, (resplen>anssiz)?anssiz:resplen);
725 curtime = time (NULL);
726 goto wait;
728 if (anhp->rcode == SERVFAIL ||
729 anhp->rcode == NOTIMP ||
730 anhp->rcode == REFUSED) {
731 DprintQ(_res.options & RES_DEBUG,
732 (stdout, "server rejected query:\n"),
733 ans, (resplen>anssiz)?anssiz:resplen);
734 badns |= (1 << ns);
735 res_close_internal();
736 /* don't retry if called from dig */
737 if (!_res.pfcode)
738 goto next_ns;
740 if (!(_res.options & RES_IGNTC) && anhp->tc) {
742 * get rest of answer;
743 * use TCP with same server.
745 Dprint(_res.options & RES_DEBUG,
746 (stdout, ";; truncated answer\n"));
747 v_circuit = 1;
748 res_close_internal();
749 goto same_ns;
751 } /*if vc/dg*/
752 Dprint((_res.options & RES_DEBUG) ||
753 ((_res.pfcode & RES_PRF_REPLY) &&
754 (_res.pfcode & RES_PRF_HEAD1)),
755 (stdout, ";; got answer:\n"));
756 DprintQ((_res.options & RES_DEBUG) ||
757 (_res.pfcode & RES_PRF_REPLY),
758 (stdout, ""),
759 ans, (resplen>anssiz)?anssiz:resplen);
761 * If using virtual circuits, we assume that the first server
762 * is preferred over the rest (i.e. it is on the local
763 * machine) and only keep that one open.
764 * If we have temporarily opened a virtual circuit,
765 * or if we haven't been asked to keep a socket open,
766 * close the socket.
768 if ((v_circuit && (!(_res.options & RES_USEVC) || ns != 0)) ||
769 !(_res.options & RES_STAYOPEN)) {
770 res_close_internal();
772 if (Rhook) {
773 int done = 0, loops = 0;
775 do {
776 res_sendhookact act;
778 act = (*Rhook)(nsap, buf, buflen,
779 ans, anssiz, &resplen);
780 switch (act) {
781 case res_goahead:
782 case res_done:
783 done = 1;
784 break;
785 case res_nextns:
786 res_close_internal();
787 goto next_ns;
788 case res_modified:
789 /* give the hook another try */
790 if (++loops < 42) /*doug adams*/
791 break;
792 /*FALLTHROUGH*/
793 case res_error:
794 /*FALLTHROUGH*/
795 default:
796 goto and_out;
798 } while (!done);
801 result = resplen;
802 goto and_out;
803 next_ns: ;
804 } /*foreach ns*/
805 } /*foreach retry*/
806 res_close_internal();
807 if (!v_circuit) {
808 if (!gotsomewhere)
809 __set_errno (ECONNREFUSED); /* no nameservers found */
810 else
811 __set_errno (ETIMEDOUT); /* no answer obtained */
812 } else
813 __set_errno (terrno);
815 and_out:
816 __libc_lock_unlock (lock);
818 return result;
822 * This routine is for closing the socket if a virtual circuit is used and
823 * the program wants to close it. This provides support for endhostent()
824 * which expects to close the socket.
826 * This routine is not expected to be user visible.
828 static void
829 res_close_internal()
831 if (s >= 0) {
832 (void) close(s);
833 s = -1;
834 connected = 0;
835 vc = 0;
839 void
840 res_close ()
842 __libc_lock_lock (lock);
843 res_close_internal ();
844 __libc_lock_unlock (lock);
847 #ifdef ultrix
848 /* ultrix 4.0 had some icky packaging in its libc.a. alias for it here.
849 * there is more gunk of this kind over in res_debug.c.
852 void
853 _res_close()
855 res_close();
858 #undef res_send
860 res_send(buf, buflen, ans, anssiz)
861 const u_char *buf;
862 int buflen;
863 u_char *ans;
864 int anssiz;
866 return (__res_send(buf, buflen, ans, anssiz));
868 #endif /* Ultrix 4.0 hackery */