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*27664Sbloom static char sccsid[] = "@(#)res_send.c 6.12 (Berkeley) 04/30/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> 19*27664Sbloom #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; 4318144Sralph int dsmask; 4418144Sralph struct timeval timeout; 4518144Sralph HEADER *hp = (HEADER *) buf; 4618144Sralph HEADER *anhp = (HEADER *) answer; 47*27664Sbloom struct iovec iov[2]; 4818144Sralph 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 */ 6427040Skjd for (retry = _res.retry; retry > 0; retry--) { 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, 6927031Skjd 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) 8027031Skjd perror("socket failed"); 8126483Skarels #endif DEBUG 8226483Skarels continue; 8326483Skarels } 8427031Skjd if (connect(s, &(_res.nsaddr_list[ns]), 8526322Sbloom sizeof(struct sockaddr)) < 0) { 8624734Sbloom #ifdef DEBUG 8726322Sbloom if (_res.options & RES_DEBUG) 8827031Skjd 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*27664Sbloom iov[0].iov_base = (caddr_t)&len; 100*27664Sbloom iov[0].iov_len = sizeof(len); 101*27664Sbloom iov[1].iov_base = buf; 102*27664Sbloom iov[1].iov_len = buflen; 103*27664Sbloom if (writev(s, iov, 2) != sizeof(len) + buflen) { 10424734Sbloom #ifdef DEBUG 10518144Sralph if (_res.options & RES_DEBUG) 10627031Skjd perror("write failed"); 10725243Skjd #endif DEBUG 10818144Sralph (void) close(s); 10918144Sralph s = -1; 11018144Sralph continue; 11118144Sralph } 11218144Sralph /* 11318144Sralph * Receive length & response 11418144Sralph */ 11518144Sralph cp = answer; 11618144Sralph len = sizeof(short); 117*27664Sbloom while (len != 0 && 11827031Skjd (n = read(s, (char *)cp, (int)len)) > 0) { 11918144Sralph cp += n; 12018144Sralph len -= n; 12118144Sralph } 12218144Sralph if (n <= 0) { 12324734Sbloom #ifdef DEBUG 12418144Sralph if (_res.options & RES_DEBUG) 12527031Skjd perror("read failed"); 12625243Skjd #endif DEBUG 12718144Sralph (void) close(s); 12818144Sralph s = -1; 12918144Sralph continue; 13018144Sralph } 13118144Sralph cp = answer; 13227025Sbloom resplen = len = ntohs(*(u_short *)cp); 133*27664Sbloom while (len != 0 && 13427031Skjd (n = read(s, (char *)cp, (int)len)) > 0) { 13518144Sralph cp += n; 13618144Sralph len -= n; 13718144Sralph } 13818144Sralph if (n <= 0) { 13924734Sbloom #ifdef DEBUG 14018144Sralph if (_res.options & RES_DEBUG) 14127031Skjd perror("read failed"); 14225243Skjd #endif DEBUG 14318144Sralph (void) close(s); 14418144Sralph s = -1; 14518144Sralph continue; 14618144Sralph } 14718144Sralph } else { 14818144Sralph /* 14918144Sralph * Use datagrams. 15018144Sralph */ 15118144Sralph if (s < 0) 15218144Sralph s = socket(AF_INET, SOCK_DGRAM, 0); 15326483Skarels #if BSD >= 43 15426323Skarels if (connect(s, &_res.nsaddr_list[ns], 15526323Skarels sizeof(struct sockaddr)) < 0 || 15626323Skarels send(s, buf, buflen, 0) != buflen) { 15724734Sbloom #ifdef DEBUG 15827031Skjd if (_res.options & RES_DEBUG) 15927031Skjd perror("connect"); 16025243Skjd #endif DEBUG 16126483Skarels continue; 16218144Sralph } 16326483Skarels #else BSD 16426483Skarels if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns], 16526483Skarels sizeof(struct sockaddr)) != buflen) { 16626483Skarels #ifdef DEBUG 16727031Skjd if (_res.options & RES_DEBUG) 16827031Skjd perror("sendto"); 16926483Skarels #endif DEBUG 17026483Skarels continue; 17126483Skarels } 17226483Skarels #endif BSD 17318144Sralph /* 17427031Skjd * Wait for reply 17518144Sralph */ 17627031Skjd timeout.tv_sec = (_res.retrans << (_res.retry - retry)) 17727031Skjd / _res.nscount; 17827031Skjd if (timeout.tv_sec <= 0) 17927031Skjd timeout.tv_sec = 1; 18018144Sralph timeout.tv_usec = 0; 18126323Skarels wait: 18218144Sralph dsmask = 1 << s; 183*27664Sbloom n = select(s+1, &dsmask, (fd_set *)NULL, 184*27664Sbloom (fd_set *)NULL, &timeout); 18518144Sralph if (n < 0) { 18624734Sbloom #ifdef DEBUG 18718144Sralph if (_res.options & RES_DEBUG) 18827031Skjd perror("select"); 18925243Skjd #endif DEBUG 19018144Sralph continue; 19118144Sralph } 19218144Sralph if (n == 0) { 19318144Sralph /* 19418144Sralph * timeout 19518144Sralph */ 19624734Sbloom #ifdef DEBUG 19718144Sralph if (_res.options & RES_DEBUG) 19818144Sralph printf("timeout\n"); 19925243Skjd #endif DEBUG 20026483Skarels gotsomewhere = 1; 20118144Sralph continue; 20218144Sralph } 20325332Skjd if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 20424734Sbloom #ifdef DEBUG 20518144Sralph if (_res.options & RES_DEBUG) 20627031Skjd perror("recvfrom"); 20725243Skjd #endif DEBUG 20818144Sralph continue; 20918144Sralph } 21026483Skarels gotsomewhere = 1; 21118144Sralph if (id != anhp->id) { 21218144Sralph /* 21318144Sralph * response from old query, ignore it 21418144Sralph */ 21524734Sbloom #ifdef DEBUG 21618144Sralph if (_res.options & RES_DEBUG) { 21718144Sralph printf("old answer:\n"); 21818144Sralph p_query(answer); 21918144Sralph } 22025243Skjd #endif DEBUG 22126323Skarels goto wait; 22218144Sralph } 22318144Sralph if (!(_res.options & RES_IGNTC) && anhp->tc) { 22418144Sralph /* 22518144Sralph * get rest of answer 22618144Sralph */ 22724734Sbloom #ifdef DEBUG 22818144Sralph if (_res.options & RES_DEBUG) 22918144Sralph printf("truncated answer\n"); 23025243Skjd #endif DEBUG 23118144Sralph (void) close(s); 23218144Sralph s = -1; 23327040Skjd /* 23427040Skjd * retry decremented on continue 23527040Skjd * to desired starting value 23627040Skjd */ 23727040Skjd retry = _res.retry + 1; 23818144Sralph v_circuit = 1; 23918144Sralph continue; 24018144Sralph } 24118144Sralph } 24224734Sbloom #ifdef DEBUG 24318144Sralph if (_res.options & RES_DEBUG) { 24418144Sralph printf("got answer:\n"); 24518144Sralph p_query(answer); 24618144Sralph } 24725243Skjd #endif DEBUG 24826322Sbloom /* 24926322Sbloom * We are going to assume that the first server is preferred 25026322Sbloom * over the rest (i.e. it is on the local machine) and only 25126322Sbloom * keep that one open. 25226322Sbloom */ 25326322Sbloom if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) { 25426322Sbloom return (resplen); 25526322Sbloom } else { 25626322Sbloom (void) close(s); 25726322Sbloom s = -1; 25826322Sbloom return (resplen); 25926322Sbloom } 26025243Skjd } 26118144Sralph } 26223873Skjd (void) close(s); 26326897Sbloom s = -1; 26426483Skarels if (v_circuit == 0 && gotsomewhere == 0) 26526483Skarels errno = ECONNREFUSED; 26626483Skarels else 26726483Skarels errno = ETIMEDOUT; 26818144Sralph return (-1); 26918144Sralph } 27027025Sbloom 27127025Sbloom /* 27227025Sbloom * This routine is for closing the socket if a virtual circuit is used and 27327025Sbloom * the program wants to close it. This provides support for endhostent() 27427025Sbloom * which expects to close the socket. 27527025Sbloom * 27627025Sbloom * This routine is not expected to be user visible. 27727025Sbloom */ 27827025Sbloom _res_close() 27927025Sbloom { 28027025Sbloom if (s != -1) { 28127025Sbloom (void) close(s); 28227025Sbloom s = -1; 28327025Sbloom } 28427025Sbloom } 285