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*32603Skarels static char sccsid[] = "@(#)res_send.c 6.18 (Berkeley) 11/07/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 */ 2931113Skarels 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; 51*32603Skarels int gotsomewhere = 0, connected = 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; 60*32603Skarels char junk[512]; 6118144Sralph 6224734Sbloom #ifdef DEBUG 6318144Sralph if (_res.options & RES_DEBUG) { 6418531Sralph printf("res_send()\n"); 6518144Sralph p_query(buf); 6618144Sralph } 6725243Skjd #endif DEBUG 6818531Sralph if (!(_res.options & RES_INIT)) 6924734Sbloom if (res_init() == -1) { 7024734Sbloom return(-1); 7124734Sbloom } 7218144Sralph v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; 7318144Sralph id = hp->id; 7418144Sralph /* 7518144Sralph * Send request, RETRY times, or until successful 7618144Sralph */ 7727040Skjd for (retry = _res.retry; retry > 0; retry--) { 7825243Skjd for (ns = 0; ns < _res.nscount; ns++) { 7925243Skjd #ifdef DEBUG 8025243Skjd if (_res.options & RES_DEBUG) 8125243Skjd printf("Querying server (# %d) address = %s\n", ns+1, 82*32603Skarels inet_ntoa(_res.nsaddr_list[ns].sin_addr)); 8325243Skjd #endif DEBUG 8418144Sralph if (v_circuit) { 85*32603Skarels int truncated = 0; 86*32603Skarels 8718144Sralph /* 8818144Sralph * Use virtual circuit. 8918144Sralph */ 9026322Sbloom if (s < 0) { 9118144Sralph s = socket(AF_INET, SOCK_STREAM, 0); 9226483Skarels if (s < 0) { 9329434Sbloom terrno = errno; 9426483Skarels #ifdef DEBUG 9526483Skarels if (_res.options & RES_DEBUG) 9627031Skjd perror("socket failed"); 9726483Skarels #endif DEBUG 9826483Skarels continue; 9926483Skarels } 10027031Skjd if (connect(s, &(_res.nsaddr_list[ns]), 10126322Sbloom sizeof(struct sockaddr)) < 0) { 10229434Sbloom terrno = errno; 10324734Sbloom #ifdef DEBUG 10426322Sbloom if (_res.options & RES_DEBUG) 10527031Skjd perror("connect failed"); 10625243Skjd #endif DEBUG 10726322Sbloom (void) close(s); 10826322Sbloom s = -1; 10926322Sbloom continue; 11026322Sbloom } 11118144Sralph } 11218144Sralph /* 11318144Sralph * Send length & message 11418144Sralph */ 11527025Sbloom len = htons((u_short)buflen); 11627664Sbloom iov[0].iov_base = (caddr_t)&len; 11727664Sbloom iov[0].iov_len = sizeof(len); 11827664Sbloom iov[1].iov_base = buf; 11927664Sbloom iov[1].iov_len = buflen; 12027664Sbloom if (writev(s, iov, 2) != sizeof(len) + buflen) { 12129434Sbloom terrno = errno; 12224734Sbloom #ifdef DEBUG 12318144Sralph if (_res.options & RES_DEBUG) 12427031Skjd perror("write failed"); 12525243Skjd #endif DEBUG 12618144Sralph (void) close(s); 12718144Sralph s = -1; 12818144Sralph continue; 12918144Sralph } 13018144Sralph /* 13118144Sralph * Receive length & response 13218144Sralph */ 13318144Sralph cp = answer; 13418144Sralph len = sizeof(short); 13527664Sbloom while (len != 0 && 13627031Skjd (n = read(s, (char *)cp, (int)len)) > 0) { 13718144Sralph cp += n; 13818144Sralph len -= n; 13918144Sralph } 14018144Sralph if (n <= 0) { 14129434Sbloom terrno = errno; 14224734Sbloom #ifdef DEBUG 14318144Sralph if (_res.options & RES_DEBUG) 14427031Skjd perror("read failed"); 14525243Skjd #endif DEBUG 14618144Sralph (void) close(s); 14718144Sralph s = -1; 14818144Sralph continue; 14918144Sralph } 15018144Sralph cp = answer; 151*32603Skarels if ((resplen = ntohs(*(u_short *)cp)) > anslen) { 152*32603Skarels #ifdef DEBUG 153*32603Skarels if (_res.options & RES_DEBUG) 154*32603Skarels fprintf(stderr, "response truncated\n"); 155*32603Skarels #endif DEBUG 156*32603Skarels len = anslen; 157*32603Skarels truncated = 1; 158*32603Skarels } else 159*32603Skarels len = resplen; 16027664Sbloom while (len != 0 && 16127031Skjd (n = read(s, (char *)cp, (int)len)) > 0) { 16218144Sralph cp += n; 16318144Sralph len -= n; 16418144Sralph } 16518144Sralph if (n <= 0) { 16629434Sbloom terrno = errno; 16724734Sbloom #ifdef DEBUG 16818144Sralph if (_res.options & RES_DEBUG) 16927031Skjd perror("read failed"); 17025243Skjd #endif DEBUG 17118144Sralph (void) close(s); 17218144Sralph s = -1; 17318144Sralph continue; 17418144Sralph } 175*32603Skarels if (truncated) { 176*32603Skarels /* 177*32603Skarels * Flush rest of answer 178*32603Skarels * so connection stays in synch. 179*32603Skarels */ 180*32603Skarels anhp->tc = 1; 181*32603Skarels len = resplen - anslen; 182*32603Skarels while (len != 0) { 183*32603Skarels n = (len > sizeof(junk) ? 184*32603Skarels sizeof(junk) : len); 185*32603Skarels if ((n = read(s, junk, n)) > 0) 186*32603Skarels len -= n; 187*32603Skarels else 188*32603Skarels break; 189*32603Skarels } 190*32603Skarels } 19118144Sralph } else { 19218144Sralph /* 19318144Sralph * Use datagrams. 19418144Sralph */ 19518144Sralph if (s < 0) 19618144Sralph s = socket(AF_INET, SOCK_DGRAM, 0); 19726483Skarels #if BSD >= 43 19831113Skarels if (_res.nscount == 1 || retry == _res.retry) { 19930394Skjd /* 20031113Skarels * Don't use connect if we might 20131113Skarels * still receive a response 20231113Skarels * from another server. 20330394Skjd */ 204*32603Skarels if (connected == 0) { 205*32603Skarels if (connect(s, &_res.nsaddr_list[ns], 206*32603Skarels sizeof(struct sockaddr)) < 0) { 20724734Sbloom #ifdef DEBUG 208*32603Skarels if (_res.options & RES_DEBUG) 209*32603Skarels perror("connect"); 210*32603Skarels #endif DEBUG 211*32603Skarels continue; 212*32603Skarels } 213*32603Skarels connected = 1; 214*32603Skarels } 215*32603Skarels if (send(s, buf, buflen, 0) != buflen) { 216*32603Skarels #ifdef DEBUG 21730394Skjd if (_res.options & RES_DEBUG) 218*32603Skarels perror("send"); 21925243Skjd #endif DEBUG 22030394Skjd continue; 22130394Skjd } 22230394Skjd } else 22330394Skjd #endif BSD 22426483Skarels if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns], 22526483Skarels sizeof(struct sockaddr)) != buflen) { 22626483Skarels #ifdef DEBUG 22727031Skjd if (_res.options & RES_DEBUG) 22827031Skjd perror("sendto"); 22926483Skarels #endif DEBUG 23026483Skarels continue; 23126483Skarels } 23230394Skjd 23318144Sralph /* 23427031Skjd * Wait for reply 23518144Sralph */ 23627031Skjd timeout.tv_sec = (_res.retrans << (_res.retry - retry)) 23727031Skjd / _res.nscount; 23827031Skjd if (timeout.tv_sec <= 0) 23927031Skjd timeout.tv_sec = 1; 24018144Sralph timeout.tv_usec = 0; 24126323Skarels wait: 24227796Skjd FD_ZERO(&dsmask); 24327796Skjd FD_SET(s, &dsmask); 24427664Sbloom n = select(s+1, &dsmask, (fd_set *)NULL, 24527664Sbloom (fd_set *)NULL, &timeout); 24618144Sralph if (n < 0) { 24724734Sbloom #ifdef DEBUG 24818144Sralph if (_res.options & RES_DEBUG) 24927031Skjd perror("select"); 25025243Skjd #endif DEBUG 25118144Sralph continue; 25218144Sralph } 25318144Sralph if (n == 0) { 25418144Sralph /* 25518144Sralph * timeout 25618144Sralph */ 25724734Sbloom #ifdef DEBUG 25818144Sralph if (_res.options & RES_DEBUG) 25918144Sralph printf("timeout\n"); 26025243Skjd #endif DEBUG 26131113Skarels /* 26231113Skarels * Disconnect if we want to listen 26331113Skarels * for responses from more than one server. 26431113Skarels */ 265*32603Skarels if (_res.nscount > 1 && connected) { 26631113Skarels (void) connect(s, &no_addr, 26731113Skarels sizeof(no_addr)); 268*32603Skarels connected = 0; 269*32603Skarels } 27026483Skarels gotsomewhere = 1; 27118144Sralph continue; 27218144Sralph } 27325332Skjd if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 27424734Sbloom #ifdef DEBUG 27518144Sralph if (_res.options & RES_DEBUG) 27627031Skjd perror("recvfrom"); 27725243Skjd #endif DEBUG 27818144Sralph continue; 27918144Sralph } 28026483Skarels gotsomewhere = 1; 28118144Sralph if (id != anhp->id) { 28218144Sralph /* 28318144Sralph * response from old query, ignore it 28418144Sralph */ 28524734Sbloom #ifdef DEBUG 28618144Sralph if (_res.options & RES_DEBUG) { 28718144Sralph printf("old answer:\n"); 28818144Sralph p_query(answer); 28918144Sralph } 29025243Skjd #endif DEBUG 29126323Skarels goto wait; 29218144Sralph } 29318144Sralph if (!(_res.options & RES_IGNTC) && anhp->tc) { 29418144Sralph /* 29518144Sralph * get rest of answer 29618144Sralph */ 29724734Sbloom #ifdef DEBUG 29818144Sralph if (_res.options & RES_DEBUG) 29918144Sralph printf("truncated answer\n"); 30025243Skjd #endif DEBUG 30118144Sralph (void) close(s); 30218144Sralph s = -1; 30327040Skjd /* 30427040Skjd * retry decremented on continue 30527040Skjd * to desired starting value 30627040Skjd */ 30727040Skjd retry = _res.retry + 1; 30818144Sralph v_circuit = 1; 30918144Sralph continue; 31018144Sralph } 31118144Sralph } 31224734Sbloom #ifdef DEBUG 31318144Sralph if (_res.options & RES_DEBUG) { 31418144Sralph printf("got answer:\n"); 31518144Sralph p_query(answer); 31618144Sralph } 31725243Skjd #endif DEBUG 31826322Sbloom /* 31926322Sbloom * We are going to assume that the first server is preferred 32026322Sbloom * over the rest (i.e. it is on the local machine) and only 32126322Sbloom * keep that one open. 32226322Sbloom */ 32326322Sbloom if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) { 32426322Sbloom return (resplen); 32526322Sbloom } else { 32626322Sbloom (void) close(s); 32726322Sbloom s = -1; 32826322Sbloom return (resplen); 32926322Sbloom } 33025243Skjd } 33118144Sralph } 33229434Sbloom if (s >= 0) { 33329434Sbloom (void) close(s); 33429434Sbloom s = -1; 33529434Sbloom } 33629434Sbloom if (v_circuit == 0) 33729434Sbloom if (gotsomewhere == 0) 33829434Sbloom errno = ECONNREFUSED; 33929434Sbloom else 34029434Sbloom errno = ETIMEDOUT; 34126483Skarels else 34229434Sbloom errno = terrno; 34318144Sralph return (-1); 34418144Sralph } 34527025Sbloom 34627025Sbloom /* 34727025Sbloom * This routine is for closing the socket if a virtual circuit is used and 34827025Sbloom * the program wants to close it. This provides support for endhostent() 34927025Sbloom * which expects to close the socket. 35027025Sbloom * 35127025Sbloom * This routine is not expected to be user visible. 35227025Sbloom */ 35327025Sbloom _res_close() 35427025Sbloom { 35527025Sbloom if (s != -1) { 35627025Sbloom (void) close(s); 35727025Sbloom s = -1; 35827025Sbloom } 35927025Sbloom } 360