* Copyright (c) 1985, 1989 Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
static char sccsid
[] = "@(#)send.c 5.18 (Berkeley) 3/2/91";
*******************************************************************************
* Routine to send request packets to a name server.
* Based on "@(#)res_send.c 6.25 (Berkeley) 6/1/90".
*******************************************************************************
* Send query to name server and wait for reply.
#include <arpa/nameser.h>
static int s
= -1; /* socket used for communications */
#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
#define SR 1 /* SendRequest style */
unsigned short nsport
= NAMESERVER_PORT
;
*******************************************************************************
* Sends a request packet to a name server whose address
* is specified by the first argument and returns with
* SUCCESS - the request was sent and an answer
* TIME_OUT - the virtual circuit connection timed-out
* or a reply to a datagram wasn't received.
*******************************************************************************
SendRequest(nsAddrPtr
, buf
, buflen
, answer
, anslen
, trueLenPtr
)
struct in_addr
*nsAddrPtr
;
int try, v_circuit
, resplen
, ns
;
int gotsomewhere
= 0, connected
= 0;
HEADER
*hp
= (HEADER
*) buf
;
HEADER
*anhp
= (HEADER
*) answer
;
if (_res
.options
& RES_DEBUG2
) {
printf("------------\nSendRequest(), len %d\n", buflen
);
Print_query(buf
, buf
+buflen
, 1);
sin
.sin_family
= AF_INET
;
sin
.sin_port
= htons(nsport
);
sin
.sin_addr
= *nsAddrPtr
;
if (_res
.options
& RES_DEBUG
) {
if (!(_res
.options
& RES_INIT
))
v_circuit
= (_res
.options
& RES_USEVC
) || buflen
> PACKETSZ
;
* Send request, RETRY times, or until successful
for (try = 0; try < _res
.retry
; try++) {
for (ns
= 0; ns
< _res
.nscount
; ns
++) {
if (_res
.options
& RES_DEBUG
)
printf("Querying server (# %d) address = %s\n", ns
+1,
inet_ntoa(_res
.nsaddr_list
[ns
].sin_addr
));
* at most one attempt per server.
s
= socket(AF_INET
, SOCK_STREAM
, 0);
if (_res
.options
& RES_DEBUG
)
perror("socket (vc) failed");
if (connect(s
, (struct sockaddr
*)&sin
,
(struct sockaddr
*)&(_res
.nsaddr_list
[ns
]),
sizeof(struct sockaddr
)) < 0) {
if (_res
.options
& RES_DEBUG
)
perror("connect failed");
len
= htons((u_short
)buflen
);
iov
[0].iov_base
= (caddr_t
)&len
;
iov
[0].iov_len
= sizeof(len
);
if (writev(s
, iov
, 2) != sizeof(len
) + buflen
) {
if (_res
.options
& RES_DEBUG
)
* Receive length & response
(n
= read(s
, (char *)cp
, (int)len
)) > 0) {
if (_res
.options
& RES_DEBUG
)
* A long running process might get its TCP
* connection reset if the remote server was
* restarted. Requery the server instead of
* trying a new one. When there is only one
* server, this means that a query might work
* instead of failing. We only allow one reset
* per query to prevent looping.
if (terrno
== ECONNRESET
&& !connreset
) {
if ((resplen
= ntohs(*(u_short
*)cp
)) > anslen
) {
if (_res
.options
& RES_DEBUG
)
fprintf(stderr
, "response truncated\n");
(n
= read(s
, (char *)cp
, (int)len
)) > 0) {
if (_res
.options
& RES_DEBUG
)
* so connection stays in synch.
n
= (len
> sizeof(junk
) ?
if ((n
= read(s
, junk
, n
)) > 0)
s
= socket(AF_INET
, SOCK_DGRAM
, 0);
if (_res
.options
& RES_DEBUG
)
perror("socket (dg) failed");
* Special case the send code below
* since we have just 1 server.
if (connect(s
, (struct sockaddr
*)&sin
,
sizeof(struct sockaddr
)) < 0) {
if (_res
.options
& RES_DEBUG
)
if (send(s
, buf
, buflen
, 0) != buflen
) {
if (_res
.options
& RES_DEBUG
)
if (sendto(s
, buf
, buflen
, 0, &sin
,
sizeof(struct sockaddr
)) != buflen
) {
if (_res
.options
& RES_DEBUG
)
* I'm tired of answering this question, so:
* On a 4.3BSD+ machine (client and server,
* actually), sending to a nameserver datagram
* port with no nameserver will cause an
* ICMP port unreachable message to be returned.
* If our datagram socket is "connected" to the
* server, we get an ECONNREFUSED error on the next
* socket operation, and select returns if the
* error message is received. We can thus detect
* the absence of a nameserver without timing out.
* If we have sent queries to at least two servers,
* however, we don't want to remain connected,
* as we wish to receive answers from the first
if (_res
.nscount
== 1 || (try == 0 && ns
== 0)) {
* Don't use connect if we might
* still receive a response
if (connect(s
, &_res
.nsaddr_list
[ns
],
sizeof(struct sockaddr
)) < 0) {
if (_res
.options
& RES_DEBUG
)
if (send(s
, buf
, buflen
, 0) != buflen
) {
if (_res
.options
& RES_DEBUG
)
* Disconnect if we want to listen
* for responses from more than one server.
(void) connect(s
, &no_addr
,
if (sendto(s
, buf
, buflen
, 0,
sizeof(struct sockaddr
)) != buflen
) {
if (_res
.options
& RES_DEBUG
)
timeout
.tv_sec
= (_res
.retrans
<< try);
timeout
.tv_sec
/= _res
.nscount
;
n
= select(s
+1, &dsmask
, (fd_set
*)NULL
,
(fd_set
*)NULL
, &timeout
);
if (_res
.options
& RES_DEBUG
)
if (_res
.options
& RES_DEBUG
)
printf("timeout (%d secs)\n",
if ((resplen
= recv(s
, answer
, anslen
, 0)) <= 0) {
if (_res
.options
& RES_DEBUG
)
* response from old query, ignore it
if (_res
.options
& RES_DEBUG2
) {
printf("------------\nOld answer:\n");
Print_query(answer
, answer
+resplen
, 1);
if (_res
.options
& RES_DEBUG
) {
if (!(_res
.options
& RES_IGNTC
) && anhp
->tc
) {
* use TCP with same server.
if (_res
.options
& RES_DEBUG
)
printf("truncated answer\n");
if (_res
.options
& RES_DEBUG
) {
if (_res
.options
& RES_DEBUG2
)
printf("------------\nGot answer (%d bytes):\n",
printf("------------\nGot answer:\n");
Print_query(answer
, answer
+resplen
, 1);
if (_res
.options
& RES_DEBUG
) {
* If using virtual circuits, we assume that the first server
* is preferred * over the rest (i.e. it is on the local
* machine) and only keep that one open.
* If we have temporarily opened a virtual circuit,
* or if we haven't been asked to keep a socket open,
((_res
.options
& RES_USEVC
) == 0 || ns
!= 0)) ||
(_res
.options
& RES_STAYOPEN
) == 0) {
return NO_RESPONSE
; /* no nameservers found */
return TIME_OUT
; /* no answer obtained */
if (errno
== ECONNREFUSED
)
errno
= ECONNREFUSED
; /* no nameservers found */
errno
= ETIMEDOUT
; /* no answer obtained */
* This routine is for closing the socket if a virtual circuit is used and
* the program wants to close it.
* Called from the interrupt handler.