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*27031Skjd static char sccsid[] = "@(#)res_send.c 6.10 (Berkeley) 04/10/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> 1918144Sralph #include <netinet/in.h> 2018144Sralph #include <stdio.h> 2118144Sralph #include <errno.h> 2224083Skjd #include <arpa/nameser.h> 2326896Skjd #include <resolv.h> 2418144Sralph 2518144Sralph extern int errno; 2618144Sralph 2727025Sbloom static int s = -1; /* socket used for communications */ 2827025Sbloom 2926322Sbloom #define KEEPOPEN (RES_USEVC|RES_STAYOPEN) 3026322Sbloom 3118531Sralph res_send(buf, buflen, answer, anslen) 3218144Sralph char *buf; 3318144Sralph int buflen; 3418144Sralph char *answer; 3518144Sralph int anslen; 3618144Sralph { 3718144Sralph register int n; 3826322Sbloom int retry, v_circuit, resplen, ns; 3926483Skarels int gotsomewhere = 0; 4018144Sralph u_short id, len; 4118144Sralph char *cp; 4218144Sralph int dsmask; 4318144Sralph struct timeval timeout; 4418144Sralph HEADER *hp = (HEADER *) buf; 4518144Sralph HEADER *anhp = (HEADER *) answer; 4618144Sralph 47*27031Skjd extern u_short htons(), ntohs(); 48*27031Skjd 4924734Sbloom #ifdef DEBUG 5018144Sralph if (_res.options & RES_DEBUG) { 5118531Sralph printf("res_send()\n"); 5218144Sralph p_query(buf); 5318144Sralph } 5425243Skjd #endif DEBUG 5518531Sralph if (!(_res.options & RES_INIT)) 5624734Sbloom if (res_init() == -1) { 5724734Sbloom return(-1); 5824734Sbloom } 5918144Sralph v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; 6018144Sralph id = hp->id; 6118144Sralph /* 6218144Sralph * Send request, RETRY times, or until successful 6318144Sralph */ 6418144Sralph for (retry = _res.retry; --retry >= 0; ) { 6525243Skjd for (ns = 0; ns < _res.nscount; ns++) { 6625243Skjd #ifdef DEBUG 6725243Skjd if (_res.options & RES_DEBUG) 6825243Skjd printf("Querying server (# %d) address = %s\n", ns+1, 69*27031Skjd inet_ntoa(_res.nsaddr_list[ns].sin_addr.s_addr)); 7025243Skjd #endif DEBUG 7118144Sralph if (v_circuit) { 7218144Sralph /* 7318144Sralph * Use virtual circuit. 7418144Sralph */ 7526322Sbloom if (s < 0) { 7618144Sralph s = socket(AF_INET, SOCK_STREAM, 0); 7726483Skarels if (s < 0) { 7826483Skarels #ifdef DEBUG 7926483Skarels if (_res.options & RES_DEBUG) 80*27031Skjd perror("socket failed"); 8126483Skarels #endif DEBUG 8226483Skarels continue; 8326483Skarels } 84*27031Skjd if (connect(s, &(_res.nsaddr_list[ns]), 8526322Sbloom sizeof(struct sockaddr)) < 0) { 8624734Sbloom #ifdef DEBUG 8726322Sbloom if (_res.options & RES_DEBUG) 88*27031Skjd perror("connect failed"); 8925243Skjd #endif DEBUG 9026322Sbloom (void) close(s); 9126322Sbloom s = -1; 9226322Sbloom continue; 9326322Sbloom } 9418144Sralph } 9518144Sralph /* 9618144Sralph * Send length & message 9718144Sralph */ 9827025Sbloom len = htons((u_short)buflen); 99*27031Skjd if (write(s, (char *)&len, sizeof(len)) != sizeof(len)|| 100*27031Skjd write(s, buf, buflen) != buflen) { 10124734Sbloom #ifdef DEBUG 10218144Sralph if (_res.options & RES_DEBUG) 103*27031Skjd perror("write failed"); 10425243Skjd #endif DEBUG 10518144Sralph (void) close(s); 10618144Sralph s = -1; 10718144Sralph continue; 10818144Sralph } 10918144Sralph /* 11018144Sralph * Receive length & response 11118144Sralph */ 11218144Sralph cp = answer; 11318144Sralph len = sizeof(short); 114*27031Skjd while (len > 0 && 115*27031Skjd (n = read(s, (char *)cp, (int)len)) > 0) { 11618144Sralph cp += n; 11718144Sralph len -= n; 11818144Sralph } 11918144Sralph if (n <= 0) { 12024734Sbloom #ifdef DEBUG 12118144Sralph if (_res.options & RES_DEBUG) 122*27031Skjd perror("read failed"); 12325243Skjd #endif DEBUG 12418144Sralph (void) close(s); 12518144Sralph s = -1; 12618144Sralph continue; 12718144Sralph } 12818144Sralph cp = answer; 12927025Sbloom resplen = len = ntohs(*(u_short *)cp); 130*27031Skjd while (len > 0 && 131*27031Skjd (n = read(s, (char *)cp, (int)len)) > 0) { 13218144Sralph cp += n; 13318144Sralph len -= n; 13418144Sralph } 13518144Sralph if (n <= 0) { 13624734Sbloom #ifdef DEBUG 13718144Sralph if (_res.options & RES_DEBUG) 138*27031Skjd perror("read failed"); 13925243Skjd #endif DEBUG 14018144Sralph (void) close(s); 14118144Sralph s = -1; 14218144Sralph continue; 14318144Sralph } 14418144Sralph } else { 14518144Sralph /* 14618144Sralph * Use datagrams. 14718144Sralph */ 14818144Sralph if (s < 0) 14918144Sralph s = socket(AF_INET, SOCK_DGRAM, 0); 15026483Skarels #if BSD >= 43 15126323Skarels if (connect(s, &_res.nsaddr_list[ns], 15226323Skarels sizeof(struct sockaddr)) < 0 || 15326323Skarels send(s, buf, buflen, 0) != buflen) { 15424734Sbloom #ifdef DEBUG 155*27031Skjd if (_res.options & RES_DEBUG) 156*27031Skjd perror("connect"); 15725243Skjd #endif DEBUG 15826483Skarels continue; 15918144Sralph } 16026483Skarels #else BSD 16126483Skarels if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns], 16226483Skarels sizeof(struct sockaddr)) != buflen) { 16326483Skarels #ifdef DEBUG 164*27031Skjd if (_res.options & RES_DEBUG) 165*27031Skjd perror("sendto"); 16626483Skarels #endif DEBUG 16726483Skarels continue; 16826483Skarels } 16926483Skarels #endif BSD 17018144Sralph /* 171*27031Skjd * Wait for reply 17218144Sralph */ 173*27031Skjd timeout.tv_sec = (_res.retrans << (_res.retry - retry)) 174*27031Skjd / _res.nscount; 175*27031Skjd if (timeout.tv_sec <= 0) 176*27031Skjd timeout.tv_sec = 1; 17718144Sralph timeout.tv_usec = 0; 17826323Skarels wait: 17918144Sralph dsmask = 1 << s; 18018144Sralph n = select(s+1, &dsmask, 0, 0, &timeout); 18118144Sralph if (n < 0) { 18224734Sbloom #ifdef DEBUG 18318144Sralph if (_res.options & RES_DEBUG) 184*27031Skjd perror("select"); 18525243Skjd #endif DEBUG 18618144Sralph continue; 18718144Sralph } 18818144Sralph if (n == 0) { 18918144Sralph /* 19018144Sralph * timeout 19118144Sralph */ 19224734Sbloom #ifdef DEBUG 19318144Sralph if (_res.options & RES_DEBUG) 19418144Sralph printf("timeout\n"); 19525243Skjd #endif DEBUG 19626483Skarels gotsomewhere = 1; 19718144Sralph continue; 19818144Sralph } 19925332Skjd if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 20024734Sbloom #ifdef DEBUG 20118144Sralph if (_res.options & RES_DEBUG) 202*27031Skjd perror("recvfrom"); 20325243Skjd #endif DEBUG 20418144Sralph continue; 20518144Sralph } 20626483Skarels gotsomewhere = 1; 20718144Sralph if (id != anhp->id) { 20818144Sralph /* 20918144Sralph * response from old query, ignore it 21018144Sralph */ 21124734Sbloom #ifdef DEBUG 21218144Sralph if (_res.options & RES_DEBUG) { 21318144Sralph printf("old answer:\n"); 21418144Sralph p_query(answer); 21518144Sralph } 21625243Skjd #endif DEBUG 21726323Skarels goto wait; 21818144Sralph } 21918144Sralph if (!(_res.options & RES_IGNTC) && anhp->tc) { 22018144Sralph /* 22118144Sralph * get rest of answer 22218144Sralph */ 22324734Sbloom #ifdef DEBUG 22418144Sralph if (_res.options & RES_DEBUG) 22518144Sralph printf("truncated answer\n"); 22625243Skjd #endif DEBUG 22718144Sralph (void) close(s); 22818144Sralph s = -1; 22918144Sralph retry = _res.retry; 23018144Sralph v_circuit = 1; 23118144Sralph continue; 23218144Sralph } 23318144Sralph } 23424734Sbloom #ifdef DEBUG 23518144Sralph if (_res.options & RES_DEBUG) { 23618144Sralph printf("got answer:\n"); 23718144Sralph p_query(answer); 23818144Sralph } 23925243Skjd #endif DEBUG 24026322Sbloom /* 24126322Sbloom * We are going to assume that the first server is preferred 24226322Sbloom * over the rest (i.e. it is on the local machine) and only 24326322Sbloom * keep that one open. 24426322Sbloom */ 24526322Sbloom if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) { 24626322Sbloom return (resplen); 24726322Sbloom } else { 24826322Sbloom (void) close(s); 24926322Sbloom s = -1; 25026322Sbloom return (resplen); 25126322Sbloom } 25225243Skjd } 25318144Sralph } 25423873Skjd (void) close(s); 25526897Sbloom s = -1; 25626483Skarels if (v_circuit == 0 && gotsomewhere == 0) 25726483Skarels errno = ECONNREFUSED; 25826483Skarels else 25926483Skarels errno = ETIMEDOUT; 26018144Sralph return (-1); 26118144Sralph } 26227025Sbloom 26327025Sbloom /* 26427025Sbloom * This routine is for closing the socket if a virtual circuit is used and 26527025Sbloom * the program wants to close it. This provides support for endhostent() 26627025Sbloom * which expects to close the socket. 26727025Sbloom * 26827025Sbloom * This routine is not expected to be user visible. 26927025Sbloom */ 27027025Sbloom _res_close() 27127025Sbloom { 27227025Sbloom if (s != -1) { 27327025Sbloom (void) close(s); 27427025Sbloom s = -1; 27527025Sbloom } 27627025Sbloom } 277