home *** CD-ROM | disk | FTP | other *** search
/ Aminet 18 / aminetcdnumber181997.iso / Aminet / dev / gcc / ixemulsrc.lha / ixemul / net / res_send.c < prev    next >
C/C++ Source or Header  |  1996-12-11  |  13KB  |  480 lines

  1. /*    $NetBSD: res_send.c,v 1.4 1995/02/25 06:21:01 cgd Exp $    */
  2.  
  3. /*-
  4.  * Copyright (c) 1985, 1989, 1993
  5.  *    The Regents of the University of California.  All rights reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  * 1. Redistributions of source code must retain the above copyright
  11.  *    notice, this list of conditions and the following disclaimer.
  12.  * 2. Redistributions in binary form must reproduce the above copyright
  13.  *    notice, this list of conditions and the following disclaimer in the
  14.  *    documentation and/or other materials provided with the distribution.
  15.  * 3. All advertising materials mentioning features or use of this software
  16.  *    must display the following acknowledgement:
  17.  *    This product includes software developed by the University of
  18.  *    California, Berkeley and its contributors.
  19.  * 4. Neither the name of the University nor the names of its contributors
  20.  *    may be used to endorse or promote products derived from this software
  21.  *    without specific prior written permission.
  22.  *
  23.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  24.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  27.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  29.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  30.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  32.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  33.  * SUCH DAMAGE.
  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.  * --Copyright--
  54.  */
  55.  
  56. #if defined(LIBC_SCCS) && !defined(lint)
  57. #if 0
  58. static char sccsid[] = "@(#)res_send.c    8.1 (Berkeley) 6/4/93";
  59. static char rcsid[] = "$Id: res_send.c,v 4.9.1.1 1993/05/02 22:43:03 vixie Rel ";
  60. #else
  61. static char rcsid[] = "$NetBSD: res_send.c,v 1.4 1995/02/25 06:21:01 cgd Exp $";
  62. #endif
  63. #endif /* LIBC_SCCS and not lint */
  64.  
  65. /*
  66.  * Send query to name server and wait for reply.
  67.  */
  68.  
  69. #include <sys/param.h>
  70. #include <sys/time.h>
  71. #include <sys/socket.h>
  72. #include <sys/uio.h>
  73. #include <netinet/in.h>
  74. #include <arpa/nameser.h>
  75. #include <arpa/inet.h>
  76. #include <stdio.h>
  77. #include <errno.h>
  78. #include <resolv.h>
  79. #include <unistd.h>
  80. #include <string.h>
  81.  
  82. /*static int s = -1;*/    /* socket used for communications */
  83. extern int _res_socket;
  84. #define s _res_socket
  85.  
  86. static struct sockaddr no_addr;
  87.  
  88. #ifndef FD_SET
  89. #define    NFDBITS        32
  90. #define    FD_SETSIZE    32
  91. #define    FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
  92. #define    FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
  93. #define    FD_ISSET(n, p)    ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
  94. #define FD_ZERO(p)    bzero((char *)(p), sizeof(*(p)))
  95. #endif
  96.  
  97. int
  98. res_send(buf, buflen, answer, anslen)
  99.     const char *buf;
  100.     int buflen;
  101.     char *answer;
  102.     int anslen;
  103. {
  104.     register int n;
  105.     int try, v_circuit, resplen, ns;
  106.     int gotsomewhere = 0, connected = 0;
  107.     int connreset = 0;
  108.     u_short id, len;
  109.     char *cp;
  110.     fd_set dsmask;
  111.     struct timeval timeout;
  112.     HEADER *hp = (HEADER *) buf;
  113.     HEADER *anhp = (HEADER *) answer;
  114.     u_int badns;        /* XXX NSMAX can't exceed #/bits per this */
  115.     struct iovec iov[2];
  116.     int terrno = ETIMEDOUT;
  117.     char junk[512];
  118.  
  119. #ifdef DEBUG
  120.     if ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY)) {
  121.         printf(";; res_send()\n");
  122.         __p_query(buf);
  123.     }
  124. #endif
  125.     if (!(_res.options & RES_INIT))
  126.         if (res_init() == -1) {
  127.             return(-1);
  128.         }
  129.     v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
  130.     id = hp->id;
  131.     badns = 0;
  132.     /*
  133.      * Send request, RETRY times, or until successful
  134.      */
  135.     for (try = 0; try < _res.retry; try++) {
  136.         for (ns = 0; ns < _res.nscount; ns++) {
  137.         if (badns & (1<<ns))
  138.             continue;
  139. #ifdef DEBUG
  140.         if (_res.options & RES_DEBUG)
  141.             printf(";; Querying server (# %d) address = %s\n",
  142.                    ns+1,
  143.                    inet_ntoa(_res.nsaddr_list[ns].sin_addr));
  144. #endif
  145.     usevc:
  146.         if (v_circuit) {
  147.             int truncated = 0;
  148.  
  149.             /*
  150.              * Use virtual circuit;
  151.              * at most one attempt per server.
  152.              */
  153.             try = _res.retry;
  154.             if (s < 0) {
  155.                 s = socket(AF_INET, SOCK_STREAM, 0);
  156.                 if (s < 0) {
  157.                     terrno = errno;
  158. #ifdef DEBUG
  159.                     if (_res.options & RES_DEBUG)
  160.                         perror("socket (vc) failed");
  161. #endif
  162.                     continue;
  163.                 }
  164.                 if (connect(s,
  165.                     (struct sockaddr *)&(_res.nsaddr_list[ns]),
  166.                     sizeof(struct sockaddr)) < 0) {
  167.                     terrno = errno;
  168. #ifdef DEBUG
  169.                     if (_res.options & RES_DEBUG)
  170.                         perror("connect failed");
  171. #endif
  172.                     (void) close(s);
  173.                     s = -1;
  174.                     continue;
  175.                 }
  176.             }
  177.             /*
  178.              * Send length & message
  179.              */
  180.             len = htons((u_short)buflen);
  181.             iov[0].iov_base = (caddr_t)&len;
  182.             iov[0].iov_len = sizeof(len);
  183.             iov[1].iov_base = (char *)buf;
  184.             iov[1].iov_len = buflen;
  185.             if (writev(s, iov, 2) != sizeof(len) + buflen) {
  186.                 terrno = errno;
  187. #ifdef DEBUG
  188.                 if (_res.options & RES_DEBUG)
  189.                     perror("write failed");
  190. #endif
  191.                 (void) close(s);
  192.                 s = -1;
  193.                 continue;
  194.             }
  195.             /*
  196.              * Receive length & response
  197.              */
  198.             cp = answer;
  199.             len = sizeof(short);
  200.             while (len != 0 &&
  201.                 (n = read(s, (char *)cp, (int)len)) > 0) {
  202.                 cp += n;
  203.                 len -= n;
  204.             }
  205.             if (n <= 0) {
  206.                 terrno = errno;
  207. #ifdef DEBUG
  208.                 if (_res.options & RES_DEBUG)
  209.                     perror("read failed");
  210. #endif
  211.                 (void) close(s);
  212.                 s = -1;
  213.                 /*
  214.                  * A long running process might get its TCP
  215.                  * connection reset if the remote server was
  216.                  * restarted.  Requery the server instead of
  217.                  * trying a new one.  When there is only one
  218.                  * server, this means that a query might work
  219.                  * instead of failing.  We only allow one reset
  220.                  * per query to prevent looping.
  221.                  */
  222.                 if (terrno == ECONNRESET && !connreset) {
  223.                     connreset = 1;
  224.                     ns--;
  225.                 }
  226.                 continue;
  227.             }
  228.             cp = answer;
  229.             if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
  230. #ifdef DEBUG
  231.                 if (_res.options & RES_DEBUG)
  232.                     fprintf(stderr,
  233.                         ";; response truncated\n");
  234. #endif
  235.                 len = anslen;
  236.                 truncated = 1;
  237.             } else
  238.                 len = resplen;
  239.             while (len != 0 &&
  240.                (n = read(s, (char *)cp, (int)len)) > 0) {
  241.                 cp += n;
  242.                 len -= n;
  243.             }
  244.             if (n <= 0) {
  245.                 terrno = errno;
  246. #ifdef DEBUG
  247.                 if (_res.options & RES_DEBUG)
  248.                     perror("read failed");
  249. #endif
  250.                 (void) close(s);
  251.                 s = -1;
  252.                 continue;
  253.             }
  254.             if (truncated) {
  255.                 /*
  256.                  * Flush rest of answer
  257.                  * so connection stays in synch.
  258.                  */
  259.                 anhp->tc = 1;
  260.                 len = resplen - anslen;
  261.                 while (len != 0) {
  262.                     n = (len > sizeof(junk) ?
  263.                         sizeof(junk) : len);
  264.                     if ((n = read(s, junk, n)) > 0)
  265.                         len -= n;
  266.                     else
  267.                         break;
  268.                 }
  269.             }
  270.         } else {
  271.             /*
  272.              * Use datagrams.
  273.              */
  274.             if (s < 0) {
  275.                 s = socket(AF_INET, SOCK_DGRAM, 0);
  276.                 if (s < 0) {
  277.                     terrno = errno;
  278. #ifdef DEBUG
  279.                     if (_res.options & RES_DEBUG)
  280.                         perror("socket (dg) failed");
  281. #endif
  282.                     continue;
  283.                 }
  284.             }
  285.             /*
  286.              * I'm tired of answering this question, so:
  287.              * On a 4.3BSD+ machine (client and server,
  288.              * actually), sending to a nameserver datagram
  289.              * port with no nameserver will cause an
  290.              * ICMP port unreachable message to be returned.
  291.              * If our datagram socket is "connected" to the
  292.              * server, we get an ECONNREFUSED error on the next
  293.              * socket operation, and select returns if the
  294.              * error message is received.  We can thus detect
  295.              * the absence of a nameserver without timing out.
  296.              * If we have sent queries to at least two servers,
  297.              * however, we don't want to remain connected,
  298.              * as we wish to receive answers from the first
  299.              * server to respond.
  300.              */
  301.             if (_res.nscount == 1 || (try == 0 && ns == 0)) {
  302.                 /*
  303.                  * Don't use connect if we might
  304.                  * still receive a response
  305.                  * from another server.
  306.                  */
  307.                 if (connected == 0) {
  308.                     if (connect(s,
  309.                         (struct sockaddr *)
  310.                         &_res.nsaddr_list[ns],
  311.                         sizeof(struct sockaddr)) < 0) {
  312. #ifdef DEBUG
  313.                         if (_res.options & RES_DEBUG)
  314.                             perror("connect");
  315. #endif
  316.                         continue;
  317.                     }
  318.                     connected = 1;
  319.                 }
  320.                 if (send(s, buf, buflen, 0) != buflen) {
  321. #ifdef DEBUG
  322.                     if (_res.options & RES_DEBUG)
  323.                         perror("send");
  324. #endif
  325.                     continue;
  326.                 }
  327.             } else {
  328.                 /*
  329.                  * Disconnect if we want to listen
  330.                  * for responses from more than one server.
  331.                  */
  332.                 if (connected) {
  333.                     (void) connect(s, &no_addr,
  334.                         sizeof(no_addr));
  335.                     connected = 0;
  336.                 }
  337.                 if (sendto(s, buf, buflen, 0,
  338.                     (struct sockaddr *)&_res.nsaddr_list[ns],
  339.                     sizeof(struct sockaddr)) != buflen) {
  340. #ifdef DEBUG
  341.                     if (_res.options & RES_DEBUG)
  342.                         perror("sendto");
  343. #endif
  344.                     continue;
  345.                 }
  346.             }
  347.  
  348.             /*
  349.              * Wait for reply
  350.              */
  351.             timeout.tv_sec = (_res.retrans << try);
  352.             if (try > 0)
  353.                 timeout.tv_sec /= _res.nscount;
  354.             if ((long) timeout.tv_sec <= 0)
  355.                 timeout.tv_sec = 1;
  356.             timeout.tv_usec = 0;
  357. wait:
  358.             FD_ZERO(&dsmask);
  359.             FD_SET(s, &dsmask);
  360.             n = select(s+1, &dsmask, (fd_set *)NULL,
  361.                 (fd_set *)NULL, &timeout);
  362.             if (n < 0) {
  363. #ifdef DEBUG
  364.                 if (_res.options & RES_DEBUG)
  365.                     perror("select");
  366. #endif
  367.                 continue;
  368.             }
  369.             if (n == 0) {
  370.                 /*
  371.                  * timeout
  372.                  */
  373. #ifdef DEBUG
  374.                 if (_res.options & RES_DEBUG)
  375.                     printf(";; timeout\n");
  376. #endif
  377.                 gotsomewhere = 1;
  378.                 continue;
  379.             }
  380.             if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
  381. #ifdef DEBUG
  382.                 if (_res.options & RES_DEBUG)
  383.                     perror("recvfrom");
  384. #endif
  385.                 continue;
  386.             }
  387.             gotsomewhere = 1;
  388.             if (id != anhp->id) {
  389.                 /*
  390.                  * response from old query, ignore it
  391.                  */
  392. #ifdef DEBUG
  393.                 if ((_res.options & RES_DEBUG) ||
  394.                     (_res.pfcode & RES_PRF_REPLY)) {
  395.                     printf(";; old answer:\n");
  396.                     __p_query(answer);
  397.                 }
  398. #endif
  399.                 goto wait;
  400.             }
  401.             if (anhp->rcode == SERVFAIL || anhp->rcode == NOTIMP ||
  402.                 anhp->rcode == REFUSED) {
  403. #ifdef DEBUG
  404.                 if (_res.options & RES_DEBUG) {
  405.                     printf("server rejected query:\n");
  406.                     __p_query(answer);
  407.                 }
  408. #endif
  409.                 badns |= (1<<ns);
  410.                 continue;
  411.             }
  412.             if (!(_res.options & RES_IGNTC) && anhp->tc) {
  413.                 /*
  414.                  * get rest of answer;
  415.                  * use TCP with same server.
  416.                  */
  417. #ifdef DEBUG
  418.                 if (_res.options & RES_DEBUG)
  419.                     printf(";; truncated answer\n");
  420. #endif
  421.                 (void) close(s);
  422.                 s = -1;
  423.                 v_circuit = 1;
  424.                 goto usevc;
  425.             }
  426.         }
  427. #ifdef DEBUG
  428.         if (_res.options & RES_DEBUG)
  429.             printf(";; got answer:\n");
  430.         if ((_res.options & RES_DEBUG) ||
  431.             (_res.pfcode & RES_PRF_REPLY))
  432.             __p_query(answer);
  433. #endif
  434.         /*
  435.          * If using virtual circuits, we assume that the first server
  436.          * is preferred * over the rest (i.e. it is on the local
  437.          * machine) and only keep that one open.
  438.          * If we have temporarily opened a virtual circuit,
  439.          * or if we haven't been asked to keep a socket open,
  440.          * close the socket.
  441.          */
  442.         if ((v_circuit &&
  443.             ((_res.options & RES_USEVC) == 0 || ns != 0)) ||
  444.             (_res.options & RES_STAYOPEN) == 0) {
  445.             (void) close(s);
  446.             s = -1;
  447.         }
  448.         return (resplen);
  449.        }
  450.     }
  451.     if (s >= 0) {
  452.         (void) close(s);
  453.         s = -1;
  454.     }
  455.     if (v_circuit == 0)
  456.         if (gotsomewhere == 0)
  457.             errno = ECONNREFUSED;    /* no nameservers found */
  458.         else
  459.             errno = ETIMEDOUT;    /* no answer obtained */
  460.     else
  461.         errno = terrno;
  462.     return (-1);
  463. }
  464.  
  465. /*
  466.  * This routine is for closing the socket if a virtual circuit is used and
  467.  * the program wants to close it.  This provides support for endhostent()
  468.  * which expects to close the socket.
  469.  *
  470.  * This routine is not expected to be user visible.
  471.  */
  472. void
  473. _res_close()
  474. {
  475.     if (s != -1) {
  476.         (void) close(s);
  477.         s = -1;
  478.     }
  479. }
  480.