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