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