X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/87b12937b3e4fb2610b90d5bb568a497f1d91a34..fad613b52dda8749b9b9e5493557045b54baf496:/usr/src/lib/libc/net/res_send.c diff --git a/usr/src/lib/libc/net/res_send.c b/usr/src/lib/libc/net/res_send.c index 9e3709043d..36b23fe055 100644 --- a/usr/src/lib/libc/net/res_send.c +++ b/usr/src/lib/libc/net/res_send.c @@ -1,29 +1,48 @@ - /* * 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. */ -#ifndef lint -static char sccsid[] = "@(#)res_send.c 6.3 (Berkeley) %G%"; -#endif not lint +#if defined(LIBC_SCCS) && !defined(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. */ -#include +#include #include #include +#include #include #include #include #include -#include +#include 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) res_send(buf, buflen, answer, anslen) @@ -34,13 +53,16 @@ res_send(buf, buflen, answer, anslen) { register int n; int retry, v_circuit, resplen, ns; - static int s = -1; + int gotsomewhere = 0, connected = 0; u_short id, len; char *cp; - int dsmask; + fd_set dsmask; struct timeval timeout; HEADER *hp = (HEADER *) buf; HEADER *anhp = (HEADER *) answer; + struct iovec iov[2]; + int terrno = ETIMEDOUT; + char junk[512]; #ifdef DEBUG if (_res.options & RES_DEBUG) { @@ -57,24 +79,35 @@ res_send(buf, buflen, answer, anslen) /* * 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, - inet_ntoa(_res.nsaddr_list[ns].sin_addr.s_addr)); + inet_ntoa(_res.nsaddr_list[ns].sin_addr)); #endif DEBUG if (v_circuit) { + int truncated = 0; + /* * Use virtual circuit. */ if (s < 0) { s = socket(AF_INET, SOCK_STREAM, 0); - if (connect(s, &(_res.nsaddr_list[ns]), + if (s < 0) { + terrno = errno; +#ifdef DEBUG + if (_res.options & RES_DEBUG) + perror("socket failed"); +#endif DEBUG + continue; + } + if (connect(s, &(_res.nsaddr_list[ns]), sizeof(struct sockaddr)) < 0) { + terrno = errno; #ifdef DEBUG if (_res.options & RES_DEBUG) - printf("connect failed %d\n",errno); + perror("connect failed"); #endif DEBUG (void) close(s); s = -1; @@ -84,12 +117,16 @@ res_send(buf, buflen, answer, anslen) /* * Send length & message */ - len = htons(buflen); - if (write(s, &len, sizeof(len)) != sizeof(len) || - write(s, buf, buflen) != buflen) { + len = htons((u_short)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) - printf("write failed %d\n", errno); + perror("write failed"); #endif DEBUG (void) close(s); s = -1; @@ -100,62 +137,121 @@ res_send(buf, buflen, answer, anslen) */ 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) { + terrno = errno; #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; - resplen = len = ntohs(*(short *)cp); - while (len > 0 && (n = read(s, cp, 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) { + terrno = errno; #ifdef DEBUG if (_res.options & RES_DEBUG) - printf("read failed %d\n", errno); + perror("read failed"); #endif DEBUG (void) close(s); 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. */ if (s < 0) s = socket(AF_INET, SOCK_DGRAM, 0); - if (connect(s, &_res.nsaddr_list[ns], - sizeof(struct sockaddr)) < 0 || - send(s, buf, buflen, 0) != buflen) { +#if BSD >= 43 + 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 - if (_res.options & RES_DEBUG) - printf("connect/send errno = %d\n", - errno); + if (_res.options & RES_DEBUG) + perror("connect"); #endif DEBUG + 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 (_res.options & RES_DEBUG) + perror("sendto"); +#endif DEBUG + continue; } + /* - * 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; 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) - printf("select errno = %d\n", errno); + perror("select"); #endif DEBUG continue; } @@ -167,15 +263,26 @@ wait: 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; } if ((resplen = recv(s, answer, anslen, 0)) <= 0) { #ifdef DEBUG if (_res.options & RES_DEBUG) - printf("recvfrom, errno=%d\n", errno); + perror("recvfrom"); #endif DEBUG continue; } + gotsomewhere = 1; if (id != anhp->id) { /* * response from old query, ignore it @@ -198,7 +305,11 @@ wait: #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; } @@ -223,7 +334,31 @@ wait: } } } - (void) close(s); - errno = ETIMEDOUT; + if (s >= 0) { + (void) close(s); + s = -1; + } + if (v_circuit == 0) + if (gotsomewhere == 0) + errno = ECONNREFUSED; + else + errno = ETIMEDOUT; + else + errno = terrno; 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; + } +}