118144Sralph /* 221388Sdist * Copyright (c) 1985 Regents of the University of California. 333679Sbostic * All rights reserved. 433679Sbostic * 533679Sbostic * Redistribution and use in source and binary forms are permitted 633679Sbostic * provided that this notice is preserved and that due credit is given 733679Sbostic * to the University of California at Berkeley. The name of the University 833679Sbostic * may not be used to endorse or promote products derived from this 933679Sbostic * software without specific prior written permission. This software 1033679Sbostic * is provided ``as is'' without express or implied warranty. 1118548Sralph */ 1218548Sralph 1326635Sdonn #if defined(LIBC_SCCS) && !defined(lint) 14*34341Skarels static char sccsid[] = "@(#)res_send.c 6.20 (Berkeley) 05/19/88"; 1533679Sbostic #endif /* LIBC_SCCS and not lint */ 1621388Sdist 1718548Sralph /* 1818144Sralph * Send query to name server and wait for reply. 1918144Sralph */ 2018144Sralph 2126886Skjd #include <sys/param.h> 2218144Sralph #include <sys/time.h> 2318144Sralph #include <sys/socket.h> 2427664Sbloom #include <sys/uio.h> 2518144Sralph #include <netinet/in.h> 2618144Sralph #include <stdio.h> 2718144Sralph #include <errno.h> 2824083Skjd #include <arpa/nameser.h> 2926896Skjd #include <resolv.h> 3018144Sralph 3118144Sralph extern int errno; 3218144Sralph 3327025Sbloom static int s = -1; /* socket used for communications */ 3431113Skarels static struct sockaddr no_addr; 3530100Skjd 3627025Sbloom 3730100Skjd #ifndef FD_SET 3830100Skjd #define NFDBITS 32 3930100Skjd #define FD_SETSIZE 32 4030100Skjd #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) 4130100Skjd #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) 4230100Skjd #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) 4330100Skjd #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) 4430100Skjd #endif 4530100Skjd 4626322Sbloom #define KEEPOPEN (RES_USEVC|RES_STAYOPEN) 4726322Sbloom 4818531Sralph res_send(buf, buflen, answer, anslen) 4918144Sralph char *buf; 5018144Sralph int buflen; 5118144Sralph char *answer; 5218144Sralph int anslen; 5318144Sralph { 5418144Sralph register int n; 5526322Sbloom int retry, v_circuit, resplen, ns; 5632603Skarels int gotsomewhere = 0, connected = 0; 5718144Sralph u_short id, len; 5818144Sralph char *cp; 5927796Skjd fd_set dsmask; 6018144Sralph struct timeval timeout; 6118144Sralph HEADER *hp = (HEADER *) buf; 6218144Sralph HEADER *anhp = (HEADER *) answer; 6327664Sbloom struct iovec iov[2]; 6429434Sbloom int terrno = ETIMEDOUT; 6532603Skarels char junk[512]; 6618144Sralph 6724734Sbloom #ifdef DEBUG 6818144Sralph if (_res.options & RES_DEBUG) { 6918531Sralph printf("res_send()\n"); 7018144Sralph p_query(buf); 7118144Sralph } 7225243Skjd #endif DEBUG 7318531Sralph if (!(_res.options & RES_INIT)) 7424734Sbloom if (res_init() == -1) { 7524734Sbloom return(-1); 7624734Sbloom } 7718144Sralph v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; 7818144Sralph id = hp->id; 7918144Sralph /* 8018144Sralph * Send request, RETRY times, or until successful 8118144Sralph */ 8227040Skjd for (retry = _res.retry; retry > 0; retry--) { 8325243Skjd for (ns = 0; ns < _res.nscount; ns++) { 8425243Skjd #ifdef DEBUG 8525243Skjd if (_res.options & RES_DEBUG) 8625243Skjd printf("Querying server (# %d) address = %s\n", ns+1, 8732603Skarels inet_ntoa(_res.nsaddr_list[ns].sin_addr)); 8825243Skjd #endif DEBUG 8918144Sralph if (v_circuit) { 9032603Skarels int truncated = 0; 9132603Skarels 9218144Sralph /* 9318144Sralph * Use virtual circuit. 9418144Sralph */ 9526322Sbloom if (s < 0) { 9618144Sralph s = socket(AF_INET, SOCK_STREAM, 0); 9726483Skarels if (s < 0) { 9829434Sbloom terrno = errno; 9926483Skarels #ifdef DEBUG 10026483Skarels if (_res.options & RES_DEBUG) 10127031Skjd perror("socket failed"); 10226483Skarels #endif DEBUG 10326483Skarels continue; 10426483Skarels } 10527031Skjd if (connect(s, &(_res.nsaddr_list[ns]), 10626322Sbloom sizeof(struct sockaddr)) < 0) { 10729434Sbloom terrno = errno; 10824734Sbloom #ifdef DEBUG 10926322Sbloom if (_res.options & RES_DEBUG) 11027031Skjd perror("connect failed"); 11125243Skjd #endif DEBUG 11226322Sbloom (void) close(s); 11326322Sbloom s = -1; 11426322Sbloom continue; 11526322Sbloom } 11618144Sralph } 11718144Sralph /* 11818144Sralph * Send length & message 11918144Sralph */ 12027025Sbloom len = htons((u_short)buflen); 12127664Sbloom iov[0].iov_base = (caddr_t)&len; 12227664Sbloom iov[0].iov_len = sizeof(len); 12327664Sbloom iov[1].iov_base = buf; 12427664Sbloom iov[1].iov_len = buflen; 12527664Sbloom if (writev(s, iov, 2) != sizeof(len) + buflen) { 12629434Sbloom terrno = errno; 12724734Sbloom #ifdef DEBUG 12818144Sralph if (_res.options & RES_DEBUG) 12927031Skjd perror("write failed"); 13025243Skjd #endif DEBUG 13118144Sralph (void) close(s); 13218144Sralph s = -1; 13318144Sralph continue; 13418144Sralph } 13518144Sralph /* 13618144Sralph * Receive length & response 13718144Sralph */ 13818144Sralph cp = answer; 13918144Sralph len = sizeof(short); 14027664Sbloom while (len != 0 && 14127031Skjd (n = read(s, (char *)cp, (int)len)) > 0) { 14218144Sralph cp += n; 14318144Sralph len -= n; 14418144Sralph } 14518144Sralph if (n <= 0) { 14629434Sbloom terrno = errno; 14724734Sbloom #ifdef DEBUG 14818144Sralph if (_res.options & RES_DEBUG) 14927031Skjd perror("read failed"); 15025243Skjd #endif DEBUG 15118144Sralph (void) close(s); 15218144Sralph s = -1; 15318144Sralph continue; 15418144Sralph } 15518144Sralph cp = answer; 15632603Skarels if ((resplen = ntohs(*(u_short *)cp)) > anslen) { 15732603Skarels #ifdef DEBUG 15832603Skarels if (_res.options & RES_DEBUG) 15932603Skarels fprintf(stderr, "response truncated\n"); 16032603Skarels #endif DEBUG 16132603Skarels len = anslen; 16232603Skarels truncated = 1; 16332603Skarels } else 16432603Skarels len = resplen; 16527664Sbloom while (len != 0 && 16627031Skjd (n = read(s, (char *)cp, (int)len)) > 0) { 16718144Sralph cp += n; 16818144Sralph len -= n; 16918144Sralph } 17018144Sralph if (n <= 0) { 17129434Sbloom terrno = errno; 17224734Sbloom #ifdef DEBUG 17318144Sralph if (_res.options & RES_DEBUG) 17427031Skjd perror("read failed"); 17525243Skjd #endif DEBUG 17618144Sralph (void) close(s); 17718144Sralph s = -1; 17818144Sralph continue; 17918144Sralph } 18032603Skarels if (truncated) { 18132603Skarels /* 18232603Skarels * Flush rest of answer 18332603Skarels * so connection stays in synch. 18432603Skarels */ 18532603Skarels anhp->tc = 1; 18632603Skarels len = resplen - anslen; 18732603Skarels while (len != 0) { 18832603Skarels n = (len > sizeof(junk) ? 18932603Skarels sizeof(junk) : len); 19032603Skarels if ((n = read(s, junk, n)) > 0) 19132603Skarels len -= n; 19232603Skarels else 19332603Skarels break; 19432603Skarels } 19532603Skarels } 19618144Sralph } else { 19718144Sralph /* 19818144Sralph * Use datagrams. 19918144Sralph */ 20018144Sralph if (s < 0) 20118144Sralph s = socket(AF_INET, SOCK_DGRAM, 0); 20226483Skarels #if BSD >= 43 20331113Skarels if (_res.nscount == 1 || retry == _res.retry) { 20430394Skjd /* 20531113Skarels * Don't use connect if we might 20631113Skarels * still receive a response 20731113Skarels * from another server. 20830394Skjd */ 20932603Skarels if (connected == 0) { 21032603Skarels if (connect(s, &_res.nsaddr_list[ns], 21132603Skarels sizeof(struct sockaddr)) < 0) { 21224734Sbloom #ifdef DEBUG 21332603Skarels if (_res.options & RES_DEBUG) 21432603Skarels perror("connect"); 21532603Skarels #endif DEBUG 21632603Skarels continue; 21732603Skarels } 21832603Skarels connected = 1; 21932603Skarels } 22032603Skarels if (send(s, buf, buflen, 0) != buflen) { 22132603Skarels #ifdef DEBUG 22230394Skjd if (_res.options & RES_DEBUG) 22332603Skarels perror("send"); 22425243Skjd #endif DEBUG 22530394Skjd continue; 22630394Skjd } 227*34341Skarels } else { 228*34341Skarels /* 229*34341Skarels * Disconnect if we want to listen 230*34341Skarels * for responses from more than one server. 231*34341Skarels */ 232*34341Skarels if (connected) { 233*34341Skarels (void) connect(s, &no_addr, 234*34341Skarels sizeof(no_addr)); 235*34341Skarels connected = 0; 236*34341Skarels } 23730394Skjd #endif BSD 238*34341Skarels if (sendto(s, buf, buflen, 0, 239*34341Skarels &_res.nsaddr_list[ns], 240*34341Skarels sizeof(struct sockaddr)) != buflen) { 24126483Skarels #ifdef DEBUG 242*34341Skarels if (_res.options & RES_DEBUG) 243*34341Skarels perror("sendto"); 24426483Skarels #endif DEBUG 245*34341Skarels continue; 246*34341Skarels } 247*34341Skarels #if BSD >= 43 24826483Skarels } 249*34341Skarels #endif 25030394Skjd 25118144Sralph /* 25227031Skjd * Wait for reply 25318144Sralph */ 25427031Skjd timeout.tv_sec = (_res.retrans << (_res.retry - retry)) 25527031Skjd / _res.nscount; 25627031Skjd if (timeout.tv_sec <= 0) 25727031Skjd timeout.tv_sec = 1; 25818144Sralph timeout.tv_usec = 0; 25926323Skarels wait: 26027796Skjd FD_ZERO(&dsmask); 26127796Skjd FD_SET(s, &dsmask); 26227664Sbloom n = select(s+1, &dsmask, (fd_set *)NULL, 26327664Sbloom (fd_set *)NULL, &timeout); 26418144Sralph if (n < 0) { 26524734Sbloom #ifdef DEBUG 26618144Sralph if (_res.options & RES_DEBUG) 26727031Skjd perror("select"); 26825243Skjd #endif DEBUG 26918144Sralph continue; 27018144Sralph } 27118144Sralph if (n == 0) { 27218144Sralph /* 27318144Sralph * timeout 27418144Sralph */ 27524734Sbloom #ifdef DEBUG 27618144Sralph if (_res.options & RES_DEBUG) 27718144Sralph printf("timeout\n"); 27825243Skjd #endif DEBUG 27926483Skarels gotsomewhere = 1; 28018144Sralph continue; 28118144Sralph } 28225332Skjd if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 28324734Sbloom #ifdef DEBUG 28418144Sralph if (_res.options & RES_DEBUG) 28527031Skjd perror("recvfrom"); 28625243Skjd #endif DEBUG 28718144Sralph continue; 28818144Sralph } 28926483Skarels gotsomewhere = 1; 29018144Sralph if (id != anhp->id) { 29118144Sralph /* 29218144Sralph * response from old query, ignore it 29318144Sralph */ 29424734Sbloom #ifdef DEBUG 29518144Sralph if (_res.options & RES_DEBUG) { 29618144Sralph printf("old answer:\n"); 29718144Sralph p_query(answer); 29818144Sralph } 29925243Skjd #endif DEBUG 30026323Skarels goto wait; 30118144Sralph } 30218144Sralph if (!(_res.options & RES_IGNTC) && anhp->tc) { 30318144Sralph /* 30418144Sralph * get rest of answer 30518144Sralph */ 30624734Sbloom #ifdef DEBUG 30718144Sralph if (_res.options & RES_DEBUG) 30818144Sralph printf("truncated answer\n"); 30925243Skjd #endif DEBUG 31018144Sralph (void) close(s); 31118144Sralph s = -1; 31227040Skjd /* 31327040Skjd * retry decremented on continue 31427040Skjd * to desired starting value 31527040Skjd */ 31627040Skjd retry = _res.retry + 1; 31718144Sralph v_circuit = 1; 31818144Sralph continue; 31918144Sralph } 32018144Sralph } 32124734Sbloom #ifdef DEBUG 32218144Sralph if (_res.options & RES_DEBUG) { 32318144Sralph printf("got answer:\n"); 32418144Sralph p_query(answer); 32518144Sralph } 32625243Skjd #endif DEBUG 32726322Sbloom /* 32826322Sbloom * We are going to assume that the first server is preferred 32926322Sbloom * over the rest (i.e. it is on the local machine) and only 33026322Sbloom * keep that one open. 33126322Sbloom */ 332*34341Skarels if ((_res.options & KEEPOPEN) == 0 || ns != 0) { 33326322Sbloom (void) close(s); 33426322Sbloom s = -1; 33526322Sbloom } 336*34341Skarels return (resplen); 33725243Skjd } 33818144Sralph } 33929434Sbloom if (s >= 0) { 34029434Sbloom (void) close(s); 34129434Sbloom s = -1; 34229434Sbloom } 34329434Sbloom if (v_circuit == 0) 34429434Sbloom if (gotsomewhere == 0) 34529434Sbloom errno = ECONNREFUSED; 34629434Sbloom else 34729434Sbloom errno = ETIMEDOUT; 34826483Skarels else 34929434Sbloom errno = terrno; 35018144Sralph return (-1); 35118144Sralph } 35227025Sbloom 35327025Sbloom /* 35427025Sbloom * This routine is for closing the socket if a virtual circuit is used and 35527025Sbloom * the program wants to close it. This provides support for endhostent() 35627025Sbloom * which expects to close the socket. 35727025Sbloom * 35827025Sbloom * This routine is not expected to be user visible. 35927025Sbloom */ 36027025Sbloom _res_close() 36127025Sbloom { 36227025Sbloom if (s != -1) { 36327025Sbloom (void) close(s); 36427025Sbloom s = -1; 36527025Sbloom } 36627025Sbloom } 367