xref: /csrg-svn/lib/libc/net/res_send.c (revision 26322)
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 
821388Sdist #ifndef lint
9*26322Sbloom static char sccsid[] = "@(#)res_send.c	6.2 (Berkeley) 02/22/86";
1021388Sdist #endif not lint
1121388Sdist 
1218548Sralph /*
1318144Sralph  * Send query to name server and wait for reply.
1418144Sralph  */
1518144Sralph 
1618144Sralph #include <sys/types.h>
1718144Sralph #include <sys/time.h>
1818144Sralph #include <sys/socket.h>
1918144Sralph #include <netinet/in.h>
2018144Sralph #include <stdio.h>
2118144Sralph #include <errno.h>
2224083Skjd #include <arpa/nameser.h>
2324083Skjd #include <arpa/resolv.h>
2418144Sralph 
2518144Sralph extern int errno;
2618144Sralph 
27*26322Sbloom #define KEEPOPEN (RES_USEVC|RES_STAYOPEN)
28*26322Sbloom 
2918531Sralph res_send(buf, buflen, answer, anslen)
3018144Sralph 	char *buf;
3118144Sralph 	int buflen;
3218144Sralph 	char *answer;
3318144Sralph 	int anslen;
3418144Sralph {
3518144Sralph 	register int n;
36*26322Sbloom 	int retry, v_circuit, resplen, ns;
37*26322Sbloom 	static int s = -1;
3818144Sralph 	u_short id, len;
3918144Sralph 	char *cp;
4018144Sralph 	int dsmask;
4118144Sralph 	struct timeval timeout;
4218144Sralph 	HEADER *hp = (HEADER *) buf;
4318144Sralph 	HEADER *anhp = (HEADER *) answer;
4418144Sralph 
4524734Sbloom #ifdef DEBUG
4618144Sralph 	if (_res.options & RES_DEBUG) {
4718531Sralph 		printf("res_send()\n");
4818144Sralph 		p_query(buf);
4918144Sralph 	}
5025243Skjd #endif DEBUG
5118531Sralph 	if (!(_res.options & RES_INIT))
5224734Sbloom 		if (res_init() == -1) {
5324734Sbloom 			return(-1);
5424734Sbloom 		}
5518144Sralph 	v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
5618144Sralph 	id = hp->id;
5718144Sralph 	/*
5818144Sralph 	 * Send request, RETRY times, or until successful
5918144Sralph 	 */
6018144Sralph 	for (retry = _res.retry; --retry >= 0; ) {
6125243Skjd 	   for (ns = 0; ns < _res.nscount; ns++) {
6225243Skjd #ifdef DEBUG
6325243Skjd 		if (_res.options & RES_DEBUG)
6425243Skjd 			printf("Querying server (# %d) address = %s\n", ns+1,
6525243Skjd 			      inet_ntoa(_res.nsaddr_list[ns].sin_addr.s_addr));
6625243Skjd #endif DEBUG
6718144Sralph 		if (v_circuit) {
6818144Sralph 			/*
6918144Sralph 			 * Use virtual circuit.
7018144Sralph 			 */
71*26322Sbloom 			if (s < 0) {
7218144Sralph 				s = socket(AF_INET, SOCK_STREAM, 0);
73*26322Sbloom 				if (connect(s, &(_res.nsaddr_list[ns]),
74*26322Sbloom 				   sizeof(struct sockaddr)) < 0) {
7524734Sbloom #ifdef DEBUG
76*26322Sbloom 					if (_res.options & RES_DEBUG)
77*26322Sbloom 					    printf("connect failed %d\n",errno);
7825243Skjd #endif DEBUG
79*26322Sbloom 					(void) close(s);
80*26322Sbloom 					s = -1;
81*26322Sbloom 					continue;
82*26322Sbloom 				}
8318144Sralph 			}
8418144Sralph 			/*
8518144Sralph 			 * Send length & message
8618144Sralph 			 */
8718144Sralph 			len = htons(buflen);
8818144Sralph 			if (write(s, &len, sizeof(len)) != sizeof(len) ||
8925243Skjd 				    write(s, buf, buflen) != buflen) {
9024734Sbloom #ifdef DEBUG
9118144Sralph 				if (_res.options & RES_DEBUG)
9218144Sralph 					printf("write failed %d\n", errno);
9325243Skjd #endif DEBUG
9418144Sralph 				(void) close(s);
9518144Sralph 				s = -1;
9618144Sralph 				continue;
9718144Sralph 			}
9818144Sralph 			/*
9918144Sralph 			 * Receive length & response
10018144Sralph 			 */
10118144Sralph 			cp = answer;
10218144Sralph 			len = sizeof(short);
10318144Sralph 			while (len > 0 && (n = read(s, cp, len)) > 0) {
10418144Sralph 				cp += n;
10518144Sralph 				len -= n;
10618144Sralph 			}
10718144Sralph 			if (n <= 0) {
10824734Sbloom #ifdef DEBUG
10918144Sralph 				if (_res.options & RES_DEBUG)
11018144Sralph 					printf("read failed %d\n", errno);
11125243Skjd #endif DEBUG
11218144Sralph 				(void) close(s);
11318144Sralph 				s = -1;
11418144Sralph 				continue;
11518144Sralph 			}
11618144Sralph 			cp = answer;
11718144Sralph 			resplen = len = ntohs(*(short *)cp);
11818144Sralph 			while (len > 0 && (n = read(s, cp, len)) > 0) {
11918144Sralph 				cp += n;
12018144Sralph 				len -= n;
12118144Sralph 			}
12218144Sralph 			if (n <= 0) {
12324734Sbloom #ifdef DEBUG
12418144Sralph 				if (_res.options & RES_DEBUG)
12518144Sralph 					printf("read failed %d\n", errno);
12625243Skjd #endif DEBUG
12718144Sralph 				(void) close(s);
12818144Sralph 				s = -1;
12918144Sralph 				continue;
13018144Sralph 			}
13118144Sralph 		} else {
13218144Sralph 			/*
13318144Sralph 			 * Use datagrams.
13418144Sralph 			 */
13518144Sralph 			if (s < 0)
13618144Sralph 				s = socket(AF_INET, SOCK_DGRAM, 0);
13725243Skjd 			if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns],
13825243Skjd 			    sizeof(struct sockaddr)) != buflen) {
13924734Sbloom #ifdef DEBUG
14025243Skjd 				if (_res.options & RES_DEBUG)
14118144Sralph 					printf("sendto errno = %d\n", errno);
14225243Skjd #endif DEBUG
14318144Sralph 			}
14418144Sralph 			/*
14518144Sralph 			 * Wait for reply
14618144Sralph 			 */
14725243Skjd 			timeout.tv_sec =
14825243Skjd 				((_res.retrans * _res.retry) / _res.nscount);
14918144Sralph 			timeout.tv_usec = 0;
15018144Sralph 			dsmask = 1 << s;
15118144Sralph 			n = select(s+1, &dsmask, 0, 0, &timeout);
15218144Sralph 			if (n < 0) {
15324734Sbloom #ifdef DEBUG
15418144Sralph 				if (_res.options & RES_DEBUG)
15518144Sralph 					printf("select errno = %d\n", errno);
15625243Skjd #endif DEBUG
15718144Sralph 				continue;
15818144Sralph 			}
15918144Sralph 			if (n == 0) {
16018144Sralph 				/*
16118144Sralph 				 * timeout
16218144Sralph 				 */
16324734Sbloom #ifdef DEBUG
16418144Sralph 				if (_res.options & RES_DEBUG)
16518144Sralph 					printf("timeout\n");
16625243Skjd #endif DEBUG
16718144Sralph 				continue;
16818144Sralph 			}
16925332Skjd 			if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
17024734Sbloom #ifdef DEBUG
17118144Sralph 				if (_res.options & RES_DEBUG)
17218144Sralph 					printf("recvfrom, errno=%d\n", errno);
17325243Skjd #endif DEBUG
17418144Sralph 				continue;
17518144Sralph 			}
17618144Sralph 			if (id != anhp->id) {
17718144Sralph 				/*
17818144Sralph 				 * response from old query, ignore it
17918144Sralph 				 */
18024734Sbloom #ifdef DEBUG
18118144Sralph 				if (_res.options & RES_DEBUG) {
18218144Sralph 					printf("old answer:\n");
18318144Sralph 					p_query(answer);
18418144Sralph 				}
18525243Skjd #endif DEBUG
18618144Sralph 				continue;
18718144Sralph 			}
18818144Sralph 			if (!(_res.options & RES_IGNTC) && anhp->tc) {
18918144Sralph 				/*
19018144Sralph 				 * get rest of answer
19118144Sralph 				 */
19224734Sbloom #ifdef DEBUG
19318144Sralph 				if (_res.options & RES_DEBUG)
19418144Sralph 					printf("truncated answer\n");
19525243Skjd #endif DEBUG
19618144Sralph 				(void) close(s);
19718144Sralph 				s = -1;
19818144Sralph 				retry = _res.retry;
19918144Sralph 				v_circuit = 1;
20018144Sralph 				continue;
20118144Sralph 			}
20218144Sralph 		}
20324734Sbloom #ifdef DEBUG
20418144Sralph 		if (_res.options & RES_DEBUG) {
20518144Sralph 			printf("got answer:\n");
20618144Sralph 			p_query(answer);
20718144Sralph 		}
20825243Skjd #endif DEBUG
209*26322Sbloom 		/*
210*26322Sbloom 		 * We are going to assume that the first server is preferred
211*26322Sbloom 		 * over the rest (i.e. it is on the local machine) and only
212*26322Sbloom 		 * keep that one open.
213*26322Sbloom 		 */
214*26322Sbloom 		if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) {
215*26322Sbloom 			return (resplen);
216*26322Sbloom 		} else {
217*26322Sbloom 			(void) close(s);
218*26322Sbloom 			s = -1;
219*26322Sbloom 			return (resplen);
220*26322Sbloom 		}
22125243Skjd 	   }
22218144Sralph 	}
22323873Skjd 	(void) close(s);
22424032Skjd 	errno = ETIMEDOUT;
22518144Sralph 	return (-1);
22618144Sralph }
227