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*29434Sbloom static char sccsid[] = "@(#)res_send.c 6.14 (Berkeley) 07/02/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 */ 2927025Sbloom 3026322Sbloom #define KEEPOPEN (RES_USEVC|RES_STAYOPEN) 3126322Sbloom 3218531Sralph res_send(buf, buflen, answer, anslen) 3318144Sralph char *buf; 3418144Sralph int buflen; 3518144Sralph char *answer; 3618144Sralph int anslen; 3718144Sralph { 3818144Sralph register int n; 3926322Sbloom int retry, v_circuit, resplen, ns; 4026483Skarels int gotsomewhere = 0; 4118144Sralph u_short id, len; 4218144Sralph char *cp; 4327796Skjd fd_set dsmask; 4418144Sralph struct timeval timeout; 4518144Sralph HEADER *hp = (HEADER *) buf; 4618144Sralph HEADER *anhp = (HEADER *) answer; 4727664Sbloom struct iovec iov[2]; 48*29434Sbloom int terrno = ETIMEDOUT; 4918144Sralph 5024734Sbloom #ifdef DEBUG 5118144Sralph if (_res.options & RES_DEBUG) { 5218531Sralph printf("res_send()\n"); 5318144Sralph p_query(buf); 5418144Sralph } 5525243Skjd #endif DEBUG 5618531Sralph if (!(_res.options & RES_INIT)) 5724734Sbloom if (res_init() == -1) { 5824734Sbloom return(-1); 5924734Sbloom } 6018144Sralph v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; 6118144Sralph id = hp->id; 6218144Sralph /* 6318144Sralph * Send request, RETRY times, or until successful 6418144Sralph */ 6527040Skjd for (retry = _res.retry; retry > 0; retry--) { 6625243Skjd for (ns = 0; ns < _res.nscount; ns++) { 6725243Skjd #ifdef DEBUG 6825243Skjd if (_res.options & RES_DEBUG) 6925243Skjd printf("Querying server (# %d) address = %s\n", ns+1, 7027031Skjd inet_ntoa(_res.nsaddr_list[ns].sin_addr.s_addr)); 7125243Skjd #endif DEBUG 7218144Sralph if (v_circuit) { 7318144Sralph /* 7418144Sralph * Use virtual circuit. 7518144Sralph */ 7626322Sbloom if (s < 0) { 7718144Sralph s = socket(AF_INET, SOCK_STREAM, 0); 7826483Skarels if (s < 0) { 79*29434Sbloom terrno = errno; 8026483Skarels #ifdef DEBUG 8126483Skarels if (_res.options & RES_DEBUG) 8227031Skjd perror("socket failed"); 8326483Skarels #endif DEBUG 8426483Skarels continue; 8526483Skarels } 8627031Skjd if (connect(s, &(_res.nsaddr_list[ns]), 8726322Sbloom sizeof(struct sockaddr)) < 0) { 88*29434Sbloom terrno = errno; 8924734Sbloom #ifdef DEBUG 9026322Sbloom if (_res.options & RES_DEBUG) 9127031Skjd perror("connect failed"); 9225243Skjd #endif DEBUG 9326322Sbloom (void) close(s); 9426322Sbloom s = -1; 9526322Sbloom continue; 9626322Sbloom } 9718144Sralph } 9818144Sralph /* 9918144Sralph * Send length & message 10018144Sralph */ 10127025Sbloom len = htons((u_short)buflen); 10227664Sbloom iov[0].iov_base = (caddr_t)&len; 10327664Sbloom iov[0].iov_len = sizeof(len); 10427664Sbloom iov[1].iov_base = buf; 10527664Sbloom iov[1].iov_len = buflen; 10627664Sbloom if (writev(s, iov, 2) != sizeof(len) + buflen) { 107*29434Sbloom terrno = errno; 10824734Sbloom #ifdef DEBUG 10918144Sralph if (_res.options & RES_DEBUG) 11027031Skjd perror("write failed"); 11125243Skjd #endif DEBUG 11218144Sralph (void) close(s); 11318144Sralph s = -1; 11418144Sralph continue; 11518144Sralph } 11618144Sralph /* 11718144Sralph * Receive length & response 11818144Sralph */ 11918144Sralph cp = answer; 12018144Sralph len = sizeof(short); 12127664Sbloom while (len != 0 && 12227031Skjd (n = read(s, (char *)cp, (int)len)) > 0) { 12318144Sralph cp += n; 12418144Sralph len -= n; 12518144Sralph } 12618144Sralph if (n <= 0) { 127*29434Sbloom terrno = errno; 12824734Sbloom #ifdef DEBUG 12918144Sralph if (_res.options & RES_DEBUG) 13027031Skjd perror("read failed"); 13125243Skjd #endif DEBUG 13218144Sralph (void) close(s); 13318144Sralph s = -1; 13418144Sralph continue; 13518144Sralph } 13618144Sralph cp = answer; 13727025Sbloom resplen = len = ntohs(*(u_short *)cp); 13827664Sbloom while (len != 0 && 13927031Skjd (n = read(s, (char *)cp, (int)len)) > 0) { 14018144Sralph cp += n; 14118144Sralph len -= n; 14218144Sralph } 14318144Sralph if (n <= 0) { 144*29434Sbloom terrno = errno; 14524734Sbloom #ifdef DEBUG 14618144Sralph if (_res.options & RES_DEBUG) 14727031Skjd perror("read failed"); 14825243Skjd #endif DEBUG 14918144Sralph (void) close(s); 15018144Sralph s = -1; 15118144Sralph continue; 15218144Sralph } 15318144Sralph } else { 15418144Sralph /* 15518144Sralph * Use datagrams. 15618144Sralph */ 15718144Sralph if (s < 0) 15818144Sralph s = socket(AF_INET, SOCK_DGRAM, 0); 15926483Skarels #if BSD >= 43 16026323Skarels if (connect(s, &_res.nsaddr_list[ns], 16126323Skarels sizeof(struct sockaddr)) < 0 || 16226323Skarels send(s, buf, buflen, 0) != buflen) { 16324734Sbloom #ifdef DEBUG 16427031Skjd if (_res.options & RES_DEBUG) 16527031Skjd perror("connect"); 16625243Skjd #endif DEBUG 16726483Skarels continue; 16818144Sralph } 16926483Skarels #else BSD 17026483Skarels if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns], 17126483Skarels sizeof(struct sockaddr)) != buflen) { 17226483Skarels #ifdef DEBUG 17327031Skjd if (_res.options & RES_DEBUG) 17427031Skjd perror("sendto"); 17526483Skarels #endif DEBUG 17626483Skarels continue; 17726483Skarels } 17826483Skarels #endif BSD 17918144Sralph /* 18027031Skjd * Wait for reply 18118144Sralph */ 18227031Skjd timeout.tv_sec = (_res.retrans << (_res.retry - retry)) 18327031Skjd / _res.nscount; 18427031Skjd if (timeout.tv_sec <= 0) 18527031Skjd timeout.tv_sec = 1; 18618144Sralph timeout.tv_usec = 0; 18726323Skarels wait: 18827796Skjd FD_ZERO(&dsmask); 18927796Skjd FD_SET(s, &dsmask); 19027664Sbloom n = select(s+1, &dsmask, (fd_set *)NULL, 19127664Sbloom (fd_set *)NULL, &timeout); 19218144Sralph if (n < 0) { 19324734Sbloom #ifdef DEBUG 19418144Sralph if (_res.options & RES_DEBUG) 19527031Skjd perror("select"); 19625243Skjd #endif DEBUG 19718144Sralph continue; 19818144Sralph } 19918144Sralph if (n == 0) { 20018144Sralph /* 20118144Sralph * timeout 20218144Sralph */ 20324734Sbloom #ifdef DEBUG 20418144Sralph if (_res.options & RES_DEBUG) 20518144Sralph printf("timeout\n"); 20625243Skjd #endif DEBUG 20726483Skarels gotsomewhere = 1; 20818144Sralph continue; 20918144Sralph } 21025332Skjd if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 21124734Sbloom #ifdef DEBUG 21218144Sralph if (_res.options & RES_DEBUG) 21327031Skjd perror("recvfrom"); 21425243Skjd #endif DEBUG 21518144Sralph continue; 21618144Sralph } 21726483Skarels gotsomewhere = 1; 21818144Sralph if (id != anhp->id) { 21918144Sralph /* 22018144Sralph * response from old query, ignore it 22118144Sralph */ 22224734Sbloom #ifdef DEBUG 22318144Sralph if (_res.options & RES_DEBUG) { 22418144Sralph printf("old answer:\n"); 22518144Sralph p_query(answer); 22618144Sralph } 22725243Skjd #endif DEBUG 22826323Skarels goto wait; 22918144Sralph } 23018144Sralph if (!(_res.options & RES_IGNTC) && anhp->tc) { 23118144Sralph /* 23218144Sralph * get rest of answer 23318144Sralph */ 23424734Sbloom #ifdef DEBUG 23518144Sralph if (_res.options & RES_DEBUG) 23618144Sralph printf("truncated answer\n"); 23725243Skjd #endif DEBUG 23818144Sralph (void) close(s); 23918144Sralph s = -1; 24027040Skjd /* 24127040Skjd * retry decremented on continue 24227040Skjd * to desired starting value 24327040Skjd */ 24427040Skjd retry = _res.retry + 1; 24518144Sralph v_circuit = 1; 24618144Sralph continue; 24718144Sralph } 24818144Sralph } 24924734Sbloom #ifdef DEBUG 25018144Sralph if (_res.options & RES_DEBUG) { 25118144Sralph printf("got answer:\n"); 25218144Sralph p_query(answer); 25318144Sralph } 25425243Skjd #endif DEBUG 25526322Sbloom /* 25626322Sbloom * We are going to assume that the first server is preferred 25726322Sbloom * over the rest (i.e. it is on the local machine) and only 25826322Sbloom * keep that one open. 25926322Sbloom */ 26026322Sbloom if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) { 26126322Sbloom return (resplen); 26226322Sbloom } else { 26326322Sbloom (void) close(s); 26426322Sbloom s = -1; 26526322Sbloom return (resplen); 26626322Sbloom } 26725243Skjd } 26818144Sralph } 269*29434Sbloom if (s >= 0) { 270*29434Sbloom (void) close(s); 271*29434Sbloom s = -1; 272*29434Sbloom } 273*29434Sbloom if (v_circuit == 0) 274*29434Sbloom if (gotsomewhere == 0) 275*29434Sbloom errno = ECONNREFUSED; 276*29434Sbloom else 277*29434Sbloom errno = ETIMEDOUT; 27826483Skarels else 279*29434Sbloom errno = terrno; 28018144Sralph return (-1); 28118144Sralph } 28227025Sbloom 28327025Sbloom /* 28427025Sbloom * This routine is for closing the socket if a virtual circuit is used and 28527025Sbloom * the program wants to close it. This provides support for endhostent() 28627025Sbloom * which expects to close the socket. 28727025Sbloom * 28827025Sbloom * This routine is not expected to be user visible. 28927025Sbloom */ 29027025Sbloom _res_close() 29127025Sbloom { 29227025Sbloom if (s != -1) { 29327025Sbloom (void) close(s); 29427025Sbloom s = -1; 29527025Sbloom } 29627025Sbloom } 297