Updated PCI IDs to latest snapshot.
[tangerine.git] / workbench / network / stacks / AROSTCP / dhcp / minires / res_send.c
blob5e9c56ae49e6a00225b605107f772b640c9b962e
1 /*
2 * Copyright (c) 1985, 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
35 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
37 * Permission to use, copy, modify, and distribute this software for any
38 * purpose with or without fee is hereby granted, provided that the above
39 * copyright notice and this permission notice appear in all copies, and that
40 * the name of Digital Equipment Corporation not be used in advertising or
41 * publicity pertaining to distribution of the document or software without
42 * specific, written prior permission.
44 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
45 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
46 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
47 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
48 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
49 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
50 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
51 * SOFTWARE.
55 * Portions Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
56 * Portions Copyright (c) 1996-2003 by Internet Software Consortium
58 * Permission to use, copy, modify, and distribute this software for any
59 * purpose with or without fee is hereby granted, provided that the above
60 * copyright notice and this permission notice appear in all copies.
62 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
63 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
64 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
65 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
66 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
67 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
68 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
70 * Internet Systems Consortium, Inc.
71 * 950 Charter Street
72 * Redwood City, CA 94063
73 * <info@isc.org>
74 * http://www.isc.org/
77 #if defined(LIBC_SCCS) && !defined(lint)
78 static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93";
79 static const char rcsid[] = "$Id$";
80 #endif /* LIBC_SCCS and not lint */
83 * Send query to name server and wait for reply.
86 #include <sys/types.h>
87 #include <sys/param.h>
88 #include <sys/time.h>
89 #include <sys/socket.h>
90 #include <sys/uio.h>
92 #include <netinet/in.h>
93 #include <arpa/inet.h>
95 #include <errno.h>
96 #include <netdb.h>
97 #include <signal.h>
98 #include <stdio.h>
99 #include <stdlib.h>
100 #include <string.h>
101 #include <unistd.h>
103 #include "minires/minires.h"
104 #include "arpa/nameser.h"
106 #ifdef __AROS__
107 #include <aros/debug.h>
108 #endif
110 /* Prototypes */
111 int trace_mr_socket (int, int, int);
112 int trace_mr_connect (int s, struct sockaddr *, SOCKLEN_T);
113 ssize_t trace_mr_read (int, void *, size_t);
114 ssize_t trace_mr_send (int, void *, size_t, int);
115 int trace_mr_close (int);
116 int trace_mr_bind (int, struct sockaddr *, SOCKLEN_T);
117 int trace_mr_select (int, fd_set *, fd_set *, fd_set *, struct timeval *);
118 ssize_t trace_mr_recvfrom (int s, void *, size_t, int,
119 struct sockaddr *, SOCKLEN_T *);
121 /* Rename the I/O functions in case we're tracing. */
122 #undef send
123 #undef recvfrom
124 #undef read
125 #undef connect
126 #undef socket
127 #undef bind
128 #undef close
129 #undef select
130 #undef time
131 #define send trace_mr_send
132 #define recvfrom trace_mr_recvfrom
133 #define read trace_mr_read
134 #define connect trace_mr_connect
135 #define socket trace_mr_socket
136 #define bind trace_mr_bind
137 #define close trace_mr_close
138 #define select trace_mr_select
139 #define time trace_mr_time
141 #define CHECK_SRVR_ADDR
143 static int cmpsock(struct sockaddr_in *a1, struct sockaddr_in *a2);
144 void res_pquery(const res_state, const u_char *, int, FILE *);
146 /* int
147 * res_isourserver(ina)
148 * looks up "ina" in _res.ns_addr_list[]
149 * returns:
150 * 0 : not found
151 * >0 : found
152 * author:
153 * paul vixie, 29may94
156 res_ourserver_p(const res_state statp, const struct sockaddr_in *inp) {
157 struct sockaddr_in ina;
158 int ns;
160 ina = *inp;
161 for (ns = 0; ns < statp->nscount; ns++) {
162 const struct sockaddr_in *srv = &statp->nsaddr_list[ns];
164 if (srv->sin_family == ina.sin_family &&
165 srv->sin_port == ina.sin_port &&
166 (srv->sin_addr.s_addr == INADDR_ANY ||
167 srv->sin_addr.s_addr == ina.sin_addr.s_addr))
168 return (1);
170 return (0);
173 /* int
174 * res_nameinquery(name, type, class, buf, eom)
175 * look for (name,type,class) in the query section of packet (buf,eom)
176 * requires:
177 * buf + HFIXEDSZ <= eom
178 * returns:
179 * -1 : format error
180 * 0 : not found
181 * >0 : found
182 * author:
183 * paul vixie, 29may94
186 res_nameinquery(const char *name, int type, int class,
187 const u_char *buf, const u_char *eom)
189 const u_char *cp = buf + HFIXEDSZ;
190 int qdcount = ntohs(((const HEADER *)buf)->qdcount);
192 while (qdcount-- > 0) {
193 char tname[MAXDNAME+1];
194 int n, ttype, tclass;
196 n = dn_expand(buf, eom, cp, tname, sizeof tname);
197 if (n < 0)
198 return (-1);
199 cp += n;
200 if (cp + 2 * INT16SZ > eom)
201 return (-1);
202 ttype = getUShort(cp); cp += INT16SZ;
203 tclass = getUShort(cp); cp += INT16SZ;
204 if (ttype == type && tclass == class &&
205 ns_samename(tname, name) == 1)
206 return (1);
208 return (0);
211 /* int
212 * res_queriesmatch(buf1, eom1, buf2, eom2)
213 * is there a 1:1 mapping of (name,type,class)
214 * in (buf1,eom1) and (buf2,eom2)?
215 * returns:
216 * -1 : format error
217 * 0 : not a 1:1 mapping
218 * >0 : is a 1:1 mapping
219 * author:
220 * paul vixie, 29may94
223 res_queriesmatch(const u_char *buf1, const u_char *eom1,
224 const u_char *buf2, const u_char *eom2)
226 const u_char *cp = buf1 + HFIXEDSZ;
227 int qdcount = ntohs(((const HEADER *)buf1)->qdcount);
229 if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
230 return (-1);
233 * Only header section present in replies to
234 * dynamic update packets.
236 if ( (((const HEADER *)buf1)->opcode == ns_o_update) &&
237 (((const HEADER *)buf2)->opcode == ns_o_update) )
238 return (1);
240 if (qdcount != ntohs(((const HEADER*)buf2)->qdcount))
241 return (0);
242 while (qdcount-- > 0) {
243 char tname[MAXDNAME+1];
244 int n, ttype, tclass;
246 n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
247 if (n < 0)
248 return (-1);
249 cp += n;
250 if (cp + 2 * INT16SZ > eom1)
251 return (-1);
252 ttype = getUShort(cp); cp += INT16SZ;
253 tclass = getUShort(cp); cp += INT16SZ;
254 if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
255 return (0);
257 return (1);
260 isc_result_t
261 res_nsend(res_state statp,
262 double *buf, unsigned buflen,
263 double *ans, unsigned anssiz, unsigned *ansret)
265 HEADER *hp = (HEADER *) buf;
266 HEADER *anhp = (HEADER *) ans;
267 int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns, n;
268 u_int badns; /* XXX NSMAX can't exceed #/bits in this variable */
269 static int highestFD = FD_SETSIZE - 1;
271 if (anssiz < HFIXEDSZ) {
272 return ISC_R_INVALIDARG;
274 DprintQ((statp->options & RES_DEBUG) ||
275 (statp->pfcode & RES_PRF_QUERY),
276 (stdout, ";; res_send()\n"), buf, buflen);
277 v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
278 gotsomewhere = 0;
279 connreset = 0;
280 terrno = ISC_R_TIMEDOUT;
281 badns = 0;
284 * Some callers want to even out the load on their resolver list.
286 if (statp->nscount > 0 && (statp->options & RES_ROTATE) != 0) {
287 struct sockaddr_in ina;
288 int lastns = statp->nscount - 1;
290 ina = statp->nsaddr_list[0];
291 for (ns = 0; ns < lastns; ns++)
292 statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
293 statp->nsaddr_list[lastns] = ina;
296 #if defined (TRACING)
297 trace_mr_statp_setup (statp);
298 #endif
301 * Send request, RETRY times, or until successful
303 for (try = 0; try < statp->retry; try++) {
304 for (ns = 0; ns < statp->nscount; ns++) {
305 struct sockaddr_in *nsap = &statp->nsaddr_list[ns];
306 same_ns:
307 if (badns & (1 << ns)) {
308 res_nclose(statp);
309 goto next_ns;
312 if (statp->qhook) {
313 int done = 0, loops = 0;
315 do {
316 res_sendhookact act;
318 act = (*statp->qhook)(&nsap, &buf, &buflen,
319 ans, anssiz, &resplen);
320 switch (act) {
321 case res_goahead:
322 done = 1;
323 break;
324 case res_nextns:
325 res_nclose(statp);
326 goto next_ns;
327 case res_done:
328 return (resplen);
329 case res_modified:
330 /* give the hook another try */
331 if (++loops < 42) /*doug adams*/
332 break;
333 /*FALLTHROUGH*/
334 case res_error:
335 /*FALLTHROUGH*/
336 default:
337 return ISC_R_UNEXPECTED;
339 } while (!done);
342 Dprint(statp->options & RES_DEBUG,
343 (stdout, ";; Querying server (# %d) address = %s\n",
344 ns + 1, inet_ntoa(nsap->sin_addr)));
346 if (v_circuit) {
347 int truncated;
348 struct iovec iov[2];
349 u_short len;
350 u_char *cp;
352 /* Use VC; at most one attempt per server. */
353 try = statp->retry;
354 truncated = 0;
356 /* Are we still talking to whom we want to talk to? */
357 if (statp->_sock >= 0 &&
358 (statp->_flags & RES_F_VC) != 0) {
359 struct sockaddr_in peer;
360 SOCKLEN_T size = sizeof(peer);
362 if (getpeername(statp->_sock,
363 (struct sockaddr *)&peer,
364 &size) < 0) {
365 res_nclose(statp);
366 statp->_flags &= ~RES_F_VC;
367 } else if (!cmpsock(&peer, nsap)) {
368 res_nclose(statp);
369 statp->_flags &= ~RES_F_VC;
373 if (statp->_sock < 0 ||
374 (statp->_flags & RES_F_VC) == 0) {
375 if (statp->_sock >= 0)
376 res_nclose(statp);
378 statp->_sock = socket(PF_INET,
379 SOCK_STREAM, 0);
380 if (statp->_sock < 0 ||
381 statp->_sock > highestFD) {
382 terrno = uerr2isc (errno);
383 Perror(statp, stderr,
384 "socket(vc)", errno);
385 return (-1);
387 errno = 0;
388 if (connect(statp->_sock,
389 (struct sockaddr *)nsap,
390 sizeof *nsap) < 0) {
391 terrno = uerr2isc (errno);
392 Aerror(statp, stderr, "connect/vc",
393 errno, *nsap);
394 badns |= (1 << ns);
395 res_nclose(statp);
396 goto next_ns;
398 statp->_flags |= RES_F_VC;
401 * Send length & message
403 putUShort((u_char*)&len, buflen);
404 iov[0].iov_base = (caddr_t)&len;
405 iov[0].iov_len = INT16SZ;
406 iov[1].iov_base = (const caddr_t)buf;
407 iov[1].iov_len = buflen;
408 #ifdef __AROS__
409 bug("DONT HAVE writev\n");
410 #else
411 if (writev(statp->_sock, iov, 2) !=
412 (INT16SZ + buflen)) {
413 terrno = uerr2isc (errno);
414 Perror(statp, stderr, "write failed", errno);
415 badns |= (1 << ns);
416 res_nclose(statp);
417 goto next_ns;
419 #endif
421 * Receive length & response
423 read_len:
424 cp = (u_char *)ans;
425 len = INT16SZ;
426 while ((n = read(statp->_sock,
427 (char *)cp, (unsigned)len)) > 0) {
428 cp += n;
429 if ((len -= n) <= 0)
430 break;
432 if (n <= 0) {
433 terrno = uerr2isc (errno);
434 Perror(statp, stderr, "read failed", errno);
435 res_nclose(statp);
437 * A long running process might get its TCP
438 * connection reset if the remote server was
439 * restarted. Requery the server instead of
440 * trying a new one. When there is only one
441 * server, this means that a query might work
442 * instead of failing. We only allow one reset
443 * per query to prevent looping.
445 if (terrno == ISC_R_CONNREFUSED &&
446 !connreset) {
447 connreset = 1;
448 res_nclose(statp);
449 goto same_ns;
451 res_nclose(statp);
452 goto next_ns;
454 resplen = getUShort ((unsigned char *)ans);
455 if (resplen > anssiz) {
456 Dprint(statp->options & RES_DEBUG,
457 (stdout, ";; response truncated\n")
459 truncated = 1;
460 len = anssiz;
461 } else
462 len = resplen;
463 if (len < HFIXEDSZ) {
465 * Undersized message.
467 Dprint(statp->options & RES_DEBUG,
468 (stdout, ";; undersized: %d\n", len));
469 terrno = ISC_R_NOSPACE;
470 badns |= (1 << ns);
471 res_nclose(statp);
472 goto next_ns;
474 cp = (u_char *)ans;
475 while (len != 0 &&
476 (n = read(statp->_sock,
477 (char *)cp, (unsigned)len))
478 > 0) {
479 cp += n;
480 len -= n;
482 if (n <= 0) {
483 terrno = uerr2isc (errno);
484 Perror(statp, stderr, "read(vc)", errno);
485 res_nclose(statp);
486 goto next_ns;
488 if (truncated) {
490 * Flush rest of answer
491 * so connection stays in synch.
493 anhp->tc = 1;
494 len = resplen - anssiz;
495 while (len != 0) {
496 char junk[PACKETSZ];
498 n = (len > sizeof(junk)
499 ? sizeof(junk)
500 : len);
501 n = read(statp->_sock,
502 junk, (unsigned)n);
503 if (n > 0)
504 len -= n;
505 else
506 break;
510 * The calling applicating has bailed out of
511 * a previous call and failed to arrange to have
512 * the circuit closed or the server has got
513 * itself confused. Anyway drop the packet and
514 * wait for the correct one.
516 if (hp->id != anhp->id) {
517 DprintQ((statp->options & RES_DEBUG) ||
518 (statp->pfcode & RES_PRF_REPLY),
519 (stdout,
520 ";; old answer (unexpected):\n"),
521 ans, (resplen>anssiz)?anssiz:resplen);
522 goto read_len;
524 } else {
526 * Use datagrams.
528 int start, timeout, finish;
529 fd_set dsmask;
530 struct sockaddr_in from;
531 SOCKLEN_T fromlen;
532 int seconds;
534 if (statp->_sock < 0 ||
535 (statp->_flags & RES_F_VC) != 0) {
536 if ((statp->_flags & RES_F_VC) != 0)
537 res_nclose(statp);
538 statp->_sock = socket(PF_INET, SOCK_DGRAM, 0);
539 if (statp->_sock < 0 ||
540 statp->_sock > highestFD) {
541 #ifndef CAN_RECONNECT
542 bad_dg_sock:
543 #endif
544 terrno = uerr2isc (errno);
545 Perror(statp, stderr,
546 "socket(dg)", errno);
547 return terrno;
549 statp->_flags &= ~RES_F_CONN;
551 #ifndef CANNOT_CONNECT_DGRAM
553 * On a 4.3BSD+ machine (client and server,
554 * actually), sending to a nameserver datagram
555 * port with no nameserver will cause an
556 * ICMP port unreachable message to be returned.
557 * If our datagram socket is "connected" to the
558 * server, we get an ECONNREFUSED error on the next
559 * socket operation, and select returns if the
560 * error message is received. We can thus detect
561 * the absence of a nameserver without timing out.
562 * If we have sent queries to at least two servers,
563 * however, we don't want to remain connected,
564 * as we wish to receive answers from the first
565 * server to respond.
567 if (statp->nscount == 1 || (try == 0 && ns == 0)) {
569 * Connect only if we are sure we won't
570 * receive a response from another server.
572 if ((statp->_flags & RES_F_CONN) == 0) {
573 if (connect(statp->_sock,
574 (struct sockaddr *)nsap,
575 sizeof *nsap) < 0) {
576 Aerror(statp, stderr,
577 "connect(dg)",
578 errno, *nsap);
579 badns |= (1 << ns);
580 res_nclose(statp);
581 goto next_ns;
583 statp->_flags |= RES_F_CONN;
585 if (send(statp->_sock,
586 (const char*)buf, (unsigned)buflen, 0)
587 != buflen) {
588 Perror(statp, stderr, "send", errno);
589 badns |= (1 << ns);
590 res_nclose(statp);
591 goto next_ns;
593 } else {
595 * Disconnect if we want to listen
596 * for responses from more than one server.
598 if ((statp->_flags & RES_F_CONN) != 0) {
599 #ifdef CAN_RECONNECT
600 struct sockaddr_in no_addr;
602 no_addr.sin_family = AF_INET;
603 no_addr.sin_addr.s_addr = INADDR_ANY;
604 no_addr.sin_port = 0;
605 (void) connect(statp->_sock,
606 (struct sockaddr *)
607 &no_addr,
608 sizeof no_addr);
609 #else
610 struct sockaddr_in local_addr;
611 SOCKLEN_T len;
612 int result, s1;
614 len = sizeof(local_addr);
615 s1 = socket(PF_INET, SOCK_DGRAM, 0);
616 result = getsockname(statp->_sock,
617 (struct sockaddr *)&local_addr,
618 &len);
619 if (s1 < 0)
620 goto bad_dg_sock;
621 #ifdef SOCKET_IS_NOT_A_FILE
622 Dup2Socket(s1, statp->_sock);
623 #else
624 (void) dup2(s1, statp->_sock);
625 #endif
626 (void) close(s1);
627 if (result == 0) {
629 * Attempt to rebind to old
630 * port. Note connected socket
631 * has an sin_addr set.
633 local_addr.sin_addr.s_addr =
634 htonl(0);
635 (void)bind(statp->_sock,
636 (struct sockaddr *)
637 &local_addr,
638 (unsigned)len);
640 Dprint(statp->options & RES_DEBUG,
641 (stdout, ";; new DG socket\n"));
642 #endif /* CAN_RECONNECT */
643 statp->_flags &= ~RES_F_CONN;
644 errno = 0;
646 #endif /* !CANNOT_CONNECT_DGRAM */
647 if (sendto(statp->_sock,
648 (const char *)buf, buflen, 0,
649 (struct sockaddr *)nsap,
650 sizeof *nsap)
651 != buflen) {
652 Aerror(statp, stderr, "sendto", errno, *nsap);
653 badns |= (1 << ns);
654 res_nclose(statp);
655 goto next_ns;
657 #ifndef CANNOT_CONNECT_DGRAM
659 #endif /* !CANNOT_CONNECT_DGRAM */
661 if (statp->_sock < 0 || statp->_sock > highestFD) {
662 Perror(statp, stderr,
663 "fd out-of-bounds", EMFILE);
664 res_nclose(statp);
665 goto next_ns;
669 * Wait for reply
671 seconds = (statp->retrans << try);
672 if (try > 0)
673 seconds /= statp->nscount;
674 if (seconds <= 0)
675 seconds = 1;
676 start = cur_time;
677 timeout = seconds;
678 finish = start + timeout;
679 wait:
680 FD_ZERO(&dsmask);
681 FD_SET(statp->_sock, &dsmask);
683 struct timeval t;
684 t.tv_sec = timeout;
685 t.tv_usec = 0;
686 n = select(statp->_sock + 1,
687 &dsmask, NULL, NULL, &t);
689 if (n == 0) {
690 Dprint(statp->options & RES_DEBUG,
691 (stdout, ";; timeout\n"));
692 gotsomewhere = 1;
693 goto next_ns;
695 if (n < 0) {
696 if (errno == EINTR) {
697 if (finish >= cur_time) {
698 timeout = finish - cur_time;
699 goto wait;
702 Perror(statp, stderr, "select", errno);
703 res_nclose(statp);
704 goto next_ns;
706 errno = 0;
707 fromlen = sizeof(struct sockaddr_in);
708 resplen = recvfrom(statp->_sock,
709 (char *)ans, anssiz, 0,
710 (struct sockaddr *)&from, &fromlen);
711 if (resplen <= 0) {
712 Perror(statp, stderr, "recvfrom", errno);
713 res_nclose(statp);
714 goto next_ns;
716 gotsomewhere = 1;
717 if (resplen < HFIXEDSZ) {
719 * Undersized message.
721 Dprint(statp->options & RES_DEBUG,
722 (stdout, ";; undersized: %d\n",
723 resplen));
724 terrno = ISC_R_NOSPACE;
725 badns |= (1 << ns);
726 res_nclose(statp);
727 goto next_ns;
729 if (hp->id != anhp->id) {
731 * response from old query, ignore it.
732 * XXX - potential security hazard could
733 * be detected here.
735 DprintQ((statp->options & RES_DEBUG) ||
736 (statp->pfcode & RES_PRF_REPLY),
737 (stdout, ";; old answer:\n"),
738 ans, (resplen>anssiz)?anssiz:resplen);
739 goto wait;
741 #ifdef CHECK_SRVR_ADDR
742 if (!(statp->options & RES_INSECURE1) &&
743 !res_ourserver_p(statp, &from)) {
745 * response from wrong server? ignore it.
746 * XXX - potential security hazard could
747 * be detected here.
749 DprintQ((statp->options & RES_DEBUG) ||
750 (statp->pfcode & RES_PRF_REPLY),
751 (stdout, ";; not our server:\n"),
752 ans, (resplen>anssiz)?anssiz:resplen);
753 goto wait;
755 #endif
756 if (!(statp->options & RES_INSECURE2) &&
757 !res_queriesmatch((u_char *)buf,
758 ((u_char *)buf) + buflen,
759 (u_char *)ans,
760 ((u_char *)ans) + anssiz)) {
762 * response contains wrong query? ignore it.
763 * XXX - potential security hazard could
764 * be detected here.
766 DprintQ((statp->options & RES_DEBUG) ||
767 (statp->pfcode & RES_PRF_REPLY),
768 (stdout, ";; wrong query name:\n"),
769 ans, (resplen>anssiz)?anssiz:resplen);
770 goto wait;
772 if (anhp->rcode == SERVFAIL ||
773 anhp->rcode == NOTIMP ||
774 anhp->rcode == REFUSED) {
775 DprintQ(statp->options & RES_DEBUG,
776 (stdout, "server rejected query:\n"),
777 ans, (resplen>anssiz)?anssiz:resplen);
778 badns |= (1 << ns);
779 res_nclose(statp);
780 /* don't retry if called from dig */
781 if (!statp->pfcode)
782 goto next_ns;
784 if (!(statp->options & RES_IGNTC) && anhp->tc) {
786 * get rest of answer;
787 * use TCP with same server.
789 Dprint(statp->options & RES_DEBUG,
790 (stdout, ";; truncated answer\n"));
791 v_circuit = 1;
792 res_nclose(statp);
793 goto same_ns;
795 } /*if vc/dg*/
796 Dprint((statp->options & RES_DEBUG) ||
797 ((statp->pfcode & RES_PRF_REPLY) &&
798 (statp->pfcode & RES_PRF_HEAD1)),
799 (stdout, ";; got answer:\n"));
800 DprintQ((statp->options & RES_DEBUG) ||
801 (statp->pfcode & RES_PRF_REPLY),
802 (stdout, ""),
803 ans, (resplen>anssiz)?anssiz:resplen);
805 * If using virtual circuits, we assume that the first server
806 * is preferred over the rest (i.e. it is on the local
807 * machine) and only keep that one open.
808 * If we have temporarily opened a virtual circuit,
809 * or if we haven't been asked to keep a socket open,
810 * close the socket.
812 if ((v_circuit && (!(statp->options & RES_USEVC) || ns != 0)) ||
813 !(statp->options & RES_STAYOPEN)) {
814 res_nclose(statp);
816 if (statp->rhook) {
817 int done = 0, loops = 0;
819 do {
820 res_sendhookact act;
822 act = (*statp->rhook)(nsap, buf, buflen,
823 ans, anssiz, &resplen);
824 switch (act) {
825 case res_goahead:
826 case res_done:
827 done = 1;
828 break;
829 case res_nextns:
830 res_nclose(statp);
831 goto next_ns;
832 case res_modified:
833 /* give the hook another try */
834 if (++loops < 42) /*doug adams*/
835 break;
836 /*FALLTHROUGH*/
837 case res_error:
838 /*FALLTHROUGH*/
839 default:
840 return ISC_R_UNEXPECTED;
842 } while (!done);
845 *ansret = resplen;
846 return ISC_R_SUCCESS;
847 next_ns: ;
848 } /*foreach ns*/
849 } /*foreach retry*/
850 res_nclose(statp);
851 if (!v_circuit) {
852 if (!gotsomewhere)
853 terrno = ISC_R_CONNREFUSED; /* no nameservers found */
854 else
855 errno = ISC_R_TIMEDOUT; /* no answer obtained */
857 return terrno;
861 * This routine is for closing the socket if a virtual circuit is used and
862 * the program wants to close it. This provides support for endhostent()
863 * which expects to close the socket.
865 * This routine is not expected to be user visible.
867 void
868 res_nclose(res_state statp) {
869 if (statp->_sock >= 0) {
870 (void) close(statp->_sock);
871 statp->_sock = -1;
872 statp->_flags &= ~(RES_F_VC | RES_F_CONN);
876 /* Private */
877 static int
878 cmpsock(struct sockaddr_in *a1, struct sockaddr_in *a2) {
879 return ((a1->sin_family == a2->sin_family) &&
880 (a1->sin_port == a2->sin_port) &&
881 (a1->sin_addr.s_addr == a2->sin_addr.s_addr));
884 #ifdef NEED_PSELECT
885 /* XXX needs to move to the porting library. */
886 static int
887 pselect(int nfds, void *rfds, void *wfds, void *efds,
888 struct timespec *tsp,
889 const sigset_t *sigmask)
891 struct timeval tv, *tvp;
892 sigset_t sigs;
893 int n;
895 if (tsp) {
896 tvp = &tv;
897 tv = evTimeVal(*tsp);
898 } else
899 tvp = NULL;
900 if (sigmask)
901 sigprocmask(SIG_SETMASK, sigmask, &sigs);
902 n = select(nfds, rfds, wfds, efds, tvp);
903 if (sigmask)
904 sigprocmask(SIG_SETMASK, &sigs, NULL);
905 if (tsp)
906 *tsp = evTimeSpec(tv);
907 return (n);
909 #endif