home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / NETWORK / ISP / bind.4.8.3.lzh / BIND483 / RES / res_send.c < prev    next >
Text File  |  1994-09-23  |  10KB  |  439 lines

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