change retry loop to test before decrementing
[unix-history] / usr / src / lib / libc / net / res_send.c
index 2aca83f..6ecde76 100644 (file)
@@ -5,25 +5,29 @@
  * specifies the terms and conditions for redistribution.
  */
 
  * specifies the terms and conditions for redistribution.
  */
 
-#ifndef lint
-static char sccsid[] = "@(#)res_send.c 5.6 (Berkeley) %G%";
-#endif not lint
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)res_send.c 6.11 (Berkeley) %G%";
+#endif LIBC_SCCS and not lint
 
 /*
  * Send query to name server and wait for reply.
  */
 
 
 /*
  * Send query to name server and wait for reply.
  */
 
-#include <sys/types.h>
+#include <sys/param.h>
 #include <sys/time.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <stdio.h>
 #include <errno.h>
 #include <arpa/nameser.h>
 #include <sys/time.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <stdio.h>
 #include <errno.h>
 #include <arpa/nameser.h>
-#include <arpa/resolv.h>
+#include <resolv.h>
 
 extern int errno;
 
 
 extern int errno;
 
+static int s = -1;     /* socket used for communications */
+
+#define KEEPOPEN (RES_USEVC|RES_STAYOPEN)
+
 res_send(buf, buflen, answer, anslen)
        char *buf;
        int buflen;
 res_send(buf, buflen, answer, anslen)
        char *buf;
        int buflen;
@@ -31,7 +35,8 @@ res_send(buf, buflen, answer, anslen)
        int anslen;
 {
        register int n;
        int anslen;
 {
        register int n;
-       int s, retry, v_circuit, resplen, ns;
+       int retry, v_circuit, resplen, ns;
+       int gotsomewhere = 0;
        u_short id, len;
        char *cp;
        int dsmask;
        u_short id, len;
        char *cp;
        int dsmask;
@@ -49,44 +54,51 @@ res_send(buf, buflen, answer, anslen)
                if (res_init() == -1) {
                        return(-1);
                }
                if (res_init() == -1) {
                        return(-1);
                }
-       s = -1;
        v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
        id = hp->id;
        /*
         * Send request, RETRY times, or until successful
         */
        v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
        id = hp->id;
        /*
         * Send request, RETRY times, or until successful
         */
-       for (retry = _res.retry; --retry >= 0; ) {
+       for (retry = _res.retry; retry > 0; retry--) {
           for (ns = 0; ns < _res.nscount; ns++) {
 #ifdef DEBUG
                if (_res.options & RES_DEBUG)
                        printf("Querying server (# %d) address = %s\n", ns+1,
           for (ns = 0; ns < _res.nscount; ns++) {
 #ifdef DEBUG
                if (_res.options & RES_DEBUG)
                        printf("Querying server (# %d) address = %s\n", ns+1,
-                             inet_ntoa(_res.nsaddr_list[ns].sin_addr.s_addr)); 
+                             inet_ntoa(_res.nsaddr_list[ns].sin_addr.s_addr));
 #endif DEBUG
                if (v_circuit) {
                        /*
                         * Use virtual circuit.
                         */
 #endif DEBUG
                if (v_circuit) {
                        /*
                         * Use virtual circuit.
                         */
-                       if (s < 0)
+                       if (s < 0) {
                                s = socket(AF_INET, SOCK_STREAM, 0);
                                s = socket(AF_INET, SOCK_STREAM, 0);
-                       if (connect(s, &(_res.nsaddr_list[ns]), 
-                          sizeof(struct sockaddr)) < 0) {
+                               if (s < 0) {
 #ifdef DEBUG
 #ifdef DEBUG
-                               if (_res.options & RES_DEBUG)
-                                       printf("connect failed %d\n", errno);
+                                       if (_res.options & RES_DEBUG)
+                                           perror("socket failed");
 #endif DEBUG
 #endif DEBUG
-                               (void) close(s);
-                               s = -1;
-                               continue;
+                                       continue;
+                               }
+                               if (connect(s, &(_res.nsaddr_list[ns]),
+                                  sizeof(struct sockaddr)) < 0) {
+#ifdef DEBUG
+                                       if (_res.options & RES_DEBUG)
+                                           perror("connect failed");
+#endif DEBUG
+                                       (void) close(s);
+                                       s = -1;
+                                       continue;
+                               }
                        }
                        /*
                         * Send length & message
                         */
                        }
                        /*
                         * Send length & message
                         */
-                       len = htons(buflen);
-                       if (write(s, &len, sizeof(len)) != sizeof(len) ||
-                                   write(s, buf, buflen) != buflen) {
+                       len = htons((u_short)buflen);
+                       if (write(s, (char *)&len, sizeof(len)) != sizeof(len)||
+                           write(s, buf, buflen) != buflen) {
 #ifdef DEBUG
                                if (_res.options & RES_DEBUG)
 #ifdef DEBUG
                                if (_res.options & RES_DEBUG)
-                                       printf("write failed %d\n", errno);
+                                       perror("write failed");
 #endif DEBUG
                                (void) close(s);
                                s = -1;
 #endif DEBUG
                                (void) close(s);
                                s = -1;
@@ -97,29 +109,31 @@ res_send(buf, buflen, answer, anslen)
                         */
                        cp = answer;
                        len = sizeof(short);
                         */
                        cp = answer;
                        len = sizeof(short);
-                       while (len > 0 && (n = read(s, cp, len)) > 0) {
+                       while (len > 0 &&
+                           (n = read(s, (char *)cp, (int)len)) > 0) {
                                cp += n;
                                len -= n;
                        }
                        if (n <= 0) {
 #ifdef DEBUG
                                if (_res.options & RES_DEBUG)
                                cp += n;
                                len -= n;
                        }
                        if (n <= 0) {
 #ifdef DEBUG
                                if (_res.options & RES_DEBUG)
-                                       printf("read failed %d\n", errno);
+                                       perror("read failed");
 #endif DEBUG
                                (void) close(s);
                                s = -1;
                                continue;
                        }
                        cp = answer;
 #endif DEBUG
                                (void) close(s);
                                s = -1;
                                continue;
                        }
                        cp = answer;
-                       resplen = len = ntohs(*(short *)cp);
-                       while (len > 0 && (n = read(s, cp, len)) > 0) {
+                       resplen = len = ntohs(*(u_short *)cp);
+                       while (len > 0 &&
+                          (n = read(s, (char *)cp, (int)len)) > 0) {
                                cp += n;
                                len -= n;
                        }
                        if (n <= 0) {
 #ifdef DEBUG
                                if (_res.options & RES_DEBUG)
                                cp += n;
                                len -= n;
                        }
                        if (n <= 0) {
 #ifdef DEBUG
                                if (_res.options & RES_DEBUG)
-                                       printf("read failed %d\n", errno);
+                                       perror("read failed");
 #endif DEBUG
                                (void) close(s);
                                s = -1;
 #endif DEBUG
                                (void) close(s);
                                s = -1;
@@ -131,25 +145,41 @@ res_send(buf, buflen, answer, anslen)
                         */
                        if (s < 0)
                                s = socket(AF_INET, SOCK_DGRAM, 0);
                         */
                        if (s < 0)
                                s = socket(AF_INET, SOCK_DGRAM, 0);
+#if    BSD >= 43
+                       if (connect(s, &_res.nsaddr_list[ns],
+                           sizeof(struct sockaddr)) < 0 ||
+                           send(s, buf, buflen, 0) != buflen) {
+#ifdef DEBUG
+                               if (_res.options & RES_DEBUG)
+                                       perror("connect");
+#endif DEBUG
+                               continue;
+                       }
+#else BSD
                        if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns],
                            sizeof(struct sockaddr)) != buflen) {
 #ifdef DEBUG
                        if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns],
                            sizeof(struct sockaddr)) != buflen) {
 #ifdef DEBUG
-                               if (_res.options & RES_DEBUG) 
-                                       printf("sendto errno = %d\n", errno);
+                               if (_res.options & RES_DEBUG)
+                                       perror("sendto");
 #endif DEBUG
 #endif DEBUG
+                               continue;
                        }
                        }
+#endif BSD
                        /*
                        /*
-                        * Wait for reply 
+                        * Wait for reply
                         */
                         */
-                       timeout.tv_sec = 
-                               ((_res.retrans * _res.retry) / _res.nscount);
+                       timeout.tv_sec = (_res.retrans << (_res.retry - retry))
+                               / _res.nscount;
+                       if (timeout.tv_sec <= 0)
+                               timeout.tv_sec = 1;
                        timeout.tv_usec = 0;
                        timeout.tv_usec = 0;
+wait:
                        dsmask = 1 << s;
                        n = select(s+1, &dsmask, 0, 0, &timeout);
                        if (n < 0) {
 #ifdef DEBUG
                                if (_res.options & RES_DEBUG)
                        dsmask = 1 << s;
                        n = select(s+1, &dsmask, 0, 0, &timeout);
                        if (n < 0) {
 #ifdef DEBUG
                                if (_res.options & RES_DEBUG)
-                                       printf("select errno = %d\n", errno);
+                                       perror("select");
 #endif DEBUG
                                continue;
                        }
 #endif DEBUG
                                continue;
                        }
@@ -161,16 +191,17 @@ res_send(buf, buflen, answer, anslen)
                                if (_res.options & RES_DEBUG)
                                        printf("timeout\n");
 #endif DEBUG
                                if (_res.options & RES_DEBUG)
                                        printf("timeout\n");
 #endif DEBUG
+                               gotsomewhere = 1;
                                continue;
                        }
                                continue;
                        }
-                       if ((resplen = recvfrom(s, answer, anslen,
-                           0, 0, 0)) <= 0) {
+                       if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
 #ifdef DEBUG
                                if (_res.options & RES_DEBUG)
 #ifdef DEBUG
                                if (_res.options & RES_DEBUG)
-                                       printf("recvfrom, errno=%d\n", errno);
+                                       perror("recvfrom");
 #endif DEBUG
                                continue;
                        }
 #endif DEBUG
                                continue;
                        }
+                       gotsomewhere = 1;
                        if (id != anhp->id) {
                                /*
                                 * response from old query, ignore it
                        if (id != anhp->id) {
                                /*
                                 * response from old query, ignore it
@@ -181,7 +212,7 @@ res_send(buf, buflen, answer, anslen)
                                        p_query(answer);
                                }
 #endif DEBUG
                                        p_query(answer);
                                }
 #endif DEBUG
-                               continue;
+                               goto wait;
                        }
                        if (!(_res.options & RES_IGNTC) && anhp->tc) {
                                /*
                        }
                        if (!(_res.options & RES_IGNTC) && anhp->tc) {
                                /*
@@ -193,7 +224,11 @@ res_send(buf, buflen, answer, anslen)
 #endif DEBUG
                                (void) close(s);
                                s = -1;
 #endif DEBUG
                                (void) close(s);
                                s = -1;
-                               retry = _res.retry;
+                               /*
+                                * retry decremented on continue
+                                * to desired starting value
+                                */
+                               retry = _res.retry + 1;
                                v_circuit = 1;
                                continue;
                        }
                                v_circuit = 1;
                                continue;
                        }
@@ -204,11 +239,40 @@ res_send(buf, buflen, answer, anslen)
                        p_query(answer);
                }
 #endif DEBUG
                        p_query(answer);
                }
 #endif DEBUG
-               (void) close(s);
-               return (resplen);
+               /*
+                * We are going to assume that the first server is preferred
+                * over the rest (i.e. it is on the local machine) and only
+                * keep that one open.
+                */
+               if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) {
+                       return (resplen);
+               } else {
+                       (void) close(s);
+                       s = -1;
+                       return (resplen);
+               }
           }
        }
        (void) close(s);
           }
        }
        (void) close(s);
-       errno = ETIMEDOUT;
+       s = -1;
+       if (v_circuit == 0 && gotsomewhere == 0)
+               errno = ECONNREFUSED;
+       else
+               errno = ETIMEDOUT;
        return (-1);
 }
        return (-1);
 }
+
+/*
+ * This routine is for closing the socket if a virtual circuit is used and
+ * the program wants to close it.  This provides support for endhostent()
+ * which expects to close the socket.
+ *
+ * This routine is not expected to be user visible.
+ */
+_res_close()
+{
+       if (s != -1) {
+               (void) close(s);
+               s = -1;
+       }
+}