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*30100Skjd static char sccsid[] = "@(#)res_send.c 6.15 (Berkeley) 11/18/86"; 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*30100Skjd 3027025Sbloom 31*30100Skjd #ifndef FD_SET 32*30100Skjd #define NFDBITS 32 33*30100Skjd #define FD_SETSIZE 32 34*30100Skjd #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) 35*30100Skjd #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) 36*30100Skjd #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) 37*30100Skjd #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) 38*30100Skjd #endif 39*30100Skjd 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 17026323Skarels if (connect(s, &_res.nsaddr_list[ns], 17126323Skarels sizeof(struct sockaddr)) < 0 || 17226323Skarels send(s, buf, buflen, 0) != buflen) { 17324734Sbloom #ifdef DEBUG 17427031Skjd if (_res.options & RES_DEBUG) 17527031Skjd perror("connect"); 17625243Skjd #endif DEBUG 17726483Skarels continue; 17818144Sralph } 17926483Skarels #else BSD 18026483Skarels if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns], 18126483Skarels sizeof(struct sockaddr)) != buflen) { 18226483Skarels #ifdef DEBUG 18327031Skjd if (_res.options & RES_DEBUG) 18427031Skjd perror("sendto"); 18526483Skarels #endif DEBUG 18626483Skarels continue; 18726483Skarels } 18826483Skarels #endif BSD 18918144Sralph /* 19027031Skjd * Wait for reply 19118144Sralph */ 19227031Skjd timeout.tv_sec = (_res.retrans << (_res.retry - retry)) 19327031Skjd / _res.nscount; 19427031Skjd if (timeout.tv_sec <= 0) 19527031Skjd timeout.tv_sec = 1; 19618144Sralph timeout.tv_usec = 0; 19726323Skarels wait: 19827796Skjd FD_ZERO(&dsmask); 19927796Skjd FD_SET(s, &dsmask); 20027664Sbloom n = select(s+1, &dsmask, (fd_set *)NULL, 20127664Sbloom (fd_set *)NULL, &timeout); 20218144Sralph if (n < 0) { 20324734Sbloom #ifdef DEBUG 20418144Sralph if (_res.options & RES_DEBUG) 20527031Skjd perror("select"); 20625243Skjd #endif DEBUG 20718144Sralph continue; 20818144Sralph } 20918144Sralph if (n == 0) { 21018144Sralph /* 21118144Sralph * timeout 21218144Sralph */ 21324734Sbloom #ifdef DEBUG 21418144Sralph if (_res.options & RES_DEBUG) 21518144Sralph printf("timeout\n"); 21625243Skjd #endif DEBUG 21726483Skarels gotsomewhere = 1; 21818144Sralph continue; 21918144Sralph } 22025332Skjd if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 22124734Sbloom #ifdef DEBUG 22218144Sralph if (_res.options & RES_DEBUG) 22327031Skjd perror("recvfrom"); 22425243Skjd #endif DEBUG 22518144Sralph continue; 22618144Sralph } 22726483Skarels gotsomewhere = 1; 22818144Sralph if (id != anhp->id) { 22918144Sralph /* 23018144Sralph * response from old query, ignore it 23118144Sralph */ 23224734Sbloom #ifdef DEBUG 23318144Sralph if (_res.options & RES_DEBUG) { 23418144Sralph printf("old answer:\n"); 23518144Sralph p_query(answer); 23618144Sralph } 23725243Skjd #endif DEBUG 23826323Skarels goto wait; 23918144Sralph } 24018144Sralph if (!(_res.options & RES_IGNTC) && anhp->tc) { 24118144Sralph /* 24218144Sralph * get rest of answer 24318144Sralph */ 24424734Sbloom #ifdef DEBUG 24518144Sralph if (_res.options & RES_DEBUG) 24618144Sralph printf("truncated answer\n"); 24725243Skjd #endif DEBUG 24818144Sralph (void) close(s); 24918144Sralph s = -1; 25027040Skjd /* 25127040Skjd * retry decremented on continue 25227040Skjd * to desired starting value 25327040Skjd */ 25427040Skjd retry = _res.retry + 1; 25518144Sralph v_circuit = 1; 25618144Sralph continue; 25718144Sralph } 25818144Sralph } 25924734Sbloom #ifdef DEBUG 26018144Sralph if (_res.options & RES_DEBUG) { 26118144Sralph printf("got answer:\n"); 26218144Sralph p_query(answer); 26318144Sralph } 26425243Skjd #endif DEBUG 26526322Sbloom /* 26626322Sbloom * We are going to assume that the first server is preferred 26726322Sbloom * over the rest (i.e. it is on the local machine) and only 26826322Sbloom * keep that one open. 26926322Sbloom */ 27026322Sbloom if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) { 27126322Sbloom return (resplen); 27226322Sbloom } else { 27326322Sbloom (void) close(s); 27426322Sbloom s = -1; 27526322Sbloom return (resplen); 27626322Sbloom } 27725243Skjd } 27818144Sralph } 27929434Sbloom if (s >= 0) { 28029434Sbloom (void) close(s); 28129434Sbloom s = -1; 28229434Sbloom } 28329434Sbloom if (v_circuit == 0) 28429434Sbloom if (gotsomewhere == 0) 28529434Sbloom errno = ECONNREFUSED; 28629434Sbloom else 28729434Sbloom errno = ETIMEDOUT; 28826483Skarels else 28929434Sbloom errno = terrno; 29018144Sralph return (-1); 29118144Sralph } 29227025Sbloom 29327025Sbloom /* 29427025Sbloom * This routine is for closing the socket if a virtual circuit is used and 29527025Sbloom * the program wants to close it. This provides support for endhostent() 29627025Sbloom * which expects to close the socket. 29727025Sbloom * 29827025Sbloom * This routine is not expected to be user visible. 29927025Sbloom */ 30027025Sbloom _res_close() 30127025Sbloom { 30227025Sbloom if (s != -1) { 30327025Sbloom (void) close(s); 30427025Sbloom s = -1; 30527025Sbloom } 30627025Sbloom } 307