source: rtems/cpukit/libnetworking/libc/res_send.c @ 39f13cb

4.104.115
Last change on this file since 39f13cb was 39f13cb, checked in by Ralf Corsepius <ralf.corsepius@…>, on 03/27/10 at 04:00:53

Add HAVE_STRINGS_H for better POSIX compliance.

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