* sysdeps/m68k/dl-machine.h (RTLD_START): Call pre-init funtions.
[glibc.git] / resolv / res_send.c
blob0c67d507bf23cf0c82b54c54f68126d6f98d49ee
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;
525 if ((s < 0) || vc) {
526 if (vc)
527 res_close_internal();
528 s = socket(PF_INET, SOCK_DGRAM, 0);
529 if (s < 0) {
530 #if !CAN_RECONNECT
531 bad_dg_sock:
532 #endif
533 terrno = errno;
534 Perror(stderr, "socket(dg)", errno);
535 goto and_out;
537 connected = 0;
540 * On a 4.3BSD+ machine (client and server,
541 * actually), sending to a nameserver datagram
542 * port with no nameserver will cause an
543 * ICMP port unreachable message to be returned.
544 * If our datagram socket is "connected" to the
545 * server, we get an ECONNREFUSED error on the next
546 * socket operation, and select returns if the
547 * error message is received. We can thus detect
548 * the absence of a nameserver without timing out.
549 * If we have sent queries to at least two servers,
550 * however, we don't want to remain connected,
551 * as we wish to receive answers from the first
552 * server to respond.
554 if (_res.nscount == 1 || (try == 0 && ns == 0)) {
556 * Connect only if we are sure we won't
557 * receive a response from another server.
559 if (!connected) {
560 if (connect(s, (struct sockaddr *)nsap,
561 sizeof(struct sockaddr)
562 ) < 0) {
563 Aerror(stderr,
564 "connect(dg)",
565 errno, *nsap);
566 badns |= (1 << ns);
567 res_close_internal();
568 goto next_ns;
570 connected = 1;
572 if (send(s, (char*)buf, buflen, 0) != buflen) {
573 Perror(stderr, "send", errno);
574 badns |= (1 << ns);
575 res_close_internal();
576 goto next_ns;
578 } else {
580 * Disconnect if we want to listen
581 * for responses from more than one server.
583 if (connected) {
584 #if CAN_RECONNECT
585 struct sockaddr_in no_addr;
587 no_addr.sin_family = AF_INET;
588 no_addr.sin_addr.s_addr = INADDR_ANY;
589 no_addr.sin_port = 0;
590 (void) connect(s,
591 (struct sockaddr *)
592 &no_addr,
593 sizeof(no_addr));
594 #else
595 int s1 = socket(PF_INET, SOCK_DGRAM,0);
596 if (s1 < 0)
597 goto bad_dg_sock;
598 (void) dup2(s1, s);
599 (void) close(s1);
600 Dprint(_res.options & RES_DEBUG,
601 (stdout, ";; new DG socket\n"))
602 #endif
603 connected = 0;
604 __set_errno (0);
606 if (sendto(s, (char*)buf, buflen, 0,
607 (struct sockaddr *)nsap,
608 sizeof(struct sockaddr))
609 != buflen) {
610 Aerror(stderr, "sendto", errno, *nsap);
611 badns |= (1 << ns);
612 res_close_internal();
613 goto next_ns;
618 * Wait for reply
620 timeout = (_res.retrans << try) * 1000;
621 if (try > 0)
622 timeout /= _res.nscount;
623 if (timeout <= 0)
624 timeout = 1000;
625 wait:
626 if (s < 0 || s >= FD_SETSIZE) {
627 Perror(stderr, "s out-of-bounds", EMFILE);
628 res_close_internal();
629 goto next_ns;
631 pfd[0].fd = s;
632 pfd[0].events = POLLIN;
633 n = __poll(pfd, 1, timeout);
634 if (n < 0) {
635 if (errno == EINTR)
636 goto wait;
637 Perror(stderr, "poll", errno);
638 res_close_internal();
639 goto next_ns;
641 if (n == 0) {
643 * timeout
645 Dprint(_res.options & RES_DEBUG,
646 (stdout, ";; timeout\n"));
647 gotsomewhere = 1;
648 res_close_internal();
649 goto next_ns;
651 __set_errno (0);
652 fromlen = sizeof(struct sockaddr_in);
653 resplen = recvfrom(s, (char*)ans, anssiz, 0,
654 (struct sockaddr *)&from, &fromlen);
655 if (resplen <= 0) {
656 Perror(stderr, "recvfrom", errno);
657 res_close_internal();
658 goto next_ns;
660 gotsomewhere = 1;
661 if (resplen < HFIXEDSZ) {
663 * Undersized message.
665 Dprint(_res.options & RES_DEBUG,
666 (stdout, ";; undersized: %d\n",
667 resplen));
668 terrno = EMSGSIZE;
669 badns |= (1 << ns);
670 res_close_internal();
671 goto next_ns;
673 if (hp->id != anhp->id) {
675 * response from old query, ignore it.
676 * XXX - potential security hazard could
677 * be detected here.
679 DprintQ((_res.options & RES_DEBUG) ||
680 (_res.pfcode & RES_PRF_REPLY),
681 (stdout, ";; old answer:\n"),
682 ans, (resplen>anssiz)?anssiz:resplen);
683 goto wait;
685 #if CHECK_SRVR_ADDR
686 if (!(_res.options & RES_INSECURE1) &&
687 !res_isourserver(&from)) {
689 * response from wrong server? ignore it.
690 * XXX - potential security hazard could
691 * be detected here.
693 DprintQ((_res.options & RES_DEBUG) ||
694 (_res.pfcode & RES_PRF_REPLY),
695 (stdout, ";; not our server:\n"),
696 ans, (resplen>anssiz)?anssiz:resplen);
697 goto wait;
699 #endif
700 if (!(_res.options & RES_INSECURE2) &&
701 !res_queriesmatch(buf, buf + buflen,
702 ans, ans + anssiz)) {
704 * response contains wrong query? ignore it.
705 * XXX - potential security hazard could
706 * be detected here.
708 DprintQ((_res.options & RES_DEBUG) ||
709 (_res.pfcode & RES_PRF_REPLY),
710 (stdout, ";; wrong query name:\n"),
711 ans, (resplen>anssiz)?anssiz:resplen);
712 goto wait;
714 if (anhp->rcode == SERVFAIL ||
715 anhp->rcode == NOTIMP ||
716 anhp->rcode == REFUSED) {
717 DprintQ(_res.options & RES_DEBUG,
718 (stdout, "server rejected query:\n"),
719 ans, (resplen>anssiz)?anssiz:resplen);
720 badns |= (1 << ns);
721 res_close_internal();
722 /* don't retry if called from dig */
723 if (!_res.pfcode)
724 goto next_ns;
726 if (!(_res.options & RES_IGNTC) && anhp->tc) {
728 * get rest of answer;
729 * use TCP with same server.
731 Dprint(_res.options & RES_DEBUG,
732 (stdout, ";; truncated answer\n"));
733 v_circuit = 1;
734 res_close_internal();
735 goto same_ns;
737 } /*if vc/dg*/
738 Dprint((_res.options & RES_DEBUG) ||
739 ((_res.pfcode & RES_PRF_REPLY) &&
740 (_res.pfcode & RES_PRF_HEAD1)),
741 (stdout, ";; got answer:\n"));
742 DprintQ((_res.options & RES_DEBUG) ||
743 (_res.pfcode & RES_PRF_REPLY),
744 (stdout, ""),
745 ans, (resplen>anssiz)?anssiz:resplen);
747 * If using virtual circuits, we assume that the first server
748 * is preferred over the rest (i.e. it is on the local
749 * machine) and only keep that one open.
750 * If we have temporarily opened a virtual circuit,
751 * or if we haven't been asked to keep a socket open,
752 * close the socket.
754 if ((v_circuit && (!(_res.options & RES_USEVC) || ns != 0)) ||
755 !(_res.options & RES_STAYOPEN)) {
756 res_close_internal();
758 if (Rhook) {
759 int done = 0, loops = 0;
761 do {
762 res_sendhookact act;
764 act = (*Rhook)(nsap, buf, buflen,
765 ans, anssiz, &resplen);
766 switch (act) {
767 case res_goahead:
768 case res_done:
769 done = 1;
770 break;
771 case res_nextns:
772 res_close_internal();
773 goto next_ns;
774 case res_modified:
775 /* give the hook another try */
776 if (++loops < 42) /*doug adams*/
777 break;
778 /*FALLTHROUGH*/
779 case res_error:
780 /*FALLTHROUGH*/
781 default:
782 goto and_out;
784 } while (!done);
787 result = resplen;
788 goto and_out;
789 next_ns: ;
790 } /*foreach ns*/
791 } /*foreach retry*/
792 res_close_internal();
793 if (!v_circuit) {
794 if (!gotsomewhere)
795 __set_errno (ECONNREFUSED); /* no nameservers found */
796 else
797 __set_errno (ETIMEDOUT); /* no answer obtained */
798 } else
799 __set_errno (terrno);
801 and_out:
802 __libc_lock_unlock (lock);
804 return result;
808 * This routine is for closing the socket if a virtual circuit is used and
809 * the program wants to close it. This provides support for endhostent()
810 * which expects to close the socket.
812 * This routine is not expected to be user visible.
814 static void
815 res_close_internal()
817 if (s >= 0) {
818 (void) close(s);
819 s = -1;
820 connected = 0;
821 vc = 0;
825 void
826 res_close ()
828 __libc_lock_lock (lock);
829 res_close_internal ();
830 __libc_lock_unlock (lock);
833 #ifdef ultrix
834 /* ultrix 4.0 had some icky packaging in its libc.a. alias for it here.
835 * there is more gunk of this kind over in res_debug.c.
838 void
839 _res_close()
841 res_close();
844 #undef res_send
846 res_send(buf, buflen, ans, anssiz)
847 const u_char *buf;
848 int buflen;
849 u_char *ans;
850 int anssiz;
852 return (__res_send(buf, buflen, ans, anssiz));
854 #endif /* Ultrix 4.0 hackery */