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 821388Sdist #ifndef lint 9*26323Skarels static char sccsid[] = "@(#)res_send.c 6.3 (Berkeley) 02/22/86"; 1021388Sdist #endif not lint 1121388Sdist 1218548Sralph /* 1318144Sralph * Send query to name server and wait for reply. 1418144Sralph */ 1518144Sralph 1618144Sralph #include <sys/types.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> 2324083Skjd #include <arpa/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; 3818144Sralph u_short id, len; 3918144Sralph char *cp; 4018144Sralph int dsmask; 4118144Sralph struct timeval timeout; 4218144Sralph HEADER *hp = (HEADER *) buf; 4318144Sralph HEADER *anhp = (HEADER *) answer; 4418144Sralph 4524734Sbloom #ifdef DEBUG 4618144Sralph if (_res.options & RES_DEBUG) { 4718531Sralph printf("res_send()\n"); 4818144Sralph p_query(buf); 4918144Sralph } 5025243Skjd #endif DEBUG 5118531Sralph if (!(_res.options & RES_INIT)) 5224734Sbloom if (res_init() == -1) { 5324734Sbloom return(-1); 5424734Sbloom } 5518144Sralph v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; 5618144Sralph id = hp->id; 5718144Sralph /* 5818144Sralph * Send request, RETRY times, or until successful 5918144Sralph */ 6018144Sralph for (retry = _res.retry; --retry >= 0; ) { 6125243Skjd for (ns = 0; ns < _res.nscount; ns++) { 6225243Skjd #ifdef DEBUG 6325243Skjd if (_res.options & RES_DEBUG) 6425243Skjd printf("Querying server (# %d) address = %s\n", ns+1, 6525243Skjd inet_ntoa(_res.nsaddr_list[ns].sin_addr.s_addr)); 6625243Skjd #endif DEBUG 6718144Sralph if (v_circuit) { 6818144Sralph /* 6918144Sralph * Use virtual circuit. 7018144Sralph */ 7126322Sbloom if (s < 0) { 7218144Sralph s = socket(AF_INET, SOCK_STREAM, 0); 7326322Sbloom if (connect(s, &(_res.nsaddr_list[ns]), 7426322Sbloom sizeof(struct sockaddr)) < 0) { 7524734Sbloom #ifdef DEBUG 7626322Sbloom if (_res.options & RES_DEBUG) 7726322Sbloom printf("connect failed %d\n",errno); 7825243Skjd #endif DEBUG 7926322Sbloom (void) close(s); 8026322Sbloom s = -1; 8126322Sbloom continue; 8226322Sbloom } 8318144Sralph } 8418144Sralph /* 8518144Sralph * Send length & message 8618144Sralph */ 8718144Sralph len = htons(buflen); 8818144Sralph if (write(s, &len, sizeof(len)) != sizeof(len) || 8925243Skjd write(s, buf, buflen) != buflen) { 9024734Sbloom #ifdef DEBUG 9118144Sralph if (_res.options & RES_DEBUG) 9218144Sralph printf("write failed %d\n", errno); 9325243Skjd #endif DEBUG 9418144Sralph (void) close(s); 9518144Sralph s = -1; 9618144Sralph continue; 9718144Sralph } 9818144Sralph /* 9918144Sralph * Receive length & response 10018144Sralph */ 10118144Sralph cp = answer; 10218144Sralph len = sizeof(short); 10318144Sralph while (len > 0 && (n = read(s, cp, len)) > 0) { 10418144Sralph cp += n; 10518144Sralph len -= n; 10618144Sralph } 10718144Sralph if (n <= 0) { 10824734Sbloom #ifdef DEBUG 10918144Sralph if (_res.options & RES_DEBUG) 11018144Sralph printf("read failed %d\n", errno); 11125243Skjd #endif DEBUG 11218144Sralph (void) close(s); 11318144Sralph s = -1; 11418144Sralph continue; 11518144Sralph } 11618144Sralph cp = answer; 11718144Sralph resplen = len = ntohs(*(short *)cp); 11818144Sralph while (len > 0 && (n = read(s, cp, len)) > 0) { 11918144Sralph cp += n; 12018144Sralph len -= n; 12118144Sralph } 12218144Sralph if (n <= 0) { 12324734Sbloom #ifdef DEBUG 12418144Sralph if (_res.options & RES_DEBUG) 12518144Sralph printf("read failed %d\n", errno); 12625243Skjd #endif DEBUG 12718144Sralph (void) close(s); 12818144Sralph s = -1; 12918144Sralph continue; 13018144Sralph } 13118144Sralph } else { 13218144Sralph /* 13318144Sralph * Use datagrams. 13418144Sralph */ 13518144Sralph if (s < 0) 13618144Sralph s = socket(AF_INET, SOCK_DGRAM, 0); 137*26323Skarels if (connect(s, &_res.nsaddr_list[ns], 138*26323Skarels sizeof(struct sockaddr)) < 0 || 139*26323Skarels send(s, buf, buflen, 0) != buflen) { 14024734Sbloom #ifdef DEBUG 14125243Skjd if (_res.options & RES_DEBUG) 142*26323Skarels printf("connect/send errno = %d\n", 143*26323Skarels errno); 14425243Skjd #endif DEBUG 14518144Sralph } 14618144Sralph /* 14718144Sralph * Wait for reply 14818144Sralph */ 14925243Skjd timeout.tv_sec = 15025243Skjd ((_res.retrans * _res.retry) / _res.nscount); 15118144Sralph timeout.tv_usec = 0; 152*26323Skarels wait: 15318144Sralph dsmask = 1 << s; 15418144Sralph n = select(s+1, &dsmask, 0, 0, &timeout); 15518144Sralph if (n < 0) { 15624734Sbloom #ifdef DEBUG 15718144Sralph if (_res.options & RES_DEBUG) 15818144Sralph printf("select errno = %d\n", errno); 15925243Skjd #endif DEBUG 16018144Sralph continue; 16118144Sralph } 16218144Sralph if (n == 0) { 16318144Sralph /* 16418144Sralph * timeout 16518144Sralph */ 16624734Sbloom #ifdef DEBUG 16718144Sralph if (_res.options & RES_DEBUG) 16818144Sralph printf("timeout\n"); 16925243Skjd #endif DEBUG 17018144Sralph continue; 17118144Sralph } 17225332Skjd if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 17324734Sbloom #ifdef DEBUG 17418144Sralph if (_res.options & RES_DEBUG) 17518144Sralph printf("recvfrom, errno=%d\n", errno); 17625243Skjd #endif DEBUG 17718144Sralph continue; 17818144Sralph } 17918144Sralph if (id != anhp->id) { 18018144Sralph /* 18118144Sralph * response from old query, ignore it 18218144Sralph */ 18324734Sbloom #ifdef DEBUG 18418144Sralph if (_res.options & RES_DEBUG) { 18518144Sralph printf("old answer:\n"); 18618144Sralph p_query(answer); 18718144Sralph } 18825243Skjd #endif DEBUG 189*26323Skarels goto wait; 19018144Sralph } 19118144Sralph if (!(_res.options & RES_IGNTC) && anhp->tc) { 19218144Sralph /* 19318144Sralph * get rest of answer 19418144Sralph */ 19524734Sbloom #ifdef DEBUG 19618144Sralph if (_res.options & RES_DEBUG) 19718144Sralph printf("truncated answer\n"); 19825243Skjd #endif DEBUG 19918144Sralph (void) close(s); 20018144Sralph s = -1; 20118144Sralph retry = _res.retry; 20218144Sralph v_circuit = 1; 20318144Sralph continue; 20418144Sralph } 20518144Sralph } 20624734Sbloom #ifdef DEBUG 20718144Sralph if (_res.options & RES_DEBUG) { 20818144Sralph printf("got answer:\n"); 20918144Sralph p_query(answer); 21018144Sralph } 21125243Skjd #endif DEBUG 21226322Sbloom /* 21326322Sbloom * We are going to assume that the first server is preferred 21426322Sbloom * over the rest (i.e. it is on the local machine) and only 21526322Sbloom * keep that one open. 21626322Sbloom */ 21726322Sbloom if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) { 21826322Sbloom return (resplen); 21926322Sbloom } else { 22026322Sbloom (void) close(s); 22126322Sbloom s = -1; 22226322Sbloom return (resplen); 22326322Sbloom } 22425243Skjd } 22518144Sralph } 22623873Skjd (void) close(s); 22724032Skjd errno = ETIMEDOUT; 22818144Sralph return (-1); 22918144Sralph } 230