source: rtems/cpukit/libnetworking/libc/res_send.c @ 9d647dfc

4.104.114.84.95
Last change on this file since 9d647dfc was ce75da6, checked in by Joel Sherrill <joel.sherrill@…>, on 07/24/02 at 13:25:06

2002-07-24 Joel Sherrill <joel@…>

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