xref: /csrg-svn/lib/libc/net/res_send.c (revision 30394)
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*30394Skjd static char sccsid[] = "@(#)res_send.c	6.16 (Berkeley) 01/15/87";
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>
1927664Sbloom #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 */
2930100Skjd 
3027025Sbloom 
3130100Skjd #ifndef FD_SET
3230100Skjd #define	NFDBITS		32
3330100Skjd #define	FD_SETSIZE	32
3430100Skjd #define	FD_SET(n, p)	((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
3530100Skjd #define	FD_CLR(n, p)	((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
3630100Skjd #define	FD_ISSET(n, p)	((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
3730100Skjd #define FD_ZERO(p)	bzero((char *)(p), sizeof(*(p)))
3830100Skjd #endif
3930100Skjd 
4026322Sbloom #define KEEPOPEN (RES_USEVC|RES_STAYOPEN)
4126322Sbloom 
4218531Sralph res_send(buf, buflen, answer, anslen)
4318144Sralph 	char *buf;
4418144Sralph 	int buflen;
4518144Sralph 	char *answer;
4618144Sralph 	int anslen;
4718144Sralph {
4818144Sralph 	register int n;
4926322Sbloom 	int retry, v_circuit, resplen, ns;
5026483Skarels 	int gotsomewhere = 0;
5118144Sralph 	u_short id, len;
5218144Sralph 	char *cp;
5327796Skjd 	fd_set dsmask;
5418144Sralph 	struct timeval timeout;
5518144Sralph 	HEADER *hp = (HEADER *) buf;
5618144Sralph 	HEADER *anhp = (HEADER *) answer;
5727664Sbloom 	struct iovec iov[2];
5829434Sbloom 	int terrno = ETIMEDOUT;
5918144Sralph 
6024734Sbloom #ifdef DEBUG
6118144Sralph 	if (_res.options & RES_DEBUG) {
6218531Sralph 		printf("res_send()\n");
6318144Sralph 		p_query(buf);
6418144Sralph 	}
6525243Skjd #endif DEBUG
6618531Sralph 	if (!(_res.options & RES_INIT))
6724734Sbloom 		if (res_init() == -1) {
6824734Sbloom 			return(-1);
6924734Sbloom 		}
7018144Sralph 	v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
7118144Sralph 	id = hp->id;
7218144Sralph 	/*
7318144Sralph 	 * Send request, RETRY times, or until successful
7418144Sralph 	 */
7527040Skjd 	for (retry = _res.retry; retry > 0; retry--) {
7625243Skjd 	   for (ns = 0; ns < _res.nscount; ns++) {
7725243Skjd #ifdef DEBUG
7825243Skjd 		if (_res.options & RES_DEBUG)
7925243Skjd 			printf("Querying server (# %d) address = %s\n", ns+1,
8027031Skjd 			      inet_ntoa(_res.nsaddr_list[ns].sin_addr.s_addr));
8125243Skjd #endif DEBUG
8218144Sralph 		if (v_circuit) {
8318144Sralph 			/*
8418144Sralph 			 * Use virtual circuit.
8518144Sralph 			 */
8626322Sbloom 			if (s < 0) {
8718144Sralph 				s = socket(AF_INET, SOCK_STREAM, 0);
8826483Skarels 				if (s < 0) {
8929434Sbloom 					terrno = errno;
9026483Skarels #ifdef DEBUG
9126483Skarels 					if (_res.options & RES_DEBUG)
9227031Skjd 					    perror("socket failed");
9326483Skarels #endif DEBUG
9426483Skarels 					continue;
9526483Skarels 				}
9627031Skjd 				if (connect(s, &(_res.nsaddr_list[ns]),
9726322Sbloom 				   sizeof(struct sockaddr)) < 0) {
9829434Sbloom 					terrno = errno;
9924734Sbloom #ifdef DEBUG
10026322Sbloom 					if (_res.options & RES_DEBUG)
10127031Skjd 					    perror("connect failed");
10225243Skjd #endif DEBUG
10326322Sbloom 					(void) close(s);
10426322Sbloom 					s = -1;
10526322Sbloom 					continue;
10626322Sbloom 				}
10718144Sralph 			}
10818144Sralph 			/*
10918144Sralph 			 * Send length & message
11018144Sralph 			 */
11127025Sbloom 			len = htons((u_short)buflen);
11227664Sbloom 			iov[0].iov_base = (caddr_t)&len;
11327664Sbloom 			iov[0].iov_len = sizeof(len);
11427664Sbloom 			iov[1].iov_base = buf;
11527664Sbloom 			iov[1].iov_len = buflen;
11627664Sbloom 			if (writev(s, iov, 2) != sizeof(len) + buflen) {
11729434Sbloom 				terrno = errno;
11824734Sbloom #ifdef DEBUG
11918144Sralph 				if (_res.options & RES_DEBUG)
12027031Skjd 					perror("write failed");
12125243Skjd #endif DEBUG
12218144Sralph 				(void) close(s);
12318144Sralph 				s = -1;
12418144Sralph 				continue;
12518144Sralph 			}
12618144Sralph 			/*
12718144Sralph 			 * Receive length & response
12818144Sralph 			 */
12918144Sralph 			cp = answer;
13018144Sralph 			len = sizeof(short);
13127664Sbloom 			while (len != 0 &&
13227031Skjd 			    (n = read(s, (char *)cp, (int)len)) > 0) {
13318144Sralph 				cp += n;
13418144Sralph 				len -= n;
13518144Sralph 			}
13618144Sralph 			if (n <= 0) {
13729434Sbloom 				terrno = errno;
13824734Sbloom #ifdef DEBUG
13918144Sralph 				if (_res.options & RES_DEBUG)
14027031Skjd 					perror("read failed");
14125243Skjd #endif DEBUG
14218144Sralph 				(void) close(s);
14318144Sralph 				s = -1;
14418144Sralph 				continue;
14518144Sralph 			}
14618144Sralph 			cp = answer;
14727025Sbloom 			resplen = len = ntohs(*(u_short *)cp);
14827664Sbloom 			while (len != 0 &&
14927031Skjd 			   (n = read(s, (char *)cp, (int)len)) > 0) {
15018144Sralph 				cp += n;
15118144Sralph 				len -= n;
15218144Sralph 			}
15318144Sralph 			if (n <= 0) {
15429434Sbloom 				terrno = errno;
15524734Sbloom #ifdef DEBUG
15618144Sralph 				if (_res.options & RES_DEBUG)
15727031Skjd 					perror("read failed");
15825243Skjd #endif DEBUG
15918144Sralph 				(void) close(s);
16018144Sralph 				s = -1;
16118144Sralph 				continue;
16218144Sralph 			}
16318144Sralph 		} else {
16418144Sralph 			/*
16518144Sralph 			 * Use datagrams.
16618144Sralph 			 */
16718144Sralph 			if (s < 0)
16818144Sralph 				s = socket(AF_INET, SOCK_DGRAM, 0);
16926483Skarels #if	BSD >= 43
170*30394Skjd 			if (_res.nscount == 1) {
171*30394Skjd 				/*
172*30394Skjd 				 * Connect/Send is detrimental if you
173*30394Skjd 				 * are going to poll more than one server
174*30394Skjd 				 */
175*30394Skjd 				if (connect(s, &_res.nsaddr_list[ns],
176*30394Skjd 				    sizeof(struct sockaddr)) < 0 ||
177*30394Skjd 				    send(s, buf, buflen, 0) != buflen) {
17824734Sbloom #ifdef DEBUG
179*30394Skjd 					if (_res.options & RES_DEBUG)
180*30394Skjd 						perror("connect");
18125243Skjd #endif DEBUG
182*30394Skjd 					continue;
183*30394Skjd 				}
184*30394Skjd 			} else
185*30394Skjd #endif BSD
18626483Skarels 			if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns],
18726483Skarels 			    sizeof(struct sockaddr)) != buflen) {
18826483Skarels #ifdef DEBUG
18927031Skjd 				if (_res.options & RES_DEBUG)
19027031Skjd 					perror("sendto");
19126483Skarels #endif DEBUG
19226483Skarels 				continue;
19326483Skarels 			}
194*30394Skjd 
19518144Sralph 			/*
19627031Skjd 			 * Wait for reply
19718144Sralph 			 */
19827031Skjd 			timeout.tv_sec = (_res.retrans << (_res.retry - retry))
19927031Skjd 				/ _res.nscount;
20027031Skjd 			if (timeout.tv_sec <= 0)
20127031Skjd 				timeout.tv_sec = 1;
20218144Sralph 			timeout.tv_usec = 0;
20326323Skarels wait:
20427796Skjd 			FD_ZERO(&dsmask);
20527796Skjd 			FD_SET(s, &dsmask);
20627664Sbloom 			n = select(s+1, &dsmask, (fd_set *)NULL,
20727664Sbloom 				(fd_set *)NULL, &timeout);
20818144Sralph 			if (n < 0) {
20924734Sbloom #ifdef DEBUG
21018144Sralph 				if (_res.options & RES_DEBUG)
21127031Skjd 					perror("select");
21225243Skjd #endif DEBUG
21318144Sralph 				continue;
21418144Sralph 			}
21518144Sralph 			if (n == 0) {
21618144Sralph 				/*
21718144Sralph 				 * timeout
21818144Sralph 				 */
21924734Sbloom #ifdef DEBUG
22018144Sralph 				if (_res.options & RES_DEBUG)
22118144Sralph 					printf("timeout\n");
22225243Skjd #endif DEBUG
22326483Skarels 				gotsomewhere = 1;
22418144Sralph 				continue;
22518144Sralph 			}
22625332Skjd 			if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
22724734Sbloom #ifdef DEBUG
22818144Sralph 				if (_res.options & RES_DEBUG)
22927031Skjd 					perror("recvfrom");
23025243Skjd #endif DEBUG
23118144Sralph 				continue;
23218144Sralph 			}
23326483Skarels 			gotsomewhere = 1;
23418144Sralph 			if (id != anhp->id) {
23518144Sralph 				/*
23618144Sralph 				 * response from old query, ignore it
23718144Sralph 				 */
23824734Sbloom #ifdef DEBUG
23918144Sralph 				if (_res.options & RES_DEBUG) {
24018144Sralph 					printf("old answer:\n");
24118144Sralph 					p_query(answer);
24218144Sralph 				}
24325243Skjd #endif DEBUG
24426323Skarels 				goto wait;
24518144Sralph 			}
24618144Sralph 			if (!(_res.options & RES_IGNTC) && anhp->tc) {
24718144Sralph 				/*
24818144Sralph 				 * get rest of answer
24918144Sralph 				 */
25024734Sbloom #ifdef DEBUG
25118144Sralph 				if (_res.options & RES_DEBUG)
25218144Sralph 					printf("truncated answer\n");
25325243Skjd #endif DEBUG
25418144Sralph 				(void) close(s);
25518144Sralph 				s = -1;
25627040Skjd 				/*
25727040Skjd 				 * retry decremented on continue
25827040Skjd 				 * to desired starting value
25927040Skjd 				 */
26027040Skjd 				retry = _res.retry + 1;
26118144Sralph 				v_circuit = 1;
26218144Sralph 				continue;
26318144Sralph 			}
26418144Sralph 		}
26524734Sbloom #ifdef DEBUG
26618144Sralph 		if (_res.options & RES_DEBUG) {
26718144Sralph 			printf("got answer:\n");
26818144Sralph 			p_query(answer);
26918144Sralph 		}
27025243Skjd #endif DEBUG
27126322Sbloom 		/*
27226322Sbloom 		 * We are going to assume that the first server is preferred
27326322Sbloom 		 * over the rest (i.e. it is on the local machine) and only
27426322Sbloom 		 * keep that one open.
27526322Sbloom 		 */
27626322Sbloom 		if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) {
27726322Sbloom 			return (resplen);
27826322Sbloom 		} else {
27926322Sbloom 			(void) close(s);
28026322Sbloom 			s = -1;
28126322Sbloom 			return (resplen);
28226322Sbloom 		}
28325243Skjd 	   }
28418144Sralph 	}
28529434Sbloom 	if (s >= 0) {
28629434Sbloom 		(void) close(s);
28729434Sbloom 		s = -1;
28829434Sbloom 	}
28929434Sbloom 	if (v_circuit == 0)
29029434Sbloom 		if (gotsomewhere == 0)
29129434Sbloom 			errno = ECONNREFUSED;
29229434Sbloom 		else
29329434Sbloom 			errno = ETIMEDOUT;
29426483Skarels 	else
29529434Sbloom 		errno = terrno;
29618144Sralph 	return (-1);
29718144Sralph }
29827025Sbloom 
29927025Sbloom /*
30027025Sbloom  * This routine is for closing the socket if a virtual circuit is used and
30127025Sbloom  * the program wants to close it.  This provides support for endhostent()
30227025Sbloom  * which expects to close the socket.
30327025Sbloom  *
30427025Sbloom  * This routine is not expected to be user visible.
30527025Sbloom  */
30627025Sbloom _res_close()
30727025Sbloom {
30827025Sbloom 	if (s != -1) {
30927025Sbloom 		(void) close(s);
31027025Sbloom 		s = -1;
31127025Sbloom 	}
31227025Sbloom }
313