home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 8 / FreshFishVol8-CD2.bin / bbs / comm / amitcp-3.0ß2.lha / AmiTCP / src / amitcp / api / res_send.c < prev    next >
C/C++ Source or Header  |  1994-04-02  |  12KB  |  431 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, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  
  32.  */
  33.  
  34. #if defined(LIBC_SCCS) && !defined(lint)
  35. static char sccsid[] = "@(#)res_send.c    6.27 (Berkeley) 2/24/91";
  36. #endif /* LIBC_SCCS and not lint */
  37.  
  38. /*
  39.  * Send query to name server and wait for reply.
  40.  */
  41.  
  42. #include <conf.h>
  43.  
  44. #include <sys/param.h>
  45. #include <sys/systm.h>
  46. #include <sys/malloc.h>
  47. #include <sys/time.h>
  48. #include <sys/socket.h>
  49. #include <netinet/in.h>
  50. #include <sys/errno.h>
  51.  
  52. #include <api/arpa_nameser.h>
  53. #include <api/resolv.h>
  54. #include <kern/amiga_includes.h>
  55. #include <api/apicalls.h>
  56. #include <api/amiga_api.h>
  57. #include <kern/amiga_subr.h>     
  58. #include <kern/amiga_netdb.h>     
  59.  
  60. #ifndef AMITCP /* AmiTCP has this in the SocketBase */     
  61. static int res_sock = -1;    /* socket used for communications */
  62. #endif
  63.  
  64. /* constant */
  65. static const struct sockaddr no_addr = { sizeof(struct sockaddr), AF_INET, 0 };
  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. int
  77. res_send(struct SocketBase *    libPtr,
  78.      const char *        buf,
  79.      int            buflen,
  80.      char *            answer,
  81.      int             anslen)
  82. {
  83.     register int n;
  84.     int try, v_circuit, resplen, nscount;
  85.     int gotsomewhere = 0, connected = 0;
  86.     int connreset = 0;
  87.     u_short id, len;
  88.     char *cp;
  89.     fd_set dsmask;
  90.     struct timeval timeout;
  91.     struct NameserventNode *ns;
  92.     struct sockaddr_in host;
  93.     HEADER *hp = (HEADER *) buf;
  94.     HEADER *anhp = (HEADER *) answer;
  95.     u_char terrno = ETIMEDOUT;
  96. #define JUNK_SIZE 512
  97.     char junk[JUNK_SIZE]; /* buffer for trash data */
  98.  
  99. #ifdef RES_DEBUG
  100.         printf("res_send()\n");
  101.         __p_query(buf);
  102. #endif /* RES_DEBUG */
  103.  
  104.     v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
  105.     id = hp->id;
  106.     /*
  107.      * Send request, RETRY times, or until successful
  108.      */
  109.     for (try = 0; try < _res.retry; try++) {
  110.       nscount = 0;
  111.       for (ns = (struct NameserventNode *)NDB->ndb_NameServers.mlh_Head;
  112.            ns->nsn_Node.mln_Succ;
  113.            ns = (struct NameserventNode *)ns->nsn_Node.mln_Succ) {
  114.         nscount++;
  115. #ifdef RES_DEBUG
  116.             printf("Querying server #%d address = %s\n", nscount,
  117.                   inet_ntoa(ns->nsn_Ent.ns_addr));
  118. #endif /* RES_DEBUG */
  119.         host.sin_len = sizeof(host);
  120.         host.sin_family = AF_INET;
  121.         host.sin_port = NAMESERVER_PORT;
  122.         host.sin_addr = ns->nsn_Ent.ns_addr;
  123.         aligned_bzero_const(&host.sin_zero, sizeof(host.sin_zero));
  124.     usevc:
  125.         if (v_circuit) {
  126.             int truncated = 0;
  127.  
  128.             /*
  129.              * Use virtual circuit;
  130.              * at most one attempt per server.
  131.              */
  132.             try = _res.retry;
  133.             if (res_sock < 0) {
  134.                 res_sock = socket(libPtr, AF_INET, SOCK_STREAM, 0);
  135.                 if (res_sock < 0) {
  136.                     terrno = readErrnoValue(libPtr);
  137. #ifdef RES_DEBUG
  138.                         perror("socket (vc) failed");
  139. #endif /* RES_DEBUG */
  140.                     continue;
  141.                 }
  142.                 if (connect(libPtr, res_sock,
  143.                         (struct sockaddr *)&host,
  144.                         sizeof(struct sockaddr)) < 0) {
  145.                         terrno = readErrnoValue(libPtr);
  146. #ifdef RES_DEBUG
  147.                         perror("connect failed");
  148. #endif /* RES_DEBUG */
  149.                     (void) CloseSocket(libPtr, res_sock);
  150.                     res_sock = -1;
  151.                     continue;
  152.                 }
  153.             }
  154.             /*
  155.              * Send length & message
  156.              */
  157.             len = htons((u_short)buflen);
  158.             if ((send(libPtr, res_sock, (char *)&len, sizeof(len), 0)
  159.                  != sizeof(len)) ||
  160.                ((send(libPtr, res_sock, (char *)buf, buflen, 0)
  161.                  != buflen))) {
  162.                 terrno = readErrnoValue(libPtr);
  163. #ifdef RES_DEBUG
  164.                     perror("write failed");
  165. #endif /* RES_DEBUG */
  166.                 (void) CloseSocket(libPtr, res_sock);
  167.                 res_sock = -1;
  168.                 continue;
  169.             }
  170.             /*
  171.              * Receive length & response
  172.              */
  173.             cp = answer;
  174.             len = sizeof(short);
  175.             while (len != 0 &&
  176.                 (n = recv(libPtr, res_sock,
  177.                       (char *)cp, (int)len, 0)) > 0) {
  178.                 cp += n;
  179.                 len -= n;
  180.             }
  181.             if (n <= 0) {
  182.                 terrno = readErrnoValue(libPtr);
  183. #ifdef RES_DEBUG
  184.                     perror("read failed");
  185. #endif /* RES_DEBUG */
  186.                 (void) CloseSocket(libPtr, res_sock);
  187.                 res_sock = -1;
  188.                 /*
  189.                  * A long running process might get its TCP
  190.                  * connection reset if the remote server was
  191.                  * restarted.  Requery the server instead of
  192.                  * trying a new one.  When there is only one
  193.                  * server, this means that a query might work
  194.                  * instead of failing.  We only allow one reset
  195.                  * per query to prevent looping.
  196.                  */
  197.                 if (terrno == ECONNRESET && !connreset) {
  198.                     connreset = 1;
  199.                     ns--;
  200.                 }
  201.                 continue;
  202.             }
  203.             cp = answer;
  204.             if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
  205. #ifdef RES_DEBUG
  206.                            fprintf(stderr, "response truncated\n");
  207. #endif /* RES_DEBUG */
  208.                 len = anslen;
  209.                 truncated = 1;
  210.             } else
  211.                 len = resplen;
  212.             while (len != 0 &&
  213.                (n = recv(libPtr, res_sock,
  214.                      (char *)cp, (int)len, 0)) > 0) {
  215.                 cp += n;
  216.                 len -= n;
  217.             }
  218.             if (n <= 0) {
  219.                 terrno = readErrnoValue(libPtr);
  220. #ifdef RES_DEBUG
  221.                     perror("read failed");
  222. #endif /* RES_DEBUG */
  223.                 (void) CloseSocket(libPtr, res_sock);
  224.                 res_sock = -1;
  225.                 continue;
  226.             }
  227.             if (truncated) {
  228.                 /*
  229.                  * Flush rest of answer
  230.                  * so connection stays in synch.
  231.                  */
  232.                 anhp->tc = 1;
  233.                 len = resplen - anslen;
  234.                 while (len != 0) {
  235.                     n = (len > JUNK_SIZE ? JUNK_SIZE : len);
  236.                     if ((n = recv(libPtr, res_sock,
  237.                               junk, n, 0)) > 0)
  238.                         len -= n;
  239.                     else
  240.                         break;
  241.                 }
  242.             }
  243.         } else {
  244.             /*
  245.              * Use datagrams.
  246.              */
  247.             if (res_sock < 0) {
  248.                 res_sock = socket(libPtr, AF_INET, SOCK_DGRAM, 0);
  249.                 if (res_sock < 0) {
  250.                     terrno = readErrnoValue(libPtr);
  251. #ifdef RES_DEBUG
  252.                         perror("socket (dg) failed");
  253. #endif /* RES_DEBUG */
  254.                     continue;
  255.                 }
  256.             }
  257.             /*
  258.              * I'm tired of answering this question, so:
  259.              * On a 4.3BSD+ machine (client and server,
  260.              * actually), sending to a nameserver datagram
  261.              * port with no nameserver will cause an
  262.              * ICMP port unreachable message to be returned.
  263.              * If our datagram socket is "connected" to the
  264.              * server, we get an ECONNREFUSED error on the next
  265.              * socket operation, and select returns if the
  266.              * error message is received.  We can thus detect
  267.              * the absence of a nameserver without timing out.
  268.              * If we have sent queries to at least two servers,
  269.              * however, we don't want to remain connected,
  270.              * as we wish to receive answers from the first
  271.              * server to respond.
  272.              */
  273.             if (tr