xref: /csrg-svn/lib/libc/net/res_send.c (revision 29434)
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*29434Sbloom static char sccsid[] = "@(#)res_send.c	6.14 (Berkeley) 07/02/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>
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 */
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;
4327796Skjd 	fd_set dsmask;
4418144Sralph 	struct timeval timeout;
4518144Sralph 	HEADER *hp = (HEADER *) buf;
4618144Sralph 	HEADER *anhp = (HEADER *) answer;
4727664Sbloom 	struct iovec iov[2];
48*29434Sbloom 	int terrno = ETIMEDOUT;
4918144Sralph 
5024734Sbloom #ifdef DEBUG
5118144Sralph 	if (_res.options & RES_DEBUG) {
5218531Sralph 		printf("res_send()\n");
5318144Sralph 		p_query(buf);
5418144Sralph 	}
5525243Skjd #endif DEBUG
5618531Sralph 	if (!(_res.options & RES_INIT))
5724734Sbloom 		if (res_init() == -1) {
5824734Sbloom 			return(-1);
5924734Sbloom 		}
6018144Sralph 	v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
6118144Sralph 	id = hp->id;
6218144Sralph 	/*
6318144Sralph 	 * Send request, RETRY times, or until successful
6418144Sralph 	 */
6527040Skjd 	for (retry = _res.retry; retry > 0; retry--) {
6625243Skjd 	   for (ns = 0; ns < _res.nscount; ns++) {
6725243Skjd #ifdef DEBUG
6825243Skjd 		if (_res.options & RES_DEBUG)
6925243Skjd 			printf("Querying server (# %d) address = %s\n", ns+1,
7027031Skjd 			      inet_ntoa(_res.nsaddr_list[ns].sin_addr.s_addr));
7125243Skjd #endif DEBUG
7218144Sralph 		if (v_circuit) {
7318144Sralph 			/*
7418144Sralph 			 * Use virtual circuit.
7518144Sralph 			 */
7626322Sbloom 			if (s < 0) {
7718144Sralph 				s = socket(AF_INET, SOCK_STREAM, 0);
7826483Skarels 				if (s < 0) {
79*29434Sbloom 					terrno = errno;
8026483Skarels #ifdef DEBUG
8126483Skarels 					if (_res.options & RES_DEBUG)
8227031Skjd 					    perror("socket failed");
8326483Skarels #endif DEBUG
8426483Skarels 					continue;
8526483Skarels 				}
8627031Skjd 				if (connect(s, &(_res.nsaddr_list[ns]),
8726322Sbloom 				   sizeof(struct sockaddr)) < 0) {
88*29434Sbloom 					terrno = errno;
8924734Sbloom #ifdef DEBUG
9026322Sbloom 					if (_res.options & RES_DEBUG)
9127031Skjd 					    perror("connect failed");
9225243Skjd #endif DEBUG
9326322Sbloom 					(void) close(s);
9426322Sbloom 					s = -1;
9526322Sbloom 					continue;
9626322Sbloom 				}
9718144Sralph 			}
9818144Sralph 			/*
9918144Sralph 			 * Send length & message
10018144Sralph 			 */
10127025Sbloom 			len = htons((u_short)buflen);
10227664Sbloom 			iov[0].iov_base = (caddr_t)&len;
10327664Sbloom 			iov[0].iov_len = sizeof(len);
10427664Sbloom 			iov[1].iov_base = buf;
10527664Sbloom 			iov[1].iov_len = buflen;
10627664Sbloom 			if (writev(s, iov, 2) != sizeof(len) + buflen) {
107*29434Sbloom 				terrno = errno;
10824734Sbloom #ifdef DEBUG
10918144Sralph 				if (_res.options & RES_DEBUG)
11027031Skjd 					perror("write failed");
11125243Skjd #endif DEBUG
11218144Sralph 				(void) close(s);
11318144Sralph 				s = -1;
11418144Sralph 				continue;
11518144Sralph 			}
11618144Sralph 			/*
11718144Sralph 			 * Receive length & response
11818144Sralph 			 */
11918144Sralph 			cp = answer;
12018144Sralph 			len = sizeof(short);
12127664Sbloom 			while (len != 0 &&
12227031Skjd 			    (n = read(s, (char *)cp, (int)len)) > 0) {
12318144Sralph 				cp += n;
12418144Sralph 				len -= n;
12518144Sralph 			}
12618144Sralph 			if (n <= 0) {
127*29434Sbloom 				terrno = errno;
12824734Sbloom #ifdef DEBUG
12918144Sralph 				if (_res.options & RES_DEBUG)
13027031Skjd 					perror("read failed");
13125243Skjd #endif DEBUG
13218144Sralph 				(void) close(s);
13318144Sralph 				s = -1;
13418144Sralph 				continue;
13518144Sralph 			}
13618144Sralph 			cp = answer;
13727025Sbloom 			resplen = len = ntohs(*(u_short *)cp);
13827664Sbloom 			while (len != 0 &&
13927031Skjd 			   (n = read(s, (char *)cp, (int)len)) > 0) {
14018144Sralph 				cp += n;
14118144Sralph 				len -= n;
14218144Sralph 			}
14318144Sralph 			if (n <= 0) {
144*29434Sbloom 				terrno = errno;
14524734Sbloom #ifdef DEBUG
14618144Sralph 				if (_res.options & RES_DEBUG)
14727031Skjd 					perror("read failed");
14825243Skjd #endif DEBUG
14918144Sralph 				(void) close(s);
15018144Sralph 				s = -1;
15118144Sralph 				continue;
15218144Sralph 			}
15318144Sralph 		} else {
15418144Sralph 			/*
15518144Sralph 			 * Use datagrams.
15618144Sralph 			 */
15718144Sralph 			if (s < 0)
15818144Sralph 				s = socket(AF_INET, SOCK_DGRAM, 0);
15926483Skarels #if	BSD >= 43
16026323Skarels 			if (connect(s, &_res.nsaddr_list[ns],
16126323Skarels 			    sizeof(struct sockaddr)) < 0 ||
16226323Skarels 			    send(s, buf, buflen, 0) != buflen) {
16324734Sbloom #ifdef DEBUG
16427031Skjd 				if (_res.options & RES_DEBUG)
16527031Skjd 					perror("connect");
16625243Skjd #endif DEBUG
16726483Skarels 				continue;
16818144Sralph 			}
16926483Skarels #else BSD
17026483Skarels 			if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns],
17126483Skarels 			    sizeof(struct sockaddr)) != buflen) {
17226483Skarels #ifdef DEBUG
17327031Skjd 				if (_res.options & RES_DEBUG)
17427031Skjd 					perror("sendto");
17526483Skarels #endif DEBUG
17626483Skarels 				continue;
17726483Skarels 			}
17826483Skarels #endif BSD
17918144Sralph 			/*
18027031Skjd 			 * Wait for reply
18118144Sralph 			 */
18227031Skjd 			timeout.tv_sec = (_res.retrans << (_res.retry - retry))
18327031Skjd 				/ _res.nscount;
18427031Skjd 			if (timeout.tv_sec <= 0)
18527031Skjd 				timeout.tv_sec = 1;
18618144Sralph 			timeout.tv_usec = 0;
18726323Skarels wait:
18827796Skjd 			FD_ZERO(&dsmask);
18927796Skjd 			FD_SET(s, &dsmask);
19027664Sbloom 			n = select(s+1, &dsmask, (fd_set *)NULL,
19127664Sbloom 				(fd_set *)NULL, &timeout);
19218144Sralph 			if (n < 0) {
19324734Sbloom #ifdef DEBUG
19418144Sralph 				if (_res.options & RES_DEBUG)
19527031Skjd 					perror("select");
19625243Skjd #endif DEBUG
19718144Sralph 				continue;
19818144Sralph 			}
19918144Sralph 			if (n == 0) {
20018144Sralph 				/*
20118144Sralph 				 * timeout
20218144Sralph 				 */
20324734Sbloom #ifdef DEBUG
20418144Sralph 				if (_res.options & RES_DEBUG)
20518144Sralph 					printf("timeout\n");
20625243Skjd #endif DEBUG
20726483Skarels 				gotsomewhere = 1;
20818144Sralph 				continue;
20918144Sralph 			}
21025332Skjd 			if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
21124734Sbloom #ifdef DEBUG
21218144Sralph 				if (_res.options & RES_DEBUG)
21327031Skjd 					perror("recvfrom");
21425243Skjd #endif DEBUG
21518144Sralph 				continue;
21618144Sralph 			}
21726483Skarels 			gotsomewhere = 1;
21818144Sralph 			if (id != anhp->id) {
21918144Sralph 				/*
22018144Sralph 				 * response from old query, ignore it
22118144Sralph 				 */
22224734Sbloom #ifdef DEBUG
22318144Sralph 				if (_res.options & RES_DEBUG) {
22418144Sralph 					printf("old answer:\n");
22518144Sralph 					p_query(answer);
22618144Sralph 				}
22725243Skjd #endif DEBUG
22826323Skarels 				goto wait;
22918144Sralph 			}
23018144Sralph 			if (!(_res.options & RES_IGNTC) && anhp->tc) {
23118144Sralph 				/*
23218144Sralph 				 * get rest of answer
23318144Sralph 				 */
23424734Sbloom #ifdef DEBUG
23518144Sralph 				if (_res.options & RES_DEBUG)
23618144Sralph 					printf("truncated answer\n");
23725243Skjd #endif DEBUG
23818144Sralph 				(void) close(s);
23918144Sralph 				s = -1;
24027040Skjd 				/*
24127040Skjd 				 * retry decremented on continue
24227040Skjd 				 * to desired starting value
24327040Skjd 				 */
24427040Skjd 				retry = _res.retry + 1;
24518144Sralph 				v_circuit = 1;
24618144Sralph 				continue;
24718144Sralph 			}
24818144Sralph 		}
24924734Sbloom #ifdef DEBUG
25018144Sralph 		if (_res.options & RES_DEBUG) {
25118144Sralph 			printf("got answer:\n");
25218144Sralph 			p_query(answer);
25318144Sralph 		}
25425243Skjd #endif DEBUG
25526322Sbloom 		/*
25626322Sbloom 		 * We are going to assume that the first server is preferred
25726322Sbloom 		 * over the rest (i.e. it is on the local machine) and only
25826322Sbloom 		 * keep that one open.
25926322Sbloom 		 */
26026322Sbloom 		if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) {
26126322Sbloom 			return (resplen);
26226322Sbloom 		} else {
26326322Sbloom 			(void) close(s);
26426322Sbloom 			s = -1;
26526322Sbloom 			return (resplen);
26626322Sbloom 		}
26725243Skjd 	   }
26818144Sralph 	}
269*29434Sbloom 	if (s >= 0) {
270*29434Sbloom 		(void) close(s);
271*29434Sbloom 		s = -1;
272*29434Sbloom 	}
273*29434Sbloom 	if (v_circuit == 0)
274*29434Sbloom 		if (gotsomewhere == 0)
275*29434Sbloom 			errno = ECONNREFUSED;
276*29434Sbloom 		else
277*29434Sbloom 			errno = ETIMEDOUT;
27826483Skarels 	else
279*29434Sbloom 		errno = terrno;
28018144Sralph 	return (-1);
28118144Sralph }
28227025Sbloom 
28327025Sbloom /*
28427025Sbloom  * This routine is for closing the socket if a virtual circuit is used and
28527025Sbloom  * the program wants to close it.  This provides support for endhostent()
28627025Sbloom  * which expects to close the socket.
28727025Sbloom  *
28827025Sbloom  * This routine is not expected to be user visible.
28927025Sbloom  */
29027025Sbloom _res_close()
29127025Sbloom {
29227025Sbloom 	if (s != -1) {
29327025Sbloom 		(void) close(s);
29427025Sbloom 		s = -1;
29527025Sbloom 	}
29627025Sbloom }
297