home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume26 / ns2tab / part01 / send.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-04  |  8.0 KB  |  354 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/types.h>
  42. #include <sys/param.h>
  43. #include <sys/time.h>
  44. #include <sys/socket.h>
  45. #include <sys/uio.h>
  46. #include <netinet/in.h>
  47. #include <stdio.h>
  48. #include <errno.h>
  49. #include <arpa/nameser.h>
  50. #include <arpa/inet.h>
  51. #include <resolv.h>
  52. #include "res.h"
  53.  
  54. #ifdef ultrix
  55. #define nsaddr_list(i)  ns_list[(i)].addr
  56. #else
  57. #define nsaddr_list(i)  nsaddr_list[(i)]
  58. #endif
  59.  
  60. extern int errno;
  61.  
  62. static int s = -1;    /* socket used for communications */
  63.  
  64.  
  65. #ifndef FD_SET
  66. #define    NFDBITS        32
  67. #define    FD_SETSIZE    32
  68. #define    FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
  69. #define    FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
  70. #define    FD_ISSET(n, p)    ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
  71. #define FD_ZERO(p)    bzero((char *)(p), sizeof(*(p)))
  72. #endif
  73.  
  74. #define SR 1        /* SendRequest style */
  75.  
  76. #ifndef DEBUG
  77. #define DEBUG
  78. #endif
  79.  
  80. unsigned short nsport = NAMESERVER_PORT;
  81.  
  82.  
  83.  
  84. /*
  85.  *******************************************************************************
  86.  *
  87.  *   SendRequest --
  88.  *
  89.  *    Sends a request packet to a name server whose address
  90.  *    is specified by the first argument and returns with
  91.  *    the answer packet.
  92.  *
  93.  *  Results:
  94.  *    SUCCESS        - the request was sent and an answer
  95.  *              was received.
  96.  *    TIME_OUT    - the virtual circuit connection timed-out
  97.  *              or a reply to a datagram wasn't received.
  98.  *
  99.  *
  100.  *******************************************************************************
  101.  */
  102.  
  103. int
  104. SendRequest(nsAddrPtr, buf, buflen, answer, anslen, trueLenPtr)
  105.     struct in_addr    *nsAddrPtr;
  106.     char        *buf;
  107.     int        buflen;
  108.     char        *answer;
  109.     u_int        anslen;
  110.     int        *trueLenPtr;
  111. {
  112.     register int n;
  113.     int try, resplen, ns;
  114.     int gotsomewhere = 0, connected = 0;
  115.     int connreset = 0;
  116.     u_short id, len;
  117.     char *cp;
  118.     fd_set dsmask;
  119.     struct timeval timeout;
  120.     HEADER *hp = (HEADER *) buf;
  121.     HEADER *anhp = (HEADER *) answer;
  122.     struct iovec iov[2];
  123.     int terrno = ETIMEDOUT;
  124.     char junk[512];
  125.  
  126. #if SR
  127.     struct sockaddr_in sin;
  128.  
  129.     if (_res.options & RES_DEBUG2) {
  130.         printf("------------\nSendRequest(), len %d\n", buflen);
  131.         Print_query(buf, buf+buflen, 1);
  132.     }
  133.     sin.sin_family    = AF_INET;
  134.     sin.sin_port    = htons(nsport);
  135.     sin.sin_addr    = *nsAddrPtr;
  136. #else
  137. #ifdef DEBUG
  138.     if (_res.options & RES_DEBUG) {
  139.         printf("res_send()\n");
  140.         p_query(buf);
  141.     }
  142. #endif
  143.     if (!(_res.options & RES_INIT))
  144.         if (res_init() == -1) {
  145.             return(-1);
  146.         }
  147. #endif /* SR */
  148.     id = hp->id;
  149.     /*
  150.      * Send request, RETRY times, or until successful
  151.      */
  152.     for (try = 0; try < _res.retry; try++) {
  153. #if !SR
  154.        for (ns = 0; ns < _res.nscount; ns++) {
  155. #ifdef DEBUG
  156.         if (_res.options & RES_DEBUG)
  157.             printf("Querying server (# %d) address = %s\n", ns+1,
  158.                   inet_ntoa(_res.nsaddr_list(ns).sin_addr));
  159. #endif
  160. #endif /* !SR */
  161.     usevc:
  162.         {
  163.             int truncated = 0;
  164.  
  165.             /*
  166.              * Use virtual circuit;
  167.              * at most one attempt per server.
  168.              */
  169.             try = _res.retry;
  170.             if (s < 0) {
  171.                 s = socket(AF_INET, SOCK_STREAM, 0);
  172.                 if (s < 0) {
  173.                     terrno = errno;
  174. #ifdef DEBUG
  175.                     if (_res.options & RES_DEBUG)
  176.                         perror("socket (vc) failed");
  177. #endif
  178.                     continue;
  179.                 }
  180. #if SR
  181.                 if (connect(s, &sin,
  182. #else
  183.                 if (connect(s, &(_res.nsaddr_list(ns)),
  184. #endif
  185.                    sizeof(struct sockaddr)) < 0) {
  186.                     terrno = errno;
  187. #ifdef DEBUG
  188.                     if (_res.options & RES_DEBUG)
  189.                         perror("connect failed");
  190. #endif
  191.                     (void) close(s);
  192.                     s = -1;
  193.                     continue;
  194.                 }
  195.             }
  196.             /*
  197.              * Send length & message
  198.              */
  199.             len = htons((u_short)buflen);
  200.             iov[0].iov_base = (caddr_t)&len;
  201.             iov[0].iov_len = sizeof(len);
  202.             iov[1].iov_base = buf;
  203.             iov[1].iov_len = buflen;
  204.             if (writev(s, iov, 2) != sizeof(len) + buflen) {
  205.                 terrno = errno;
  206. #ifdef DEBUG
  207.                 if (_res.options & RES_DEBUG)
  208.                     perror("write failed");
  209. #endif
  210.                 (void) close(s);
  211.                 s = -1;
  212.                 continue;
  213.             }
  214.             /*
  215.              * Receive length & response
  216.              */
  217.             cp = answer;
  218.             len = sizeof(short);
  219.             while (len != 0 &&
  220.                 (n = read(s, (char *)cp, (int)len)) > 0) {
  221.                 cp += n;
  222.                 len -= n;
  223.             }
  224.             if (n <= 0) {
  225.                 terrno = errno;
  226. #ifdef DEBUG
  227.                 if (_res.options & RES_DEBUG)
  228.                     perror("read failed");
  229. #endif
  230.                 (void) close(s);
  231.                 s = -1;
  232.                 /*
  233.                  * A long running process might get its TCP
  234.                  * connection reset if the remote server was
  235.                  * restarted.  Requery the server instead of
  236.                  * trying a new one.  When there is only one
  237.                  * server, this means that a query might work
  238.                  * instead of failing.  We only allow one reset
  239.                  * per query to prevent looping.
  240.                  */
  241.                 if (terrno == ECONNRESET && !connreset) {
  242.                     connreset = 1;
  243.                     ns--;
  244.                 }
  245.                 continue;
  246.             }
  247.             cp = answer;
  248.             if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
  249. #ifdef DEBUG
  250.                 if (_res.options & RES_DEBUG)
  251.                     fprintf(stderr, "response truncated\n");
  252. #endif
  253.                 len = anslen;
  254.                 truncated = 1;
  255.             } else
  256.                 len = resplen;
  257.             while (len != 0 &&
  258.                (n = read(s, (char *)cp, (int)len)) > 0) {
  259.                 cp += n;
  260.                 len -= n;
  261.             }
  262.             if (n <= 0) {
  263.                 terrno = errno;
  264. #ifdef DEBUG
  265.                 if (_res.options & RES_DEBUG)
  266.                     perror("read failed");
  267. #endif
  268.                 (void) close(s);
  269.                 s = -1;
  270.                 continue;
  271.             }
  272.             if (truncated) {
  273.                 /*
  274.                  * Flush rest of answer
  275.                  * so connection stays in synch.
  276.                  */
  277.                 anhp->tc = 1;
  278.                 len = resplen - anslen;
  279.                 while (len != 0) {
  280.                     n = (len > sizeof(junk) ?
  281.                         sizeof(junk) : len);
  282.                     if ((n = read(s, junk, n)) > 0)
  283.                         len -= n;
  284.                     else
  285.                         break;
  286.                 }
  287.             }
  288.         }
  289. #if SR
  290.         if (_res.options & RES_DEBUG) {
  291.             if (_res.options & RES_DEBUG2)
  292.             printf("------------\nGot answer (%d bytes):\n",
  293.                 resplen);
  294.             else
  295.             printf("------------\nGot answer:\n");
  296.             Print_query(answer, answer+resplen, 1);
  297.         }
  298.         (void) close(s);
  299.         s = -1;
  300.         *trueLenPtr = resplen;
  301.         return (SUCCESS);
  302. #else
  303. #ifdef DEBUG
  304.         if (_res.options & RES_DEBUG) {
  305.             printf("got answer:\n");
  306.             p_query(answer);
  307.         }
  308. #endif
  309.         /*
  310.          * If using virtual circuits, we assume that the first server
  311.          * is preferred * over the rest (i.e. it is on the local
  312.          * machine) and only keep that one open.
  313.          * If we have temporarily opened a virtual circuit,
  314.          * or if we haven't been asked to keep a socket open,
  315.          * close the socket.
  316.          */
  317.         if ( ((_res.options & RES_USEVC) == 0 || ns != 0) ||
  318.             (_res.options & RES_STAYOPEN) == 0) {
  319.             (void) close(s);
  320.             s = -1;
  321.         }
  322.         return (resplen);
  323.        }
  324. #endif /* SR */
  325.     }
  326.     if (s >= 0) {
  327.         (void) close(s);
  328.         s = -1;
  329.     }
  330. #if SR
  331.     if (errno == ECONNREFUSED)
  332.         return NO_RESPONSE;
  333.     else
  334.         return ERROR;
  335. #else
  336.     errno = terrno;
  337.     return (-1);
  338. #endif
  339. }
  340.  
  341. /*
  342.  * This routine is for closing the socket if a virtual circuit is used and
  343.  * the program wants to close it.
  344.  *
  345.  * Called from the interrupt handler.
  346.  */
  347. SendRequest_close()
  348. {
  349.     if (s != -1) {
  350.         (void) close(s);
  351.         s = -1;
  352.     }
  353. }
  354.