X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/616a94babcd3c92632fde5171763ca2d2b783c28..15537e14cdc235c00610fef2f343a5d2363e3df9:/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 d0a1f663af..af6f6d0836 100644 --- a/usr/src/lib/libc/net/res_send.c +++ b/usr/src/lib/libc/net/res_send.c @@ -1,73 +1,124 @@ -#ifndef lint -static char sccsid[] = "@(#)res_send.c 4.1 (Berkeley) %G%"; -#endif + +/* + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)res_send.c 6.15 (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; -sendquery(buf, buflen, answer, anslen) +static int s = -1; /* socket used for communications */ + + +#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) char *buf; int buflen; char *answer; int anslen; { register int n; - int s, retry, v_circuit, resplen; + int retry, v_circuit, resplen, ns; + int gotsomewhere = 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; +#ifdef DEBUG if (_res.options & RES_DEBUG) { - printf("sendquery()\n"); + printf("res_send()\n"); p_query(buf); } - if (!(_res.options & RES_INIT)) { - if (!res_init()) - return (-1); - } - s = -1; +#endif DEBUG + if (!(_res.options & RES_INIT)) + if (res_init() == -1) { + return(-1); + } 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, + inet_ntoa(_res.nsaddr_list[ns].sin_addr.s_addr)); +#endif DEBUG if (v_circuit) { /* * Use virtual circuit. */ - if (s < 0) + if (s < 0) { s = socket(AF_INET, SOCK_STREAM, 0); - if (connect(s, &_res.nsaddr, sizeof(_res.nsaddr)) < 0) { - if (_res.options & RES_DEBUG) - printf("connect failed %d\n", errno); - (void) close(s); - s = -1; - continue; + 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) + perror("connect failed"); +#endif DEBUG + (void) close(s); + s = -1; + continue; + } } /* * 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; continue; @@ -77,26 +128,34 @@ sendquery(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) { + resplen = len = ntohs(*(u_short *)cp); + 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; @@ -107,70 +166,141 @@ sendquery(buf, buflen, answer, anslen) */ if (s < 0) s = socket(AF_INET, SOCK_DGRAM, 0); - if (sendto(s, buf, buflen, 0, &_res.nsaddr, - sizeof(_res.nsaddr)) != buflen) { +#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) - printf("sendto errno = %d\n", errno); + perror("connect"); +#endif DEBUG + continue; } +#else 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; + } +#endif BSD /* - * Wait for reply + * Wait for reply */ - timeout.tv_sec = _res.retrans; + timeout.tv_sec = (_res.retrans << (_res.retry - retry)) + / _res.nscount; + if (timeout.tv_sec <= 0) + timeout.tv_sec = 1; timeout.tv_usec = 0; - dsmask = 1 << s; - n = select(s+1, &dsmask, 0, 0, &timeout); +wait: + 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; } if (n == 0) { /* * timeout */ +#ifdef DEBUG if (_res.options & RES_DEBUG) printf("timeout\n"); +#endif DEBUG + gotsomewhere = 1; 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) - printf("recvfrom, errno=%d\n", errno); + perror("recvfrom"); +#endif DEBUG continue; } + gotsomewhere = 1; if (id != anhp->id) { /* * response from old query, ignore it */ +#ifdef DEBUG if (_res.options & RES_DEBUG) { - int f; - printf("old answer:\n"); - f = creat("ro", 0644); - write(f, answer, resplen); - close(f); p_query(answer); } - continue; +#endif DEBUG + goto wait; } if (!(_res.options & RES_IGNTC) && anhp->tc) { /* * get rest of answer */ +#ifdef DEBUG if (_res.options & RES_DEBUG) printf("truncated answer\n"); +#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; } } +#ifdef DEBUG if (_res.options & RES_DEBUG) { printf("got answer:\n"); p_query(answer); } - return (resplen); +#endif DEBUG + /* + * 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); + } + } + } + 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; + } +}