source: rtems/cpukit/libnetworking/libc/res_send.c @ 09fdb5e8

4.104.114.84.95
Last change on this file since 09fdb5e8 was 09fdb5e8, checked in by Ralf Corsepius <ralf.corsepius@…>, on 03/30/07 at 05:15:58

Eliminate SCCS, LINT. Add HAVE_CONFIG_H.

  • Property mode set to 100644
File size: 22.9 KB
Line 
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.
20 *
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.
32 */
33
34/*
35 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
36 *
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.
43 *
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.
52 */
53
54/*
55 * Portions Copyright (c) 1996 by Internet Software Consortium.
56 *
57 * Permission to use, copy, modify, and distribute this software for any
58 * purpose with or without fee is hereby granted, provided that the above
59 * copyright notice and this permission notice appear in all copies.
60 *
61 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
62 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
63 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
64 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
65 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
66 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
67 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
68 * SOFTWARE.
69 */
70
71#if HAVE_CONFIG_H
72#include "config.h"
73#endif
74
75/*
76 * Send query to name server and wait for reply.
77 */
78
79#include <sys/types.h>
80#include <sys/param.h>
81#include <sys/time.h>
82#include <sys/socket.h>
83#include <sys/uio.h>
84
85#include <netinet/in.h>
86#include <arpa/nameser.h>
87#include <arpa/inet.h>
88
89#include <errno.h>
90#include <netdb.h>
91#include <resolv.h>
92#include <stdio.h>
93#include <stdlib.h>
94#include <string.h>
95#include <unistd.h>
96#if !defined(__rtems__)
97#include <poll.h>
98#endif
99
100#include "res_config.h"
101
102#if !defined(__rtems__)
103
104#ifdef NOPOLL                   /* libc_r doesn't wrap poll yet() */
105static int use_poll = 0;
106#else
107static int use_poll = 1;        /* adapt to poll() syscall availability */
108                                /* 0 = not present, 1 = try it, 2 = exists */
109#endif
110#endif
111
112static int s = -1;              /* socket used for communications */
113static int connected = 0;       /* is the socket connected */
114static int vc = 0;              /* is the socket a virtual circuit? */
115static res_send_qhook Qhook = NULL;
116static res_send_rhook Rhook = NULL;
117
118
119#define CAN_RECONNECT 1
120
121#ifndef DEBUG
122#   define Dprint(cond, args) /*empty*/
123#   define DprintQ(cond, args, query, size) /*empty*/
124#   define Aerror(file, string, error, address) /*empty*/
125#   define Perror(file, string, error) /*empty*/
126#else
127#   define Dprint(cond, args) if (cond) {fprintf args;} else {}
128#   define DprintQ(cond, args, query, size) if (cond) {\
129                        fprintf args;\
130                        __fp_nquery(query, size, stdout);\
131                } else {}
132    static void
133    Aerror(file, string, error, address)
134        FILE *file;
135        char *string;
136        int error;
137        struct sockaddr_in address;
138    {
139        int save = errno;
140
141        if (_res.options & RES_DEBUG) {
142                fprintf(file, "res_send: %s ([%s].%u): %s\n",
143                        string,
144                        inet_ntoa(address.sin_addr),
145                        ntohs(address.sin_port),
146                        strerror(error));
147        }
148        errno = save;
149    }
150    static void
151    Perror(file, string, error)
152        FILE *file;
153        char *string;
154        int error;
155    {
156        int save = errno;
157
158        if (_res.options & RES_DEBUG) {
159                fprintf(file, "res_send: %s: %s\n",
160                        string, strerror(error));
161        }
162        errno = save;
163    }
164#endif
165
166void
167res_send_setqhook(hook)
168        res_send_qhook hook;
169{
170
171        Qhook = hook;
172}
173
174void
175res_send_setrhook(hook)
176        res_send_rhook hook;
177{
178
179        Rhook = hook;
180}
181
182/* int
183 * res_isourserver(ina)
184 *      looks up "ina" in _res.ns_addr_list[]
185 * returns:
186 *      0  : not found
187 *      >0 : found
188 * author:
189 *      paul vixie, 29may94
190 */
191int
192res_isourserver(inp)
193        const struct sockaddr_in *inp;
194{
195        struct sockaddr_in ina;
196        int ns, ret;
197
198        ina = *inp;
199        ret = 0;
200        for (ns = 0;  ns < _res.nscount;  ns++) {
201                const struct sockaddr_in *srv = &_res.nsaddr_list[ns];
202
203                if (srv->sin_family == ina.sin_family &&
204                    srv->sin_port == ina.sin_port &&
205                    (srv->sin_addr.s_addr == INADDR_ANY ||
206                     srv->sin_addr.s_addr == ina.sin_addr.s_addr)) {
207                        ret++;
208                        break;
209                }
210        }
211        return (ret);
212}
213
214/* int
215 * res_nameinquery(name, type, class, buf, eom)
216 *      look for (name,type,class) in the query section of packet (buf,eom)
217 * requires:
218 *      buf + HFIXEDSZ <= eom
219 * returns:
220 *      -1 : format error
221 *      0  : not found
222 *      >0 : found
223 * author:
224 *      paul vixie, 29may94
225 */
226int
227res_nameinquery(name, type, class, buf, eom)
228        const char *name;
229        int type, class;
230        const u_char *buf, *eom;
231{
232        const u_char *cp = buf + HFIXEDSZ;
233        int qdcount = ntohs(((HEADER*)buf)->qdcount);
234
235        while (qdcount-- > 0) {
236                char tname[MAXDNAME+1];
237                int n, ttype, tclass;
238
239                n = dn_expand(buf, eom, cp, tname, sizeof tname);
240                if (n < 0)
241                        return (-1);
242                cp += n;
243                if (cp + 2 * INT16SZ > eom)
244                        return (-1);
245                ttype = ns_get16(cp); cp += INT16SZ;
246                tclass = ns_get16(cp); cp += INT16SZ;
247                if (ttype == type &&
248                    tclass == class &&
249                    strcasecmp(tname, name) == 0)
250                        return (1);
251        }
252        return (0);
253}
254
255/* int
256 * res_queriesmatch(buf1, eom1, buf2, eom2)
257 *      is there a 1:1 mapping of (name,type,class)
258 *      in (buf1,eom1) and (buf2,eom2)?
259 * returns:
260 *      -1 : format error
261 *      0  : not a 1:1 mapping
262 *      >0 : is a 1:1 mapping
263 * author:
264 *      paul vixie, 29may94
265 */
266int
267res_queriesmatch(buf1, eom1, buf2, eom2)
268        const u_char *buf1, *eom1;
269        const u_char *buf2, *eom2;
270{
271        const u_char *cp = buf1 + HFIXEDSZ;
272        int qdcount = ntohs(((HEADER*)buf1)->qdcount);
273
274        if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
275                return (-1);
276
277        /*
278         * Only header section present in replies to
279         * dynamic update packets.
280         */
281        if ( (((HEADER *)buf1)->opcode == ns_o_update) &&
282             (((HEADER *)buf2)->opcode == ns_o_update) )
283                return (1);
284
285        if (qdcount != ntohs(((HEADER*)buf2)->qdcount))
286                return (0);
287        while (qdcount-- > 0) {
288                char tname[MAXDNAME+1];
289                int n, ttype, tclass;
290
291                n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
292                if (n < 0)
293                        return (-1);
294                cp += n;
295                if (cp + 2 * INT16SZ > eom1)
296                        return (-1);
297                ttype = ns_get16(cp);   cp += INT16SZ;
298                tclass = ns_get16(cp); cp += INT16SZ;
299                if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
300                        return (0);
301        }
302        return (1);
303}
304
305int
306res_send(buf, buflen, ans, anssiz)
307        const u_char *buf;
308        int buflen;
309        u_char *ans;
310        int anssiz;
311{
312        HEADER *hp = (HEADER *) buf;
313        HEADER *anhp = (HEADER *) ans;
314        int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns, n;
315        u_int badns;    /* XXX NSMAX can't exceed #/bits in this variable */
316
317        if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
318                /* errno should have been set by res_init() in this case. */
319                return (-1);
320        }
321        if (anssiz < HFIXEDSZ) {
322                errno = EINVAL;
323                return (-1);
324        }
325        DprintQ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY),
326                (stdout, ";; res_send()\n"), buf, buflen);
327        v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
328        gotsomewhere = 0;
329        connreset = 0;
330        terrno = ETIMEDOUT;
331        badns = 0;
332
333        /*
334         * Send request, RETRY times, or until successful
335         */
336        for (try = 0; try < _res.retry; try++) {
337            for (ns = 0; ns < _res.nscount; ns++) {
338                struct sockaddr_in *nsap = &_res.nsaddr_list[ns];
339    same_ns:
340                if (badns & (1 << ns)) {
341                        res_close();
342                        goto next_ns;
343                }
344
345                if (Qhook) {
346                        int done = 0, loops = 0;
347
348                        do {
349                                res_sendhookact act;
350
351                                act = (*Qhook)(&nsap, &buf, &buflen,
352                                               ans, anssiz, &resplen);
353                                switch (act) {
354                                case res_goahead:
355                                        done = 1;
356                                        break;
357                                case res_nextns:
358                                        res_close();
359                                        goto next_ns;
360                                case res_done:
361                                        return (resplen);
362                                case res_modified:
363                                        /* give the hook another try */
364                                        if (++loops < 42) /*doug adams*/
365                                                break;
366                                        /*FALLTHROUGH*/
367                                case res_error:
368                                        /*FALLTHROUGH*/
369                                default:
370                                        return (-1);
371                                }
372                        } while (!done);
373                }
374
375                Dprint(_res.options & RES_DEBUG,
376                       (stdout, ";; Querying server (# %d) address = %s\n",
377                        ns + 1, inet_ntoa(nsap->sin_addr)));
378
379                if (v_circuit) {
380                        int truncated;
381#if !defined(__rtems__)
382                        struct iovec iov[2];
383#endif
384                        u_short len;
385                        u_char *cp;
386
387                        /*
388                         * Use virtual circuit;
389                         * at most one attempt per server.
390                         */
391                        try = _res.retry;
392                        truncated = 0;
393                        if (s < 0 || !vc || hp->opcode == ns_o_update) {
394                                if (s >= 0)
395                                        res_close();
396
397                                s = socket(PF_INET, SOCK_STREAM, 0);
398                                if (s < 0) {
399                                        terrno = errno;
400                                        Perror(stderr, "socket(vc)", errno);
401                                        return (-1);
402                                }
403                                errno = 0;
404                                if (connect(s, (struct sockaddr *)nsap,
405                                            sizeof *nsap) < 0) {
406                                        terrno = errno;
407                                        Aerror(stderr, "connect/vc",
408                                               errno, *nsap);
409                                        badns |= (1 << ns);
410                                        res_close();
411                                        goto next_ns;
412                                }
413                                vc = 1;
414                        }
415                        /*
416                         * Send length & message
417                         */
418                        putshort((u_short)buflen, (u_char*)&len);
419#if !defined(__rtems__)
420                        iov[0].iov_base = (caddr_t)&len;
421                        iov[0].iov_len = INT16SZ;
422                        iov[1].iov_base = (caddr_t)buf;
423                        iov[1].iov_len = buflen;
424                        if (writev(s, iov, 2) != (INT16SZ + buflen)) {
425#else
426                        /*
427                         * RTEMS doesn't have writev (yet)
428                         */
429                        if ((write (s, &len, INT16SZ) != INT16SZ)
430                         || (write (s, buf, buflen) != buflen)) {
431#endif
432                                terrno = errno;
433                                Perror(stderr, "write failed", errno);
434                                badns |= (1 << ns);
435                                res_close();
436                                goto next_ns;
437                        }
438                        /*
439                         * Receive length & response
440                         */
441read_len:
442                        cp = ans;
443                        len = INT16SZ;
444                        while ((n = read(s, (char *)cp, (int)len)) > 0) {
445                                cp += n;
446                                if ((len -= n) <= 0)
447                                        break;
448                        }
449                        if (n <= 0) {
450                                terrno = errno;
451                                Perror(stderr, "read failed", errno);
452                                res_close();
453                                /*
454                                 * A long running process might get its TCP
455                                 * connection reset if the remote server was
456                                 * restarted.  Requery the server instead of
457                                 * trying a new one.  When there is only one
458                                 * server, this means that a query might work
459                                 * instead of failing.  We only allow one reset
460                                 * per query to prevent looping.
461                                 */
462                                if (terrno == ECONNRESET && !connreset) {
463                                        connreset = 1;
464                                        res_close();
465                                        goto same_ns;
466                                }
467                                res_close();
468                                goto next_ns;
469                        }
470                        resplen = ns_get16(ans);
471                        if (resplen > anssiz) {
472                                Dprint(_res.options & RES_DEBUG,
473                                       (stdout, ";; response truncated\n")
474                                       );
475                                truncated = 1;
476                                len = anssiz;
477                        } else
478                                len = resplen;
479                        if (len < HFIXEDSZ) {
480                                /*
481                                 * Undersized message.
482                                 */
483                                Dprint(_res.options & RES_DEBUG,
484                                       (stdout, ";; undersized: %d\n", len));
485                                terrno = EMSGSIZE;
486                                badns |= (1 << ns);
487                                res_close();
488                                goto next_ns;
489                        }
490                        cp = ans;
491                        while (len != 0 &&
492                               (n = read(s, (char *)cp, (int)len)) > 0) {
493                                cp += n;
494                                len -= n;
495                        }
496                        if (n <= 0) {
497                                terrno = errno;
498                                Perror(stderr, "read(vc)", errno);
499                                res_close();
500                                goto next_ns;
501                        }
502                        if (truncated) {
503                                /*
504                                 * Flush rest of answer
505                                 * so connection stays in synch.
506                                 */
507                                anhp->tc = 1;
508                                len = resplen - anssiz;
509                                while (len != 0) {
510                                        char junk[PACKETSZ];
511
512                                        n = (len > sizeof(junk)
513                                             ? sizeof(junk)
514                                             : len);
515                                        if ((n = read(s, junk, n)) > 0)
516                                                len -= n;
517                                        else
518                                                break;
519                                }
520                        }
521                        /*
522                         * The calling applicating has bailed out of
523                         * a previous call and failed to arrange to have
524                         * the circuit closed or the server has got
525                         * itself confused. Anyway drop the packet and
526                         * wait for the correct one.
527                         */
528                        if (hp->id != anhp->id) {
529                                DprintQ((_res.options & RES_DEBUG) ||
530                                        (_res.pfcode & RES_PRF_REPLY),
531                                        (stdout, ";; old answer (unexpected):\n"),
532                                        ans, (resplen>anssiz)?anssiz:resplen);
533                                goto read_len;
534                        }
535                } else {
536                        /*
537                         * Use datagrams.
538                         */
539#ifndef NOPOLL
540                        struct pollfd pfd;
541                        int msec;
542#endif
543                        struct timeval timeout;
544#ifndef NOSELECT
545                        fd_set dsmask, *dsmaskp;
546                        int dsmasklen;
547#endif
548                        struct sockaddr_in from;
549                        socklen_t fromlen;
550
551                        if ((s < 0) || vc) {
552                                if (vc)
553                                        res_close();
554                                s = socket(PF_INET, SOCK_DGRAM, 0);
555                                if (s < 0) {
556#ifndef CAN_RECONNECT
557 bad_dg_sock:
558#endif
559                                        terrno = errno;
560                                        Perror(stderr, "socket(dg)", errno);
561                                        return (-1);
562                                }
563                                connected = 0;
564                        }
565#ifndef CANNOT_CONNECT_DGRAM
566                        /*
567                         * On a 4.3BSD+ machine (client and server,
568                         * actually), sending to a nameserver datagram
569                         * port with no nameserver will cause an
570                         * ICMP port unreachable message to be returned.
571                         * If our datagram socket is "connected" to the
572                         * server, we get an ECONNREFUSED error on the next
573                         * socket operation, and select returns if the
574                         * error message is received.  We can thus detect
575                         * the absence of a nameserver without timing out.
576                         * If we have sent queries to at least two servers,
577                         * however, we don't want to remain connected,
578                         * as we wish to receive answers from the first
579                         * server to respond.
580                         */
581                        if (_res.nscount == 1 || (try == 0 && ns == 0)) {
582                                /*
583                                 * Connect only if we are sure we won't
584                                 * receive a response from another server.
585                                 */
586                                if (!connected) {
587                                        if (connect(s, (struct sockaddr *)nsap,
588                                                    sizeof *nsap
589                                                    ) < 0) {
590                                                Aerror(stderr,
591                                                       "connect(dg)",
592                                                       errno, *nsap);
593                                                badns |= (1 << ns);
594                                                res_close();
595                                                goto next_ns;
596                                        }
597                                        connected = 1;
598                                }
599                                if (send(s, (char*)buf, buflen, 0) != buflen) {
600                                        Perror(stderr, "send", errno);
601                                        badns |= (1 << ns);
602                                        res_close();
603                                        goto next_ns;
604                                }
605                        } else {
606                                /*
607                                 * Disconnect if we want to listen
608                                 * for responses from more than one server.
609                                 */
610                                if (connected) {
611#ifdef CAN_RECONNECT
612                                        struct sockaddr_in no_addr;
613
614                                        no_addr.sin_family = AF_INET;
615                                        no_addr.sin_addr.s_addr = INADDR_ANY;
616                                        no_addr.sin_port = 0;
617                                        (void) connect(s,
618                                                       (struct sockaddr *)
619                                                        &no_addr,
620                                                       sizeof no_addr);
621#else
622                                        int s1 = socket(PF_INET, SOCK_DGRAM,0);
623                                        if (s1 < 0)
624                                                goto bad_dg_sock;
625                                        (void) dup2(s1, s);
626                                        (void) close(s1);
627                                        Dprint(_res.options & RES_DEBUG,
628                                                (stdout, ";; new DG socket\n"))
629#endif /* CAN_RECONNECT */
630                                        connected = 0;
631                                        errno = 0;
632                                }
633#endif /* !CANNOT_CONNECT_DGRAM */
634                                if (sendto(s, (char*)buf, buflen, 0,
635                                           (struct sockaddr *)nsap,
636                                           sizeof *nsap)
637                                    != buflen) {
638                                        Aerror(stderr, "sendto", errno, *nsap);
639                                        badns |= (1 << ns);
640                                        res_close();
641                                        goto next_ns;
642                                }
643#ifndef CANNOT_CONNECT_DGRAM
644                        }
645#endif /* !CANNOT_CONNECT_DGRAM */
646
647                        /*
648                         * Wait for reply
649                         */
650#ifndef NOPOLL
651    othersyscall:
652                        if (use_poll) {
653                                msec = (_res.retrans << try) * 1000;
654                                if (try > 0)
655                                        msec /= _res.nscount;
656                                if (msec <= 0)
657                                        msec = 1000;
658                        } else {
659#endif
660                                timeout.tv_sec = (_res.retrans << try);
661                                if (try > 0)
662                                        timeout.tv_sec /= _res.nscount;
663                                if ((long) timeout.tv_sec <= 0)
664                                        timeout.tv_sec = 1;
665                                timeout.tv_usec = 0;
666#ifndef NOPOLL
667                        }
668#endif
669    wait:
670                        if (s < 0) {
671                                Perror(stderr, "s out-of-bounds", EMFILE);
672                                res_close();
673                                goto next_ns;
674                        }
675#ifndef NOPOLL
676                        if (use_poll) {
677                                struct sigaction sa, osa;
678                                int sigsys_installed = 0;
679
680                                pfd.fd = s;
681                                pfd.events = POLLIN;
682                                if (use_poll == 1) {
683                                        bzero(&sa, sizeof(sa));
684                                        sa.sa_handler = SIG_IGN;
685                                        if (sigaction(SIGSYS, &sa, &osa) >= 0)
686                                                sigsys_installed = 1;
687                                }
688                                n = poll(&pfd, 1, msec);
689                                if (sigsys_installed == 1) {
690                                        int oerrno = errno;
691                                        sigaction(SIGSYS, &osa, NULL);
692                                        errno = oerrno;
693                                }
694                                /* XXX why does nosys() return EINVAL? */
695                                if (n < 0 && (errno == ENOSYS ||
696                                    errno == EINVAL)) {
697                                        use_poll = 0;
698                                        goto othersyscall;
699                                } else if (use_poll == 1)
700                                        use_poll = 2;
701                                if (n < 0) {
702                                        if (errno == EINTR)
703                                                goto wait;
704                                        Perror(stderr, "poll", errno);
705                                        res_close();
706                                        goto next_ns;
707                                }
708                        } else {
709#endif
710#ifndef NOSELECT
711                                dsmasklen = howmany(s + 1, NFDBITS) *
712                                            sizeof(fd_mask);
713                                if (dsmasklen > sizeof(fd_set)) {
714                                        dsmaskp = (fd_set *)malloc(dsmasklen);
715                                        if (dsmaskp == NULL) {
716                                                res_close();
717                                                goto next_ns;
718                                        }
719                                } else
720                                        dsmaskp = &dsmask;
721                                /* only zero what we need */
722                                bzero((char *)dsmaskp, dsmasklen);
723                                FD_SET(s, dsmaskp);
724                                n = select(s + 1, dsmaskp, (fd_set *)NULL,
725                                           (fd_set *)NULL, &timeout);
726                                if (dsmaskp != &dsmask)
727                                        free(dsmaskp);
728                                if (n < 0) {
729                                        if (errno == EINTR)
730                                                goto wait;
731                                        Perror(stderr, "select", errno);
732                                        res_close();
733                                        goto next_ns;
734                                }
735#endif
736#ifndef NOPOLL
737                        }
738#endif
739
740#ifdef NOSELECT
741                        setsockopt (s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof timeout);
742#else
743                        if (n == 0) {
744                                /*
745                                 * timeout
746                                 */
747                                Dprint(_res.options & RES_DEBUG,
748                                       (stdout, ";; timeout\n"));
749                                gotsomewhere = 1;
750                                res_close();
751                                goto next_ns;
752                        }
753#endif
754                        errno = 0;
755                        fromlen = sizeof(struct sockaddr_in);
756                        resplen = recvfrom(s, (char*)ans, anssiz, 0,
757                                           (struct sockaddr *)&from, &fromlen);
758                        if (resplen <= 0) {
759#ifdef NOSELECT
760                                if (errno == ETIMEDOUT) {
761                                        Dprint(_res.options & RES_DEBUG,
762                                               (stdout, ";; timeout\n"));
763                                        gotsomewhere = 1;
764                                        res_close();
765                                        goto next_ns;
766                                }
767#endif
768                                Perror(stderr, "recvfrom", errno);
769                                res_close();
770                                goto next_ns;
771                        }
772                        gotsomewhere = 1;
773                        if (resplen < HFIXEDSZ) {
774                                /*
775                                 * Undersized message.
776                                 */
777                                Dprint(_res.options & RES_DEBUG,
778                                       (stdout, ";; undersized: %d\n",
779                                        resplen));
780                                terrno = EMSGSIZE;
781                                badns |= (1 << ns);
782                                res_close();
783                                goto next_ns;
784                        }
785                        if (hp->id != anhp->id) {
786                                /*
787                                 * response from old query, ignore it.
788                                 * XXX - potential security hazard could
789                                 *       be detected here.
790                                 */
791                                DprintQ((_res.options & RES_DEBUG) ||
792                                        (_res.pfcode & RES_PRF_REPLY),
793                                        (stdout, ";; old answer:\n"),
794                                        ans, (resplen>anssiz)?anssiz:resplen);
795                                goto wait;
796                        }
797#ifdef CHECK_SRVR_ADDR
798                        if (!(_res.options & RES_INSECURE1) &&
799                            !res_isourserver(&from)) {
800                                /*
801                                 * response from wrong server? ignore it.
802                                 * XXX - potential security hazard could
803                                 *       be detected here.
804                                 */
805                                DprintQ((_res.options & RES_DEBUG) ||
806                                        (_res.pfcode & RES_PRF_REPLY),
807                                        (stdout, ";; not our server:\n"),
808                                        ans, (resplen>anssiz)?anssiz:resplen);
809                                goto wait;
810                        }
811#endif
812                        if (!(_res.options & RES_INSECURE2) &&
813                            !res_queriesmatch(buf, buf + buflen,
814                                              ans, ans + anssiz)) {
815                                /*
816                                 * response contains wrong query? ignore it.
817                                 * XXX - potential security hazard could
818                                 *       be detected here.
819                                 */
820                                DprintQ((_res.options & RES_DEBUG) ||
821                                        (_res.pfcode & RES_PRF_REPLY),
822                                        (stdout, ";; wrong query name:\n"),
823                                        ans, (resplen>anssiz)?anssiz:resplen);
824                                goto wait;
825                        }
826                        if (anhp->rcode == SERVFAIL ||
827                            anhp->rcode == NOTIMP ||
828                            anhp->rcode == REFUSED) {
829                                DprintQ(_res.options & RES_DEBUG,
830                                        (stdout, "server rejected query:\n"),
831                                        ans, (resplen>anssiz)?anssiz:resplen);
832                                badns |= (1 << ns);
833                                res_close();
834                                /* don't retry if called from dig */
835                                if (!_res.pfcode)
836                                        goto next_ns;
837                        }
838                        if (!(_res.options & RES_IGNTC) && anhp->tc) {
839                                /*
840                                 * get rest of answer;
841                                 * use TCP with same server.
842                                 */
843                                Dprint(_res.options & RES_DEBUG,
844                                       (stdout, ";; truncated answer\n"));
845                                v_circuit = 1;
846                                res_close();
847                                goto same_ns;
848                        }
849                } /*if vc/dg*/
850                Dprint((_res.options & RES_DEBUG) ||
851                       ((_res.pfcode & RES_PRF_REPLY) &&
852                        (_res.pfcode & RES_PRF_HEAD1)),
853                       (stdout, ";; got answer:\n"));
854                DprintQ((_res.options & RES_DEBUG) ||
855                        (_res.pfcode & RES_PRF_REPLY),
856                        (stdout, "%s", ""),
857                        ans, (resplen>anssiz)?anssiz:resplen);
858                /*
859                 * If using virtual circuits, we assume that the first server
860                 * is preferred over the rest (i.e. it is on the local
861                 * machine) and only keep that one open.
862                 * If we have temporarily opened a virtual circuit,
863                 * or if we haven't been asked to keep a socket open,
864                 * close the socket.
865                 */
866                if ((v_circuit && (!(_res.options & RES_USEVC) || ns != 0)) ||
867                    !(_res.options & RES_STAYOPEN)) {
868                        res_close();
869                }
870                if (Rhook) {
871                        int done = 0, loops = 0;
872
873                        do {
874                                res_sendhookact act;
875
876                                act = (*Rhook)(nsap, buf, buflen,
877                                               ans, anssiz, &resplen);
878                                switch (act) {
879                                case res_goahead:
880                                case res_done:
881                                        done = 1;
882                                        break;
883                                case res_nextns:
884                                        res_close();
885                                        goto next_ns;
886                                case res_modified:
887                                        /* give the hook another try */
888                                        if (++loops < 42) /*doug adams*/
889                                                break;
890                                        /*FALLTHROUGH*/
891                                case res_error:
892                                        /*FALLTHROUGH*/
893                                default:
894                                        return (-1);
895                                }
896                        } while (!done);
897
898                }
899                return (resplen);
900    next_ns: ;
901           } /*foreach ns*/
902        } /*foreach retry*/
903        res_close();
904        if (!v_circuit) {
905                if (!gotsomewhere)
906                        errno = ECONNREFUSED;   /* no nameservers found */
907                else
908                        errno = ETIMEDOUT;      /* no answer obtained */
909        } else
910                errno = terrno;
911        return (-1);
912}
913
914/*
915 * This routine is for closing the socket if a virtual circuit is used and
916 * the program wants to close it.  This provides support for endhostent()
917 * which expects to close the socket.
918 *
919 * This routine is not expected to be user visible.
920 */
921void
922res_close()
923{
924        if (s >= 0) {
925                (void) close(s);
926                s = -1;
927                connected = 0;
928                vc = 0;
929        }
930}
Note: See TracBrowser for help on using the repository browser.