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*26896Skjd static char sccsid[] = "@(#)res_send.c 6.7 (Berkeley) 03/17/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> 23*26896Skjd #include <resolv.h> 2418144Sralph 2518144Sralph extern int errno; 2618144Sralph 2726322Sbloom #define KEEPOPEN (RES_USEVC|RES_STAYOPEN) 2826322Sbloom 2918531Sralph res_send(buf, buflen, answer, anslen) 3018144Sralph char *buf; 3118144Sralph int buflen; 3218144Sralph char *answer; 3318144Sralph int anslen; 3418144Sralph { 3518144Sralph register int n; 3626322Sbloom int retry, v_circuit, resplen, ns; 3726322Sbloom static int s = -1; 3826483Skarels int gotsomewhere = 0; 3918144Sralph u_short id, len; 4018144Sralph char *cp; 4118144Sralph int dsmask; 4218144Sralph struct timeval timeout; 4318144Sralph HEADER *hp = (HEADER *) buf; 4418144Sralph HEADER *anhp = (HEADER *) answer; 4518144Sralph 4624734Sbloom #ifdef DEBUG 4718144Sralph if (_res.options & RES_DEBUG) { 4818531Sralph printf("res_send()\n"); 4918144Sralph p_query(buf); 5018144Sralph } 5125243Skjd #endif DEBUG 5218531Sralph if (!(_res.options & RES_INIT)) 5324734Sbloom if (res_init() == -1) { 5424734Sbloom return(-1); 5524734Sbloom } 5618144Sralph v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; 5718144Sralph id = hp->id; 5818144Sralph /* 5918144Sralph * Send request, RETRY times, or until successful 6018144Sralph */ 6118144Sralph for (retry = _res.retry; --retry >= 0; ) { 6225243Skjd for (ns = 0; ns < _res.nscount; ns++) { 6325243Skjd #ifdef DEBUG 6425243Skjd if (_res.options & RES_DEBUG) 6525243Skjd printf("Querying server (# %d) address = %s\n", ns+1, 6625243Skjd inet_ntoa(_res.nsaddr_list[ns].sin_addr.s_addr)); 6725243Skjd #endif DEBUG 6818144Sralph if (v_circuit) { 6918144Sralph /* 7018144Sralph * Use virtual circuit. 7118144Sralph */ 7226322Sbloom if (s < 0) { 7318144Sralph s = socket(AF_INET, SOCK_STREAM, 0); 7426483Skarels if (s < 0) { 7526483Skarels #ifdef DEBUG 7626483Skarels if (_res.options & RES_DEBUG) 7726483Skarels printf("socket failed %d\n",errno); 7826483Skarels #endif DEBUG 7926483Skarels continue; 8026483Skarels } 8126322Sbloom if (connect(s, &(_res.nsaddr_list[ns]), 8226322Sbloom sizeof(struct sockaddr)) < 0) { 8324734Sbloom #ifdef DEBUG 8426322Sbloom if (_res.options & RES_DEBUG) 8526322Sbloom printf("connect failed %d\n",errno); 8625243Skjd #endif DEBUG 8726322Sbloom (void) close(s); 8826322Sbloom s = -1; 8926322Sbloom continue; 9026322Sbloom } 9118144Sralph } 9218144Sralph /* 9318144Sralph * Send length & message 9418144Sralph */ 9518144Sralph len = htons(buflen); 9618144Sralph if (write(s, &len, sizeof(len)) != sizeof(len) || 9725243Skjd write(s, buf, buflen) != buflen) { 9824734Sbloom #ifdef DEBUG 9918144Sralph if (_res.options & RES_DEBUG) 10018144Sralph printf("write failed %d\n", errno); 10125243Skjd #endif DEBUG 10218144Sralph (void) close(s); 10318144Sralph s = -1; 10418144Sralph continue; 10518144Sralph } 10618144Sralph /* 10718144Sralph * Receive length & response 10818144Sralph */ 10918144Sralph cp = answer; 11018144Sralph len = sizeof(short); 11118144Sralph while (len > 0 && (n = read(s, cp, len)) > 0) { 11218144Sralph cp += n; 11318144Sralph len -= n; 11418144Sralph } 11518144Sralph if (n <= 0) { 11624734Sbloom #ifdef DEBUG 11718144Sralph if (_res.options & RES_DEBUG) 11818144Sralph printf("read failed %d\n", errno); 11925243Skjd #endif DEBUG 12018144Sralph (void) close(s); 12118144Sralph s = -1; 12218144Sralph continue; 12318144Sralph } 12418144Sralph cp = answer; 12518144Sralph resplen = len = ntohs(*(short *)cp); 12618144Sralph while (len > 0 && (n = read(s, cp, len)) > 0) { 12718144Sralph cp += n; 12818144Sralph len -= n; 12918144Sralph } 13018144Sralph if (n <= 0) { 13124734Sbloom #ifdef DEBUG 13218144Sralph if (_res.options & RES_DEBUG) 13318144Sralph printf("read failed %d\n", errno); 13425243Skjd #endif DEBUG 13518144Sralph (void) close(s); 13618144Sralph s = -1; 13718144Sralph continue; 13818144Sralph } 13918144Sralph } else { 14018144Sralph /* 14118144Sralph * Use datagrams. 14218144Sralph */ 14318144Sralph if (s < 0) 14418144Sralph s = socket(AF_INET, SOCK_DGRAM, 0); 14526483Skarels #if BSD >= 43 14626323Skarels if (connect(s, &_res.nsaddr_list[ns], 14726323Skarels sizeof(struct sockaddr)) < 0 || 14826323Skarels send(s, buf, buflen, 0) != buflen) { 14924734Sbloom #ifdef DEBUG 15025243Skjd if (_res.options & RES_DEBUG) 15126323Skarels printf("connect/send errno = %d\n", 15226323Skarels errno); 15325243Skjd #endif DEBUG 15426483Skarels continue; 15518144Sralph } 15626483Skarels #else BSD 15726483Skarels if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns], 15826483Skarels sizeof(struct sockaddr)) != buflen) { 15926483Skarels #ifdef DEBUG 16026483Skarels if (_res.options & RES_DEBUG) 16126483Skarels printf("sendto errno = %d\n", errno); 16226483Skarels #endif DEBUG 16326483Skarels continue; 16426483Skarels } 16526483Skarels #endif BSD 16618144Sralph /* 16718144Sralph * Wait for reply 16818144Sralph */ 16925243Skjd timeout.tv_sec = 17025243Skjd ((_res.retrans * _res.retry) / _res.nscount); 17118144Sralph timeout.tv_usec = 0; 17226323Skarels wait: 17318144Sralph dsmask = 1 << s; 17418144Sralph n = select(s+1, &dsmask, 0, 0, &timeout); 17518144Sralph if (n < 0) { 17624734Sbloom #ifdef DEBUG 17718144Sralph if (_res.options & RES_DEBUG) 17818144Sralph printf("select errno = %d\n", errno); 17925243Skjd #endif DEBUG 18018144Sralph continue; 18118144Sralph } 18218144Sralph if (n == 0) { 18318144Sralph /* 18418144Sralph * timeout 18518144Sralph */ 18624734Sbloom #ifdef DEBUG 18718144Sralph if (_res.options & RES_DEBUG) 18818144Sralph printf("timeout\n"); 18925243Skjd #endif DEBUG 19026483Skarels gotsomewhere = 1; 19118144Sralph continue; 19218144Sralph } 19325332Skjd if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 19424734Sbloom #ifdef DEBUG 19518144Sralph if (_res.options & RES_DEBUG) 19618144Sralph printf("recvfrom, errno=%d\n", errno); 19725243Skjd #endif DEBUG 19818144Sralph continue; 19918144Sralph } 20026483Skarels gotsomewhere = 1; 20118144Sralph if (id != anhp->id) { 20218144Sralph /* 20318144Sralph * response from old query, ignore it 20418144Sralph */ 20524734Sbloom #ifdef DEBUG 20618144Sralph if (_res.options & RES_DEBUG) { 20718144Sralph printf("old answer:\n"); 20818144Sralph p_query(answer); 20918144Sralph } 21025243Skjd #endif DEBUG 21126323Skarels goto wait; 21218144Sralph } 21318144Sralph if (!(_res.options & RES_IGNTC) && anhp->tc) { 21418144Sralph /* 21518144Sralph * get rest of answer 21618144Sralph */ 21724734Sbloom #ifdef DEBUG 21818144Sralph if (_res.options & RES_DEBUG) 21918144Sralph printf("truncated answer\n"); 22025243Skjd #endif DEBUG 22118144Sralph (void) close(s); 22218144Sralph s = -1; 22318144Sralph retry = _res.retry; 22418144Sralph v_circuit = 1; 22518144Sralph continue; 22618144Sralph } 22718144Sralph } 22824734Sbloom #ifdef DEBUG 22918144Sralph if (_res.options & RES_DEBUG) { 23018144Sralph printf("got answer:\n"); 23118144Sralph p_query(answer); 23218144Sralph } 23325243Skjd #endif DEBUG 23426322Sbloom /* 23526322Sbloom * We are going to assume that the first server is preferred 23626322Sbloom * over the rest (i.e. it is on the local machine) and only 23726322Sbloom * keep that one open. 23826322Sbloom */ 23926322Sbloom if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) { 24026322Sbloom return (resplen); 24126322Sbloom } else { 24226322Sbloom (void) close(s); 24326322Sbloom s = -1; 24426322Sbloom return (resplen); 24526322Sbloom } 24625243Skjd } 24718144Sralph } 24823873Skjd (void) close(s); 24926483Skarels if (v_circuit == 0 && gotsomewhere == 0) 25026483Skarels errno = ECONNREFUSED; 25126483Skarels else 25226483Skarels errno = ETIMEDOUT; 25318144Sralph return (-1); 25418144Sralph } 255