install C version of _doprnt
[unix-history] / usr / src / lib / libc / net / res_send.c
index 77b1ab5..36b23fe 100644 (file)
@@ -1,13 +1,18 @@
-
 /*
  * Copyright (c) 1985 Regents of the University of California.
 /*
  * Copyright (c) 1985 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of California at Berkeley. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)res_send.c 6.11 (Berkeley) %G%";
-#endif LIBC_SCCS and not lint
+static char sccsid[] = "@(#)res_send.c 6.19 (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.
@@ -16,6 +21,7 @@ static char sccsid[] = "@(#)res_send.c        6.11 (Berkeley) %G%";
 #include <sys/param.h>
 #include <sys/time.h>
 #include <sys/socket.h>
 #include <sys/param.h>
 #include <sys/time.h>
 #include <sys/socket.h>
+#include <sys/uio.h>
 #include <netinet/in.h>
 #include <stdio.h>
 #include <errno.h>
 #include <netinet/in.h>
 #include <stdio.h>
 #include <errno.h>
@@ -25,6 +31,17 @@ static char sccsid[] = "@(#)res_send.c       6.11 (Berkeley) %G%";
 extern int errno;
 
 static int s = -1;     /* socket used for communications */
 extern int errno;
 
 static int s = -1;     /* socket used for communications */
+static struct sockaddr no_addr;
+  
+
+#ifndef FD_SET
+#define        NFDBITS         32
+#define        FD_SETSIZE      32
+#define        FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define        FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define        FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#define FD_ZERO(p)     bzero((char *)(p), sizeof(*(p)))
+#endif
 
 #define KEEPOPEN (RES_USEVC|RES_STAYOPEN)
 
 
 #define KEEPOPEN (RES_USEVC|RES_STAYOPEN)
 
@@ -36,15 +53,16 @@ res_send(buf, buflen, answer, anslen)
 {
        register int n;
        int retry, v_circuit, resplen, ns;
 {
        register int n;
        int retry, v_circuit, resplen, ns;
-       int gotsomewhere = 0;
+       int gotsomewhere = 0, connected = 0;
        u_short id, len;
        char *cp;
        u_short id, len;
        char *cp;
-       int dsmask;
+       fd_set dsmask;
        struct timeval timeout;
        HEADER *hp = (HEADER *) buf;
        HEADER *anhp = (HEADER *) answer;
        struct timeval timeout;
        HEADER *hp = (HEADER *) buf;
        HEADER *anhp = (HEADER *) answer;
-
-       extern u_short htons(), ntohs();
+       struct iovec iov[2];
+       int terrno = ETIMEDOUT;
+       char junk[512];
 
 #ifdef DEBUG
        if (_res.options & RES_DEBUG) {
 
 #ifdef DEBUG
        if (_res.options & RES_DEBUG) {
@@ -61,20 +79,23 @@ res_send(buf, buflen, answer, anslen)
        /*
         * Send request, RETRY times, or until successful
         */
        /*
         * 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));
 #endif DEBUG
                if (v_circuit) {
 #endif DEBUG
                if (v_circuit) {
+                       int truncated = 0;
+
                        /*
                         * Use virtual circuit.
                         */
                        if (s < 0) {
                                s = socket(AF_INET, SOCK_STREAM, 0);
                                if (s < 0) {
                        /*
                         * Use virtual circuit.
                         */
                        if (s < 0) {
                                s = socket(AF_INET, SOCK_STREAM, 0);
                                if (s < 0) {
+                                       terrno = errno;
 #ifdef DEBUG
                                        if (_res.options & RES_DEBUG)
                                            perror("socket failed");
 #ifdef DEBUG
                                        if (_res.options & RES_DEBUG)
                                            perror("socket failed");
@@ -83,6 +104,7 @@ res_send(buf, buflen, answer, anslen)
                                }
                                if (connect(s, &(_res.nsaddr_list[ns]),
                                   sizeof(struct sockaddr)) < 0) {
                                }
                                if (connect(s, &(_res.nsaddr_list[ns]),
                                   sizeof(struct sockaddr)) < 0) {
+                                       terrno = errno;
 #ifdef DEBUG
                                        if (_res.options & RES_DEBUG)
                                            perror("connect failed");
 #ifdef DEBUG
                                        if (_res.options & RES_DEBUG)
                                            perror("connect failed");
@@ -96,8 +118,12 @@ res_send(buf, buflen, answer, anslen)
                         * Send length & message
                         */
                        len = htons((u_short)buflen);
                         * Send length & message
                         */
                        len = htons((u_short)buflen);
-                       if (write(s, (char *)&len, sizeof(len)) != sizeof(len)||
-                           write(s, buf, buflen) != buflen) {
+                       iov[0].iov_base = (caddr_t)&len;
+                       iov[0].iov_len = sizeof(len);
+                       iov[1].iov_base = buf;
+                       iov[1].iov_len = buflen;
+                       if (writev(s, iov, 2) != sizeof(len) + buflen) {
+                               terrno = errno;
 #ifdef DEBUG
                                if (_res.options & RES_DEBUG)
                                        perror("write failed");
 #ifdef DEBUG
                                if (_res.options & RES_DEBUG)
                                        perror("write failed");
@@ -111,12 +137,13 @@ res_send(buf, buflen, answer, anslen)
                         */
                        cp = answer;
                        len = sizeof(short);
                         */
                        cp = answer;
                        len = sizeof(short);
-                       while (len > 0 &&
+                       while (len != 0 &&
                            (n = read(s, (char *)cp, (int)len)) > 0) {
                                cp += n;
                                len -= n;
                        }
                        if (n <= 0) {
                            (n = read(s, (char *)cp, (int)len)) > 0) {
                                cp += n;
                                len -= n;
                        }
                        if (n <= 0) {
+                               terrno = errno;
 #ifdef DEBUG
                                if (_res.options & RES_DEBUG)
                                        perror("read failed");
 #ifdef DEBUG
                                if (_res.options & RES_DEBUG)
                                        perror("read failed");
@@ -126,13 +153,22 @@ res_send(buf, buflen, answer, anslen)
                                continue;
                        }
                        cp = answer;
                                continue;
                        }
                        cp = answer;
-                       resplen = len = ntohs(*(u_short *)cp);
-                       while (len > 0 &&
+                       if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
+#ifdef DEBUG
+                               if (_res.options & RES_DEBUG)
+                                       fprintf(stderr, "response truncated\n");
+#endif DEBUG
+                               len = anslen;
+                               truncated = 1;
+                       } else
+                               len = resplen;
+                       while (len != 0 &&
                           (n = read(s, (char *)cp, (int)len)) > 0) {
                                cp += n;
                                len -= n;
                        }
                        if (n <= 0) {
                           (n = read(s, (char *)cp, (int)len)) > 0) {
                                cp += n;
                                len -= n;
                        }
                        if (n <= 0) {
+                               terrno = errno;
 #ifdef DEBUG
                                if (_res.options & RES_DEBUG)
                                        perror("read failed");
 #ifdef DEBUG
                                if (_res.options & RES_DEBUG)
                                        perror("read failed");
@@ -141,6 +177,22 @@ res_send(buf, buflen, answer, anslen)
                                s = -1;
                                continue;
                        }
                                s = -1;
                                continue;
                        }
+                       if (truncated) {
+                               /*
+                                * Flush rest of answer
+                                * so connection stays in synch.
+                                */
+                               anhp->tc = 1;
+                               len = resplen - anslen;
+                               while (len != 0) {
+                                       n = (len > sizeof(junk) ?
+                                           sizeof(junk) : len);
+                                       if ((n = read(s, junk, n)) > 0)
+                                               len -= n;
+                                       else
+                                               break;
+                               }
+                       }
                } else {
                        /*
                         * Use datagrams.
                } else {
                        /*
                         * Use datagrams.
@@ -148,16 +200,32 @@ res_send(buf, buflen, answer, anslen)
                        if (s < 0)
                                s = socket(AF_INET, SOCK_DGRAM, 0);
 #if    BSD >= 43
                        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) {
+                       if (_res.nscount == 1 || retry == _res.retry) {
+                               /*
+                                * Don't use connect if we might
+                                * still receive a response
+                                * from another server.
+                                */
+                               if (connected == 0) {
+                                       if (connect(s, &_res.nsaddr_list[ns],
+                                           sizeof(struct sockaddr)) < 0) {
 #ifdef DEBUG
 #ifdef DEBUG
-                               if (_res.options & RES_DEBUG)
-                                       perror("connect");
+                                               if (_res.options & RES_DEBUG)
+                                                       perror("connect");
 #endif DEBUG
 #endif DEBUG
-                               continue;
-                       }
-#else BSD
+                                               continue;
+                                       }
+                                       connected = 1;
+                               }
+                               if (send(s, buf, buflen, 0) != buflen) {
+#ifdef DEBUG
+                                       if (_res.options & RES_DEBUG)
+                                               perror("send");
+#endif DEBUG
+                                       continue;
+                               }
+                       } else
+#endif 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
@@ -166,7 +234,7 @@ res_send(buf, buflen, answer, anslen)
 #endif DEBUG
                                continue;
                        }
 #endif DEBUG
                                continue;
                        }
-#endif BSD
+
                        /*
                         * Wait for reply
                         */
                        /*
                         * Wait for reply
                         */
@@ -176,8 +244,10 @@ res_send(buf, buflen, answer, anslen)
                                timeout.tv_sec = 1;
                        timeout.tv_usec = 0;
 wait:
                                timeout.tv_sec = 1;
                        timeout.tv_usec = 0;
 wait:
-                       dsmask = 1 << s;
-                       n = select(s+1, &dsmask, 0, 0, &timeout);
+                       FD_ZERO(&dsmask);
+                       FD_SET(s, &dsmask);
+                       n = select(s+1, &dsmask, (fd_set *)NULL,
+                               (fd_set *)NULL, &timeout);
                        if (n < 0) {
 #ifdef DEBUG
                                if (_res.options & RES_DEBUG)
                        if (n < 0) {
 #ifdef DEBUG
                                if (_res.options & RES_DEBUG)
@@ -193,6 +263,15 @@ wait:
                                if (_res.options & RES_DEBUG)
                                        printf("timeout\n");
 #endif DEBUG
                                if (_res.options & RES_DEBUG)
                                        printf("timeout\n");
 #endif DEBUG
+                               /*
+                                * Disconnect if we want to listen
+                                * for responses from more than one server.
+                                */
+                               if (_res.nscount > 1 && connected) {
+                                       (void) connect(s, &no_addr,
+                                           sizeof(no_addr));
+                                       connected = 0;
+                               }
                                gotsomewhere = 1;
                                continue;
                        }
                                gotsomewhere = 1;
                                continue;
                        }
@@ -226,7 +305,11 @@ wait:
 #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;
                        }
@@ -251,12 +334,17 @@ wait:
                }
           }
        }
                }
           }
        }
-       (void) close(s);
-       s = -1;
-       if (v_circuit == 0 && gotsomewhere == 0)
-               errno = ECONNREFUSED;
+       if (s >= 0) {
+               (void) close(s);
+               s = -1;
+       }
+       if (v_circuit == 0)
+               if (gotsomewhere == 0)
+                       errno = ECONNREFUSED;
+               else
+                       errno = ETIMEDOUT;
        else
        else
-               errno = ETIMEDOUT;
+               errno = terrno;
        return (-1);
 }
 
        return (-1);
 }