125243Skjd 218144Sralph /* 321388Sdist * Copyright (c) 1985 Regents of the University of California. 421388Sdist * All rights reserved. The Berkeley software License Agreement 521388Sdist * specifies the terms and conditions for redistribution. 618548Sralph */ 718548Sralph 826635Sdonn #if defined(LIBC_SCCS) && !defined(lint) 9*31113Skarels static char sccsid[] = "@(#)res_send.c 6.17 (Berkeley) 05/12/87"; 1026635Sdonn #endif LIBC_SCCS and not lint 1121388Sdist 1218548Sralph /* 1318144Sralph * Send query to name server and wait for reply. 1418144Sralph */ 1518144Sralph 1626886Skjd #include <sys/param.h> 1718144Sralph #include <sys/time.h> 1818144Sralph #include <sys/socket.h> 1927664Sbloom #include <sys/uio.h> 2018144Sralph #include <netinet/in.h> 2118144Sralph #include <stdio.h> 2218144Sralph #include <errno.h> 2324083Skjd #include <arpa/nameser.h> 2426896Skjd #include <resolv.h> 2518144Sralph 2618144Sralph extern int errno; 2718144Sralph 2827025Sbloom static int s = -1; /* socket used for communications */ 29*31113Skarels static struct sockaddr no_addr; 3030100Skjd 3127025Sbloom 3230100Skjd #ifndef FD_SET 3330100Skjd #define NFDBITS 32 3430100Skjd #define FD_SETSIZE 32 3530100Skjd #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) 3630100Skjd #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) 3730100Skjd #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) 3830100Skjd #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) 3930100Skjd #endif 4030100Skjd 4126322Sbloom #define KEEPOPEN (RES_USEVC|RES_STAYOPEN) 4226322Sbloom 4318531Sralph res_send(buf, buflen, answer, anslen) 4418144Sralph char *buf; 4518144Sralph int buflen; 4618144Sralph char *answer; 4718144Sralph int anslen; 4818144Sralph { 4918144Sralph register int n; 5026322Sbloom int retry, v_circuit, resplen, ns; 5126483Skarels int gotsomewhere = 0; 5218144Sralph u_short id, len; 5318144Sralph char *cp; 5427796Skjd fd_set dsmask; 5518144Sralph struct timeval timeout; 5618144Sralph HEADER *hp = (HEADER *) buf; 5718144Sralph HEADER *anhp = (HEADER *) answer; 5827664Sbloom struct iovec iov[2]; 5929434Sbloom int terrno = ETIMEDOUT; 6018144Sralph 6124734Sbloom #ifdef DEBUG 6218144Sralph if (_res.options & RES_DEBUG) { 6318531Sralph printf("res_send()\n"); 6418144Sralph p_query(buf); 6518144Sralph } 6625243Skjd #endif DEBUG 6718531Sralph if (!(_res.options & RES_INIT)) 6824734Sbloom if (res_init() == -1) { 6924734Sbloom return(-1); 7024734Sbloom } 7118144Sralph v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; 7218144Sralph id = hp->id; 7318144Sralph /* 7418144Sralph * Send request, RETRY times, or until successful 7518144Sralph */ 7627040Skjd for (retry = _res.retry; retry > 0; retry--) { 7725243Skjd for (ns = 0; ns < _res.nscount; ns++) { 7825243Skjd #ifdef DEBUG 7925243Skjd if (_res.options & RES_DEBUG) 8025243Skjd printf("Querying server (# %d) address = %s\n", ns+1, 8127031Skjd inet_ntoa(_res.nsaddr_list[ns].sin_addr.s_addr)); 8225243Skjd #endif DEBUG 8318144Sralph if (v_circuit) { 8418144Sralph /* 8518144Sralph * Use virtual circuit. 8618144Sralph */ 8726322Sbloom if (s < 0) { 8818144Sralph s = socket(AF_INET, SOCK_STREAM, 0); 8926483Skarels if (s < 0) { 9029434Sbloom terrno = errno; 9126483Skarels #ifdef DEBUG 9226483Skarels if (_res.options & RES_DEBUG) 9327031Skjd perror("socket failed"); 9426483Skarels #endif DEBUG 9526483Skarels continue; 9626483Skarels } 9727031Skjd if (connect(s, &(_res.nsaddr_list[ns]), 9826322Sbloom sizeof(struct sockaddr)) < 0) { 9929434Sbloom terrno = errno; 10024734Sbloom #ifdef DEBUG 10126322Sbloom if (_res.options & RES_DEBUG) 10227031Skjd perror("connect failed"); 10325243Skjd #endif DEBUG 10426322Sbloom (void) close(s); 10526322Sbloom s = -1; 10626322Sbloom continue; 10726322Sbloom } 10818144Sralph } 10918144Sralph /* 11018144Sralph * Send length & message 11118144Sralph */ 11227025Sbloom len = htons((u_short)buflen); 11327664Sbloom iov[0].iov_base = (caddr_t)&len; 11427664Sbloom iov[0].iov_len = sizeof(len); 11527664Sbloom iov[1].iov_base = buf; 11627664Sbloom iov[1].iov_len = buflen; 11727664Sbloom if (writev(s, iov, 2) != sizeof(len) + buflen) { 11829434Sbloom terrno = errno; 11924734Sbloom #ifdef DEBUG 12018144Sralph if (_res.options & RES_DEBUG) 12127031Skjd perror("write failed"); 12225243Skjd #endif DEBUG 12318144Sralph (void) close(s); 12418144Sralph s = -1; 12518144Sralph continue; 12618144Sralph } 12718144Sralph /* 12818144Sralph * Receive length & response 12918144Sralph */ 13018144Sralph cp = answer; 13118144Sralph len = sizeof(short); 13227664Sbloom while (len != 0 && 13327031Skjd (n = read(s, (char *)cp, (int)len)) > 0) { 13418144Sralph cp += n; 13518144Sralph len -= n; 13618144Sralph } 13718144Sralph if (n <= 0) { 13829434Sbloom terrno = errno; 13924734Sbloom #ifdef DEBUG 14018144Sralph if (_res.options & RES_DEBUG) 14127031Skjd perror("read failed"); 14225243Skjd #endif DEBUG 14318144Sralph (void) close(s); 14418144Sralph s = -1; 14518144Sralph continue; 14618144Sralph } 14718144Sralph cp = answer; 14827025Sbloom resplen = len = ntohs(*(u_short *)cp); 14927664Sbloom while (len != 0 && 15027031Skjd (n = read(s, (char *)cp, (int)len)) > 0) { 15118144Sralph cp += n; 15218144Sralph len -= n; 15318144Sralph } 15418144Sralph if (n <= 0) { 15529434Sbloom terrno = errno; 15624734Sbloom #ifdef DEBUG 15718144Sralph if (_res.options & RES_DEBUG) 15827031Skjd perror("read failed"); 15925243Skjd #endif DEBUG 16018144Sralph (void) close(s); 16118144Sralph s = -1; 16218144Sralph continue; 16318144Sralph } 16418144Sralph } else { 16518144Sralph /* 16618144Sralph * Use datagrams. 16718144Sralph */ 16818144Sralph if (s < 0) 16918144Sralph s = socket(AF_INET, SOCK_DGRAM, 0); 17026483Skarels #if BSD >= 43 171*31113Skarels if (_res.nscount == 1 || retry == _res.retry) { 17230394Skjd /* 173*31113Skarels * Don't use connect if we might 174*31113Skarels * still receive a response 175*31113Skarels * from another server. 17630394Skjd */ 17730394Skjd if (connect(s, &_res.nsaddr_list[ns], 17830394Skjd sizeof(struct sockaddr)) < 0 || 17930394Skjd send(s, buf, buflen, 0) != buflen) { 18024734Sbloom #ifdef DEBUG 18130394Skjd if (_res.options & RES_DEBUG) 18230394Skjd perror("connect"); 18325243Skjd #endif DEBUG 18430394Skjd continue; 18530394Skjd } 18630394Skjd } else 18730394Skjd #endif BSD 18826483Skarels if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns], 18926483Skarels sizeof(struct sockaddr)) != buflen) { 19026483Skarels #ifdef DEBUG 19127031Skjd if (_res.options & RES_DEBUG) 19227031Skjd perror("sendto"); 19326483Skarels #endif DEBUG 19426483Skarels continue; 19526483Skarels } 19630394Skjd 19718144Sralph /* 19827031Skjd * Wait for reply 19918144Sralph */ 20027031Skjd timeout.tv_sec = (_res.retrans << (_res.retry - retry)) 20127031Skjd / _res.nscount; 20227031Skjd if (timeout.tv_sec <= 0) 20327031Skjd timeout.tv_sec = 1; 20418144Sralph timeout.tv_usec = 0; 20526323Skarels wait: 20627796Skjd FD_ZERO(&dsmask); 20727796Skjd FD_SET(s, &dsmask); 20827664Sbloom n = select(s+1, &dsmask, (fd_set *)NULL, 20927664Sbloom (fd_set *)NULL, &timeout); 21018144Sralph if (n < 0) { 21124734Sbloom #ifdef DEBUG 21218144Sralph if (_res.options & RES_DEBUG) 21327031Skjd perror("select"); 21425243Skjd #endif DEBUG 21518144Sralph continue; 21618144Sralph } 21718144Sralph if (n == 0) { 21818144Sralph /* 21918144Sralph * timeout 22018144Sralph */ 22124734Sbloom #ifdef DEBUG 22218144Sralph if (_res.options & RES_DEBUG) 22318144Sralph printf("timeout\n"); 22425243Skjd #endif DEBUG 225*31113Skarels /* 226*31113Skarels * Disconnect if we want to listen 227*31113Skarels * for responses from more than one server. 228*31113Skarels */ 229*31113Skarels if (_res.nscount > 1 && retry == _res.retry) 230*31113Skarels (void) connect(s, &no_addr, 231*31113Skarels sizeof(no_addr)); 23226483Skarels gotsomewhere = 1; 23318144Sralph continue; 23418144Sralph } 23525332Skjd if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 23624734Sbloom #ifdef DEBUG 23718144Sralph if (_res.options & RES_DEBUG) 23827031Skjd perror("recvfrom"); 23925243Skjd #endif DEBUG 24018144Sralph continue; 24118144Sralph } 24226483Skarels gotsomewhere = 1; 24318144Sralph if (id != anhp->id) { 24418144Sralph /* 24518144Sralph * response from old query, ignore it 24618144Sralph */ 24724734Sbloom #ifdef DEBUG 24818144Sralph if (_res.options & RES_DEBUG) { 24918144Sralph printf("old answer:\n"); 25018144Sralph p_query(answer); 25118144Sralph } 25225243Skjd #endif DEBUG 25326323Skarels goto wait; 25418144Sralph } 25518144Sralph if (!(_res.options & RES_IGNTC) && anhp->tc) { 25618144Sralph /* 25718144Sralph * get rest of answer 25818144Sralph */ 25924734Sbloom #ifdef DEBUG 26018144Sralph if (_res.options & RES_DEBUG) 26118144Sralph printf("truncated answer\n"); 26225243Skjd #endif DEBUG 26318144Sralph (void) close(s); 26418144Sralph s = -1; 26527040Skjd /* 26627040Skjd * retry decremented on continue 26727040Skjd * to desired starting value 26827040Skjd */ 26927040Skjd retry = _res.retry + 1; 27018144Sralph v_circuit = 1; 27118144Sralph continue; 27218144Sralph } 27318144Sralph } 27424734Sbloom #ifdef DEBUG 27518144Sralph if (_res.options & RES_DEBUG) { 27618144Sralph printf("got answer:\n"); 27718144Sralph p_query(answer); 27818144Sralph } 27925243Skjd #endif DEBUG 28026322Sbloom /* 28126322Sbloom * We are going to assume that the first server is preferred 28226322Sbloom * over the rest (i.e. it is on the local machine) and only 28326322Sbloom * keep that one open. 28426322Sbloom */ 28526322Sbloom if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) { 28626322Sbloom return (resplen); 28726322Sbloom } else { 28826322Sbloom (void) close(s); 28926322Sbloom s = -1; 29026322Sbloom return (resplen); 29126322Sbloom } 29225243Skjd } 29318144Sralph } 29429434Sbloom if (s >= 0) { 29529434Sbloom (void) close(s); 29629434Sbloom s = -1; 29729434Sbloom } 29829434Sbloom if (v_circuit == 0) 29929434Sbloom if (gotsomewhere == 0) 30029434Sbloom errno = ECONNREFUSED; 30129434Sbloom else 30229434Sbloom errno = ETIMEDOUT; 30326483Skarels else 30429434Sbloom errno = terrno; 30518144Sralph return (-1); 30618144Sralph } 30727025Sbloom 30827025Sbloom /* 30927025Sbloom * This routine is for closing the socket if a virtual circuit is used and 31027025Sbloom * the program wants to close it. This provides support for endhostent() 31127025Sbloom * which expects to close the socket. 31227025Sbloom * 31327025Sbloom * This routine is not expected to be user visible. 31427025Sbloom */ 31527025Sbloom _res_close() 31627025Sbloom { 31727025Sbloom if (s != -1) { 31827025Sbloom (void) close(s); 31927025Sbloom s = -1; 32027025Sbloom } 32127025Sbloom } 322