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*30394Skjd static char sccsid[] = "@(#)res_send.c 6.16 (Berkeley) 01/15/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 */ 2930100Skjd 3027025Sbloom 3130100Skjd #ifndef FD_SET 3230100Skjd #define NFDBITS 32 3330100Skjd #define FD_SETSIZE 32 3430100Skjd #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) 3530100Skjd #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) 3630100Skjd #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) 3730100Skjd #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) 3830100Skjd #endif 3930100Skjd 4026322Sbloom #define KEEPOPEN (RES_USEVC|RES_STAYOPEN) 4126322Sbloom 4218531Sralph res_send(buf, buflen, answer, anslen) 4318144Sralph char *buf; 4418144Sralph int buflen; 4518144Sralph char *answer; 4618144Sralph int anslen; 4718144Sralph { 4818144Sralph register int n; 4926322Sbloom int retry, v_circuit, resplen, ns; 5026483Skarels int gotsomewhere = 0; 5118144Sralph u_short id, len; 5218144Sralph char *cp; 5327796Skjd fd_set dsmask; 5418144Sralph struct timeval timeout; 5518144Sralph HEADER *hp = (HEADER *) buf; 5618144Sralph HEADER *anhp = (HEADER *) answer; 5727664Sbloom struct iovec iov[2]; 5829434Sbloom int terrno = ETIMEDOUT; 5918144Sralph 6024734Sbloom #ifdef DEBUG 6118144Sralph if (_res.options & RES_DEBUG) { 6218531Sralph printf("res_send()\n"); 6318144Sralph p_query(buf); 6418144Sralph } 6525243Skjd #endif DEBUG 6618531Sralph if (!(_res.options & RES_INIT)) 6724734Sbloom if (res_init() == -1) { 6824734Sbloom return(-1); 6924734Sbloom } 7018144Sralph v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; 7118144Sralph id = hp->id; 7218144Sralph /* 7318144Sralph * Send request, RETRY times, or until successful 7418144Sralph */ 7527040Skjd for (retry = _res.retry; retry > 0; retry--) { 7625243Skjd for (ns = 0; ns < _res.nscount; ns++) { 7725243Skjd #ifdef DEBUG 7825243Skjd if (_res.options & RES_DEBUG) 7925243Skjd printf("Querying server (# %d) address = %s\n", ns+1, 8027031Skjd inet_ntoa(_res.nsaddr_list[ns].sin_addr.s_addr)); 8125243Skjd #endif DEBUG 8218144Sralph if (v_circuit) { 8318144Sralph /* 8418144Sralph * Use virtual circuit. 8518144Sralph */ 8626322Sbloom if (s < 0) { 8718144Sralph s = socket(AF_INET, SOCK_STREAM, 0); 8826483Skarels if (s < 0) { 8929434Sbloom terrno = errno; 9026483Skarels #ifdef DEBUG 9126483Skarels if (_res.options & RES_DEBUG) 9227031Skjd perror("socket failed"); 9326483Skarels #endif DEBUG 9426483Skarels continue; 9526483Skarels } 9627031Skjd if (connect(s, &(_res.nsaddr_list[ns]), 9726322Sbloom sizeof(struct sockaddr)) < 0) { 9829434Sbloom terrno = errno; 9924734Sbloom #ifdef DEBUG 10026322Sbloom if (_res.options & RES_DEBUG) 10127031Skjd perror("connect failed"); 10225243Skjd #endif DEBUG 10326322Sbloom (void) close(s); 10426322Sbloom s = -1; 10526322Sbloom continue; 10626322Sbloom } 10718144Sralph } 10818144Sralph /* 10918144Sralph * Send length & message 11018144Sralph */ 11127025Sbloom len = htons((u_short)buflen); 11227664Sbloom iov[0].iov_base = (caddr_t)&len; 11327664Sbloom iov[0].iov_len = sizeof(len); 11427664Sbloom iov[1].iov_base = buf; 11527664Sbloom iov[1].iov_len = buflen; 11627664Sbloom if (writev(s, iov, 2) != sizeof(len) + buflen) { 11729434Sbloom terrno = errno; 11824734Sbloom #ifdef DEBUG 11918144Sralph if (_res.options & RES_DEBUG) 12027031Skjd perror("write failed"); 12125243Skjd #endif DEBUG 12218144Sralph (void) close(s); 12318144Sralph s = -1; 12418144Sralph continue; 12518144Sralph } 12618144Sralph /* 12718144Sralph * Receive length & response 12818144Sralph */ 12918144Sralph cp = answer; 13018144Sralph len = sizeof(short); 13127664Sbloom while (len != 0 && 13227031Skjd (n = read(s, (char *)cp, (int)len)) > 0) { 13318144Sralph cp += n; 13418144Sralph len -= n; 13518144Sralph } 13618144Sralph if (n <= 0) { 13729434Sbloom terrno = errno; 13824734Sbloom #ifdef DEBUG 13918144Sralph if (_res.options & RES_DEBUG) 14027031Skjd perror("read failed"); 14125243Skjd #endif DEBUG 14218144Sralph (void) close(s); 14318144Sralph s = -1; 14418144Sralph continue; 14518144Sralph } 14618144Sralph cp = answer; 14727025Sbloom resplen = len = ntohs(*(u_short *)cp); 14827664Sbloom while (len != 0 && 14927031Skjd (n = read(s, (char *)cp, (int)len)) > 0) { 15018144Sralph cp += n; 15118144Sralph len -= n; 15218144Sralph } 15318144Sralph if (n <= 0) { 15429434Sbloom terrno = errno; 15524734Sbloom #ifdef DEBUG 15618144Sralph if (_res.options & RES_DEBUG) 15727031Skjd perror("read failed"); 15825243Skjd #endif DEBUG 15918144Sralph (void) close(s); 16018144Sralph s = -1; 16118144Sralph continue; 16218144Sralph } 16318144Sralph } else { 16418144Sralph /* 16518144Sralph * Use datagrams. 16618144Sralph */ 16718144Sralph if (s < 0) 16818144Sralph s = socket(AF_INET, SOCK_DGRAM, 0); 16926483Skarels #if BSD >= 43 170*30394Skjd if (_res.nscount == 1) { 171*30394Skjd /* 172*30394Skjd * Connect/Send is detrimental if you 173*30394Skjd * are going to poll more than one server 174*30394Skjd */ 175*30394Skjd if (connect(s, &_res.nsaddr_list[ns], 176*30394Skjd sizeof(struct sockaddr)) < 0 || 177*30394Skjd send(s, buf, buflen, 0) != buflen) { 17824734Sbloom #ifdef DEBUG 179*30394Skjd if (_res.options & RES_DEBUG) 180*30394Skjd perror("connect"); 18125243Skjd #endif DEBUG 182*30394Skjd continue; 183*30394Skjd } 184*30394Skjd } else 185*30394Skjd #endif BSD 18626483Skarels if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns], 18726483Skarels sizeof(struct sockaddr)) != buflen) { 18826483Skarels #ifdef DEBUG 18927031Skjd if (_res.options & RES_DEBUG) 19027031Skjd perror("sendto"); 19126483Skarels #endif DEBUG 19226483Skarels continue; 19326483Skarels } 194*30394Skjd 19518144Sralph /* 19627031Skjd * Wait for reply 19718144Sralph */ 19827031Skjd timeout.tv_sec = (_res.retrans << (_res.retry - retry)) 19927031Skjd / _res.nscount; 20027031Skjd if (timeout.tv_sec <= 0) 20127031Skjd timeout.tv_sec = 1; 20218144Sralph timeout.tv_usec = 0; 20326323Skarels wait: 20427796Skjd FD_ZERO(&dsmask); 20527796Skjd FD_SET(s, &dsmask); 20627664Sbloom n = select(s+1, &dsmask, (fd_set *)NULL, 20727664Sbloom (fd_set *)NULL, &timeout); 20818144Sralph if (n < 0) { 20924734Sbloom #ifdef DEBUG 21018144Sralph if (_res.options & RES_DEBUG) 21127031Skjd perror("select"); 21225243Skjd #endif DEBUG 21318144Sralph continue; 21418144Sralph } 21518144Sralph if (n == 0) { 21618144Sralph /* 21718144Sralph * timeout 21818144Sralph */ 21924734Sbloom #ifdef DEBUG 22018144Sralph if (_res.options & RES_DEBUG) 22118144Sralph printf("timeout\n"); 22225243Skjd #endif DEBUG 22326483Skarels gotsomewhere = 1; 22418144Sralph continue; 22518144Sralph } 22625332Skjd if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 22724734Sbloom #ifdef DEBUG 22818144Sralph if (_res.options & RES_DEBUG) 22927031Skjd perror("recvfrom"); 23025243Skjd #endif DEBUG 23118144Sralph continue; 23218144Sralph } 23326483Skarels gotsomewhere = 1; 23418144Sralph if (id != anhp->id) { 23518144Sralph /* 23618144Sralph * response from old query, ignore it 23718144Sralph */ 23824734Sbloom #ifdef DEBUG 23918144Sralph if (_res.options & RES_DEBUG) { 24018144Sralph printf("old answer:\n"); 24118144Sralph p_query(answer); 24218144Sralph } 24325243Skjd #endif DEBUG 24426323Skarels goto wait; 24518144Sralph } 24618144Sralph if (!(_res.options & RES_IGNTC) && anhp->tc) { 24718144Sralph /* 24818144Sralph * get rest of answer 24918144Sralph */ 25024734Sbloom #ifdef DEBUG 25118144Sralph if (_res.options & RES_DEBUG) 25218144Sralph printf("truncated answer\n"); 25325243Skjd #endif DEBUG 25418144Sralph (void) close(s); 25518144Sralph s = -1; 25627040Skjd /* 25727040Skjd * retry decremented on continue 25827040Skjd * to desired starting value 25927040Skjd */ 26027040Skjd retry = _res.retry + 1; 26118144Sralph v_circuit = 1; 26218144Sralph continue; 26318144Sralph } 26418144Sralph } 26524734Sbloom #ifdef DEBUG 26618144Sralph if (_res.options & RES_DEBUG) { 26718144Sralph printf("got answer:\n"); 26818144Sralph p_query(answer); 26918144Sralph } 27025243Skjd #endif DEBUG 27126322Sbloom /* 27226322Sbloom * We are going to assume that the first server is preferred 27326322Sbloom * over the rest (i.e. it is on the local machine) and only 27426322Sbloom * keep that one open. 27526322Sbloom */ 27626322Sbloom if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) { 27726322Sbloom return (resplen); 27826322Sbloom } else { 27926322Sbloom (void) close(s); 28026322Sbloom s = -1; 28126322Sbloom return (resplen); 28226322Sbloom } 28325243Skjd } 28418144Sralph } 28529434Sbloom if (s >= 0) { 28629434Sbloom (void) close(s); 28729434Sbloom s = -1; 28829434Sbloom } 28929434Sbloom if (v_circuit == 0) 29029434Sbloom if (gotsomewhere == 0) 29129434Sbloom errno = ECONNREFUSED; 29229434Sbloom else 29329434Sbloom errno = ETIMEDOUT; 29426483Skarels else 29529434Sbloom errno = terrno; 29618144Sralph return (-1); 29718144Sralph } 29827025Sbloom 29927025Sbloom /* 30027025Sbloom * This routine is for closing the socket if a virtual circuit is used and 30127025Sbloom * the program wants to close it. This provides support for endhostent() 30227025Sbloom * which expects to close the socket. 30327025Sbloom * 30427025Sbloom * This routine is not expected to be user visible. 30527025Sbloom */ 30627025Sbloom _res_close() 30727025Sbloom { 30827025Sbloom if (s != -1) { 30927025Sbloom (void) close(s); 31027025Sbloom s = -1; 31127025Sbloom } 31227025Sbloom } 313