source: rtems/cpukit/libnetworking/libc/res_send.c @ b2b143f4

4.104.114.84.95
Last change on this file since b2b143f4 was b2b143f4, checked in by Joel Sherrill <joel.sherrill@…>, on 03/05/04 at 17:58:51

2004-03-05 Joel Sherrill <joel@…>

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