2 * Copyright (c) 1985, 1989 Regents of the University of California.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #if defined(LIBC_SCCS) && !defined(lint)
35 static char sccsid
[] = "@(#)res_send.c 6.27 (Berkeley) 2/24/91";
36 #endif /* LIBC_SCCS and not lint */
39 * Send query to name server and wait for reply.
43 #include <sys/param.h>
45 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include <arpa/nameser.h>
57 #include <sys/types.h>
58 #include <sys/ioctl.h>
71 #include <net/netlib.h>
72 #include <net/gen/in.h>
73 #include <net/gen/inet.h>
74 #include <net/gen/netdb.h>
75 #include <net/gen/nameser.h>
76 #include <net/gen/resolv.h>
77 #include <net/gen/tcp.h>
78 #include <net/gen/tcp_io.h>
79 #include <net/gen/udp.h>
80 #include <net/gen/udp_hdr.h>
81 #include <net/gen/udp_io.h>
83 static int tcp_connect
_ARGS(( ipaddr_t host
, Tcpport_t port
, int *terrno
));
84 static int tcpip_writeall
_ARGS(( int fd
, const char *buf
, size_t siz
));
85 static int udp_connect
_ARGS(( void ));
86 static int udp_sendto
_ARGS(( int fd
, const char *buf
, unsigned buflen
,
87 ipaddr_t addr
, Udpport_t port
));
88 static int udp_receive
_ARGS(( int fd
, char *buf
, unsigned buflen
,
90 static void alarm_handler
_ARGS(( int sig
));
94 static int s
= -1; /* socket used for communications */
96 static struct sockaddr no_addr
;
100 #define FD_SETSIZE 32
101 #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
102 #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
103 #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
104 #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
108 res_send(buf
, buflen
, answer
, anslen
)
115 int try, v_circuit
, resplen
, ns
;
116 int gotsomewhere
= 0, connected
= 0;
126 struct timeval timeout
;
127 HEADER
*hp
= (HEADER
*) buf
;
128 HEADER
*anhp
= (HEADER
*) answer
;
132 dns_hdr_t
*hp
= (dns_hdr_t
*) buf
;
133 dns_hdr_t
*anhp
= (dns_hdr_t
*) answer
;
135 int terrno
= ETIMEDOUT
;
139 if (_res
.options
& RES_DEBUG
) {
140 printf("res_send()\n");
144 if (!(_res
.options
& RES_INIT
))
145 if (res_init() == -1) {
149 v_circuit
= (_res
.options
& RES_USEVC
) || buflen
> PACKETSZ
;
156 * Send request, RETRY times, or until successful
158 for (try = 0; try < _res
.retry
; try++) {
159 for (ns
= 0; ns
< _res
.nscount
; ns
++) {
162 if (_res
.options
& RES_DEBUG
)
163 printf("Querying server (# %d) address = %s\n", ns
+1,
164 inet_ntoa(_res
.nsaddr_list
[ns
].sin_addr
));
166 if (_res
.options
& RES_DEBUG
)
167 printf("Querying server (# %d) address = %s\n", ns
+1,
168 inet_ntoa(_res
.nsaddr_list
[ns
]));
177 * Use virtual circuit;
178 * at most one attempt per server.
182 s
= socket(AF_INET
, SOCK_STREAM
, 0);
186 if (_res
.options
& RES_DEBUG
)
187 perror("socket (vc) failed");
192 (struct sockaddr
*)&(_res
.nsaddr_list
[ns
]),
193 sizeof(struct sockaddr
)) < 0) {
196 if (_res
.options
& RES_DEBUG
)
197 perror("connect failed");
205 * Send length & message
207 len
= htons((u_short
)buflen
);
208 iov
[0].iov_base
= (caddr_t
)&len
;
209 iov
[0].iov_len
= sizeof(len
);
210 iov
[1].iov_base
= (char *)buf
;
211 iov
[1].iov_len
= buflen
;
212 if (writev(s
, iov
, 2) != sizeof(len
) + buflen
) {
215 if (_res
.options
& RES_DEBUG
)
216 perror("write failed");
223 * Receive length & response
228 (n
= read(s
, (char *)cp
, (int)len
)) > 0) {
235 if (_res
.options
& RES_DEBUG
)
236 perror("read failed");
241 * A long running process might get its TCP
242 * connection reset if the remote server was
243 * restarted. Requery the server instead of
244 * trying a new one. When there is only one
245 * server, this means that a query might work
246 * instead of failing. We only allow one reset
247 * per query to prevent looping.
249 if (terrno
== ECONNRESET
&& !connreset
) {
256 if ((resplen
= ntohs(*(u_short
*)cp
)) > anslen
) {
258 if (_res
.options
& RES_DEBUG
)
259 fprintf(stderr
, "response truncated\n");
266 (n
= read(s
, (char *)cp
, (int)len
)) > 0) {
273 if (_res
.options
& RES_DEBUG
)
274 perror("read failed");
282 * Flush rest of answer
283 * so connection stays in synch.
286 len
= resplen
- anslen
;
288 n
= (len
> sizeof(junk
) ?
290 if ((n
= read(s
, junk
, n
)) > 0)
301 * Use virtual circuit;
302 * at most one attempt per server.
307 s
= tcp_connect(_res
.nsaddr_list
[ns
],
308 _res
.nsport_list
[ns
], &terrno
);
313 * Send length & message
315 len
= htons((u_short
)buflen
);
316 nbytes
= tcpip_writeall(s
, (char *)&len
,
318 if (nbytes
!= sizeof(len
))
322 if (_res
.options
& RES_DEBUG
)
323 fprintf(stderr
, "write failed: %s\n",
330 nbytes
= tcpip_writeall(s
, buf
, buflen
);
331 if (nbytes
!= buflen
)
335 if (_res
.options
& RES_DEBUG
)
336 fprintf(stderr
, "write failed: %s\n",
344 * Receive length & response
350 n
= read(s
, (char *)cp
, (int)len
);
360 if (_res
.options
& RES_DEBUG
)
361 fprintf(stderr
, "read failed: %s\n",
367 * A long running process might get its TCP
368 * connection reset if the remote server was
369 * restarted. Requery the server instead of
370 * trying a new one. When there is only one
371 * server, this means that a query might work
372 * instead of failing. We only allow one reset
373 * per query to prevent looping.
375 if (terrno
== ECONNRESET
&& !connreset
) {
382 if ((resplen
= ntohs(*(u_short
*)cp
)) > anslen
) {
384 if (_res
.options
& RES_DEBUG
)
385 fprintf(stderr
, "response truncated\n");
393 n
= read(s
, (char *)cp
, (int)len
);
403 if (_res
.options
& RES_DEBUG
)
404 fprintf(stderr
, "read failed: %s\n",
413 * Flush rest of answer
414 * so connection stays in synch.
416 anhp
->dh_flag1
|= DHF_TC
;
417 len
= resplen
- anslen
;
419 n
= (len
> sizeof(junk
) ?
421 n
= read(s
, junk
, n
);
438 s
= socket(AF_INET
, SOCK_DGRAM
, 0);
442 if (_res
.options
& RES_DEBUG
)
443 perror("socket (dg) failed");
450 * I'm tired of answering this question, so:
451 * On a 4.3BSD+ machine (client and server,
452 * actually), sending to a nameserver datagram
453 * port with no nameserver will cause an
454 * ICMP port unreachable message to be returned.
455 * If our datagram socket is "connected" to the
456 * server, we get an ECONNREFUSED error on the next
457 * socket operation, and select returns if the
458 * error message is received. We can thus detect
459 * the absence of a nameserver without timing out.
460 * If we have sent queries to at least two servers,
461 * however, we don't want to remain connected,
462 * as we wish to receive answers from the first
465 if (_res
.nscount
== 1 || (try == 0 && ns
== 0)) {
467 * Don't use connect if we might
468 * still receive a response
469 * from another server.
471 if (connected
== 0) {
472 if (connect(s
, (struct sockaddr
*)&_res
.nsaddr_list
[ns
],
473 sizeof(struct sockaddr
)) < 0) {
475 if (_res
.options
& RES_DEBUG
)
482 if (send(s
, buf
, buflen
, 0) != buflen
) {
484 if (_res
.options
& RES_DEBUG
)
491 * Disconnect if we want to listen
492 * for responses from more than one server.
495 (void) connect(s
, &no_addr
,
500 if (sendto(s
, buf
, buflen
, 0,
501 (struct sockaddr
*)&_res
.nsaddr_list
[ns
],
502 sizeof(struct sockaddr
)) != buflen
) {
504 if (_res
.options
& RES_DEBUG
)
516 timeout
.tv_sec
= (_res
.retrans
<< try);
518 timeout
.tv_sec
/= _res
.nscount
;
519 if (timeout
.tv_sec
<= 0)
525 n
= select(s
+1, &dsmask
, (fd_set
*)NULL
,
526 (fd_set
*)NULL
, &timeout
);
529 if (_res
.options
& RES_DEBUG
)
539 if (_res
.options
& RES_DEBUG
)
547 if ((resplen
= recv(s
, answer
, anslen
, 0)) <= 0) {
549 if (_res
.options
& RES_DEBUG
)
555 if (id
!= anhp
->id
) {
557 * response from old query, ignore it
560 if (_res
.options
& RES_DEBUG
) {
561 printf("old answer:\n");
567 if (!(_res
.options
& RES_IGNTC
) && anhp
->tc
) {
569 * get rest of answer;
570 * use TCP with same server.
573 if (_res
.options
& RES_DEBUG
)
574 printf("truncated answer\n");
590 if (_res
.options
& RES_DEBUG
)
591 perror("udp_connect failed");
596 if (udp_sendto(s
, buf
, buflen
, _res
.nsaddr_list
[ns
],
597 _res
.nsport_list
[ns
]) != buflen
) {
599 if (_res
.options
& RES_DEBUG
)
608 timeout
= (_res
.retrans
<< try);
610 timeout
/= _res
.nscount
;
614 if ((resplen
= udp_receive(s
, answer
, anslen
, timeout
))
623 if (_res
.options
& RES_DEBUG
)
631 if (_res
.options
& RES_DEBUG
)
632 perror("udp_receive");
638 if (id
!= anhp
->dh_id
) {
640 * response from old query, ignore it
643 if (_res
.options
& RES_DEBUG
) {
644 printf("old answer:\n");
650 if (!(_res
.options
& RES_IGNTC
) &&
651 (anhp
->dh_flag1
& DHF_TC
)) {
653 * get rest of answer;
654 * use TCP with same server.
657 if (_res
.options
& RES_DEBUG
)
658 printf("truncated answer\n");
668 if (_res
.options
& RES_DEBUG
) {
669 printf("got answer:\n");
674 * If using virtual circuits, we assume that the first server
675 * is preferred * over the rest (i.e. it is on the local
676 * machine) and only keep that one open.
677 * If we have temporarily opened a virtual circuit,
678 * or if we haven't been asked to keep a socket open,
682 ((_res
.options
& RES_USEVC
) == 0 || ns
!= 0)) ||
683 (_res
.options
& RES_STAYOPEN
) == 0) {
695 if (gotsomewhere
== 0)
696 errno
= ECONNREFUSED
; /* no nameservers found */
698 errno
= ETIMEDOUT
; /* no answer obtained */
705 * This routine is for closing the socket if a virtual circuit is used and
706 * the program wants to close it. This provides support for endhostent()
707 * which expects to close the socket.
709 * This routine is not expected to be user visible.
721 static int tcp_connect(host
, port
, terrno
)
729 nwio_tcpconf_t tcpconf
;
732 dev_name
= getenv("TCP_DEVICE");
734 dev_name
= TCP_DEVICE
;
735 fd
= open(dev_name
, O_RDWR
);
741 tcpconf
.nwtc_flags
= NWTC_EXCL
| NWTC_LP_SEL
| NWTC_SET_RA
| NWTC_SET_RP
;
742 tcpconf
.nwtc_remaddr
= host
;
743 tcpconf
.nwtc_remport
= port
;
744 error
= ioctl(fd
, NWIOSTCPCONF
, &tcpconf
);
751 clopt
.nwtcl_flags
= 0;
752 error
= ioctl(fd
, NWIOTCPCONN
, &clopt
);
763 static int tcpip_writeall(fd
, buf
, siz
)
775 nbytes
= write(fd
, buf
, siz
);
778 assert(siz
>= nbytes
);
786 static int udp_connect()
788 nwio_udpopt_t udpopt
;
792 dev_name
= getenv("UDP_DEVICE");
794 dev_name
= UDP_DEVICE
;
795 fd
= open(dev_name
, O_RDWR
);
799 udpopt
.nwuo_flags
= NWUO_COPY
| NWUO_LP_SEL
| NWUO_EN_LOC
|
800 NWUO_EN_BROAD
| NWUO_RP_ANY
| NWUO_RA_ANY
| NWUO_RWDATALL
|
802 r
= ioctl(fd
, NWIOSUDPOPT
, &udpopt
);
813 static int udp_sendto(fd
, buf
, buflen
, addr
, port
)
821 udp_io_hdr_t
*udp_io_hdr
;
824 newbuf
= malloc(sizeof(*udp_io_hdr
) + buflen
);
830 udp_io_hdr
= (udp_io_hdr_t
*)newbuf
;
831 udp_io_hdr
->uih_dst_addr
= addr
;
832 udp_io_hdr
->uih_dst_port
= port
;
833 udp_io_hdr
->uih_ip_opt_len
= 0;
834 udp_io_hdr
->uih_data_len
= buflen
;
836 memcpy(newbuf
+ sizeof(*udp_io_hdr
), buf
, buflen
);
837 r
= write(fd
, newbuf
, sizeof(*udp_io_hdr
) + buflen
);
840 if (r
>= sizeof(*udp_io_hdr
))
841 r
-= sizeof(*udp_io_hdr
);
846 static void alarm_handler(sig
)
849 signal(SIGALRM
, alarm_handler
);
853 static int udp_receive(fd
, buf
, buflen
, timeout
)
860 udp_io_hdr_t
*udp_io_hdr
;
862 void (*u_handler
) _ARGS(( int sig
));
865 newbuf
= malloc(sizeof(*udp_io_hdr
) + buflen
);
872 u_handler
= signal(SIGALRM
, alarm_handler
);
873 u_timeout
= alarm(timeout
);
875 r
= read(fd
, newbuf
, sizeof(*udp_io_hdr
) + buflen
);
878 if (r
< 0 || r
<= sizeof(*udp_io_hdr
))
886 signal(SIGALRM
, u_handler
);
893 memcpy(buf
, newbuf
+ sizeof(*udp_io_hdr
), r
- sizeof(*udp_io_hdr
));
897 signal(SIGALRM
, u_handler
);
900 return r
-sizeof(*udp_io_hdr
);