xref: /csrg-svn/lib/libc/net/res_send.c (revision 27031)
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*27031Skjd static char sccsid[] = "@(#)res_send.c	6.10 (Berkeley) 04/10/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>
1918144Sralph #include <netinet/in.h>
2018144Sralph #include <stdio.h>
2118144Sralph #include <errno.h>
2224083Skjd #include <arpa/nameser.h>
2326896Skjd #include <resolv.h>
2418144Sralph 
2518144Sralph extern int errno;
2618144Sralph 
2727025Sbloom static int s = -1;	/* socket used for communications */
2827025Sbloom 
2926322Sbloom #define KEEPOPEN (RES_USEVC|RES_STAYOPEN)
3026322Sbloom 
3118531Sralph res_send(buf, buflen, answer, anslen)
3218144Sralph 	char *buf;
3318144Sralph 	int buflen;
3418144Sralph 	char *answer;
3518144Sralph 	int anslen;
3618144Sralph {
3718144Sralph 	register int n;
3826322Sbloom 	int retry, v_circuit, resplen, ns;
3926483Skarels 	int gotsomewhere = 0;
4018144Sralph 	u_short id, len;
4118144Sralph 	char *cp;
4218144Sralph 	int dsmask;
4318144Sralph 	struct timeval timeout;
4418144Sralph 	HEADER *hp = (HEADER *) buf;
4518144Sralph 	HEADER *anhp = (HEADER *) answer;
4618144Sralph 
47*27031Skjd 	extern u_short htons(), ntohs();
48*27031Skjd 
4924734Sbloom #ifdef DEBUG
5018144Sralph 	if (_res.options & RES_DEBUG) {
5118531Sralph 		printf("res_send()\n");
5218144Sralph 		p_query(buf);
5318144Sralph 	}
5425243Skjd #endif DEBUG
5518531Sralph 	if (!(_res.options & RES_INIT))
5624734Sbloom 		if (res_init() == -1) {
5724734Sbloom 			return(-1);
5824734Sbloom 		}
5918144Sralph 	v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
6018144Sralph 	id = hp->id;
6118144Sralph 	/*
6218144Sralph 	 * Send request, RETRY times, or until successful
6318144Sralph 	 */
6418144Sralph 	for (retry = _res.retry; --retry >= 0; ) {
6525243Skjd 	   for (ns = 0; ns < _res.nscount; ns++) {
6625243Skjd #ifdef DEBUG
6725243Skjd 		if (_res.options & RES_DEBUG)
6825243Skjd 			printf("Querying server (# %d) address = %s\n", ns+1,
69*27031Skjd 			      inet_ntoa(_res.nsaddr_list[ns].sin_addr.s_addr));
7025243Skjd #endif DEBUG
7118144Sralph 		if (v_circuit) {
7218144Sralph 			/*
7318144Sralph 			 * Use virtual circuit.
7418144Sralph 			 */
7526322Sbloom 			if (s < 0) {
7618144Sralph 				s = socket(AF_INET, SOCK_STREAM, 0);
7726483Skarels 				if (s < 0) {
7826483Skarels #ifdef DEBUG
7926483Skarels 					if (_res.options & RES_DEBUG)
80*27031Skjd 					    perror("socket failed");
8126483Skarels #endif DEBUG
8226483Skarels 					continue;
8326483Skarels 				}
84*27031Skjd 				if (connect(s, &(_res.nsaddr_list[ns]),
8526322Sbloom 				   sizeof(struct sockaddr)) < 0) {
8624734Sbloom #ifdef DEBUG
8726322Sbloom 					if (_res.options & RES_DEBUG)
88*27031Skjd 					    perror("connect failed");
8925243Skjd #endif DEBUG
9026322Sbloom 					(void) close(s);
9126322Sbloom 					s = -1;
9226322Sbloom 					continue;
9326322Sbloom 				}
9418144Sralph 			}
9518144Sralph 			/*
9618144Sralph 			 * Send length & message
9718144Sralph 			 */
9827025Sbloom 			len = htons((u_short)buflen);
99*27031Skjd 			if (write(s, (char *)&len, sizeof(len)) != sizeof(len)||
100*27031Skjd 			    write(s, buf, buflen) != buflen) {
10124734Sbloom #ifdef DEBUG
10218144Sralph 				if (_res.options & RES_DEBUG)
103*27031Skjd 					perror("write failed");
10425243Skjd #endif DEBUG
10518144Sralph 				(void) close(s);
10618144Sralph 				s = -1;
10718144Sralph 				continue;
10818144Sralph 			}
10918144Sralph 			/*
11018144Sralph 			 * Receive length & response
11118144Sralph 			 */
11218144Sralph 			cp = answer;
11318144Sralph 			len = sizeof(short);
114*27031Skjd 			while (len > 0 &&
115*27031Skjd 			    (n = read(s, (char *)cp, (int)len)) > 0) {
11618144Sralph 				cp += n;
11718144Sralph 				len -= n;
11818144Sralph 			}
11918144Sralph 			if (n <= 0) {
12024734Sbloom #ifdef DEBUG
12118144Sralph 				if (_res.options & RES_DEBUG)
122*27031Skjd 					perror("read failed");
12325243Skjd #endif DEBUG
12418144Sralph 				(void) close(s);
12518144Sralph 				s = -1;
12618144Sralph 				continue;
12718144Sralph 			}
12818144Sralph 			cp = answer;
12927025Sbloom 			resplen = len = ntohs(*(u_short *)cp);
130*27031Skjd 			while (len > 0 &&
131*27031Skjd 			   (n = read(s, (char *)cp, (int)len)) > 0) {
13218144Sralph 				cp += n;
13318144Sralph 				len -= n;
13418144Sralph 			}
13518144Sralph 			if (n <= 0) {
13624734Sbloom #ifdef DEBUG
13718144Sralph 				if (_res.options & RES_DEBUG)
138*27031Skjd 					perror("read failed");
13925243Skjd #endif DEBUG
14018144Sralph 				(void) close(s);
14118144Sralph 				s = -1;
14218144Sralph 				continue;
14318144Sralph 			}
14418144Sralph 		} else {
14518144Sralph 			/*
14618144Sralph 			 * Use datagrams.
14718144Sralph 			 */
14818144Sralph 			if (s < 0)
14918144Sralph 				s = socket(AF_INET, SOCK_DGRAM, 0);
15026483Skarels #if	BSD >= 43
15126323Skarels 			if (connect(s, &_res.nsaddr_list[ns],
15226323Skarels 			    sizeof(struct sockaddr)) < 0 ||
15326323Skarels 			    send(s, buf, buflen, 0) != buflen) {
15424734Sbloom #ifdef DEBUG
155*27031Skjd 				if (_res.options & RES_DEBUG)
156*27031Skjd 					perror("connect");
15725243Skjd #endif DEBUG
15826483Skarels 				continue;
15918144Sralph 			}
16026483Skarels #else BSD
16126483Skarels 			if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns],
16226483Skarels 			    sizeof(struct sockaddr)) != buflen) {
16326483Skarels #ifdef DEBUG
164*27031Skjd 				if (_res.options & RES_DEBUG)
165*27031Skjd 					perror("sendto");
16626483Skarels #endif DEBUG
16726483Skarels 				continue;
16826483Skarels 			}
16926483Skarels #endif BSD
17018144Sralph 			/*
171*27031Skjd 			 * Wait for reply
17218144Sralph 			 */
173*27031Skjd 			timeout.tv_sec = (_res.retrans << (_res.retry - retry))
174*27031Skjd 				/ _res.nscount;
175*27031Skjd 			if (timeout.tv_sec <= 0)
176*27031Skjd 				timeout.tv_sec = 1;
17718144Sralph 			timeout.tv_usec = 0;
17826323Skarels wait:
17918144Sralph 			dsmask = 1 << s;
18018144Sralph 			n = select(s+1, &dsmask, 0, 0, &timeout);
18118144Sralph 			if (n < 0) {
18224734Sbloom #ifdef DEBUG
18318144Sralph 				if (_res.options & RES_DEBUG)
184*27031Skjd 					perror("select");
18525243Skjd #endif DEBUG
18618144Sralph 				continue;
18718144Sralph 			}
18818144Sralph 			if (n == 0) {
18918144Sralph 				/*
19018144Sralph 				 * timeout
19118144Sralph 				 */
19224734Sbloom #ifdef DEBUG
19318144Sralph 				if (_res.options & RES_DEBUG)
19418144Sralph 					printf("timeout\n");
19525243Skjd #endif DEBUG
19626483Skarels 				gotsomewhere = 1;
19718144Sralph 				continue;
19818144Sralph 			}
19925332Skjd 			if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
20024734Sbloom #ifdef DEBUG
20118144Sralph 				if (_res.options & RES_DEBUG)
202*27031Skjd 					perror("recvfrom");
20325243Skjd #endif DEBUG
20418144Sralph 				continue;
20518144Sralph 			}
20626483Skarels 			gotsomewhere = 1;
20718144Sralph 			if (id != anhp->id) {
20818144Sralph 				/*
20918144Sralph 				 * response from old query, ignore it
21018144Sralph 				 */
21124734Sbloom #ifdef DEBUG
21218144Sralph 				if (_res.options & RES_DEBUG) {
21318144Sralph 					printf("old answer:\n");
21418144Sralph 					p_query(answer);
21518144Sralph 				}
21625243Skjd #endif DEBUG
21726323Skarels 				goto wait;
21818144Sralph 			}
21918144Sralph 			if (!(_res.options & RES_IGNTC) && anhp->tc) {
22018144Sralph 				/*
22118144Sralph 				 * get rest of answer
22218144Sralph 				 */
22324734Sbloom #ifdef DEBUG
22418144Sralph 				if (_res.options & RES_DEBUG)
22518144Sralph 					printf("truncated answer\n");
22625243Skjd #endif DEBUG
22718144Sralph 				(void) close(s);
22818144Sralph 				s = -1;
22918144Sralph 				retry = _res.retry;
23018144Sralph 				v_circuit = 1;
23118144Sralph 				continue;
23218144Sralph 			}
23318144Sralph 		}
23424734Sbloom #ifdef DEBUG
23518144Sralph 		if (_res.options & RES_DEBUG) {
23618144Sralph 			printf("got answer:\n");
23718144Sralph 			p_query(answer);
23818144Sralph 		}
23925243Skjd #endif DEBUG
24026322Sbloom 		/*
24126322Sbloom 		 * We are going to assume that the first server is preferred
24226322Sbloom 		 * over the rest (i.e. it is on the local machine) and only
24326322Sbloom 		 * keep that one open.
24426322Sbloom 		 */
24526322Sbloom 		if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) {
24626322Sbloom 			return (resplen);
24726322Sbloom 		} else {
24826322Sbloom 			(void) close(s);
24926322Sbloom 			s = -1;
25026322Sbloom 			return (resplen);
25126322Sbloom 		}
25225243Skjd 	   }
25318144Sralph 	}
25423873Skjd 	(void) close(s);
25526897Sbloom 	s = -1;
25626483Skarels 	if (v_circuit == 0 && gotsomewhere == 0)
25726483Skarels 		errno = ECONNREFUSED;
25826483Skarels 	else
25926483Skarels 		errno = ETIMEDOUT;
26018144Sralph 	return (-1);
26118144Sralph }
26227025Sbloom 
26327025Sbloom /*
26427025Sbloom  * This routine is for closing the socket if a virtual circuit is used and
26527025Sbloom  * the program wants to close it.  This provides support for endhostent()
26627025Sbloom  * which expects to close the socket.
26727025Sbloom  *
26827025Sbloom  * This routine is not expected to be user visible.
26927025Sbloom  */
27027025Sbloom _res_close()
27127025Sbloom {
27227025Sbloom 	if (s != -1) {
27327025Sbloom 		(void) close(s);
27427025Sbloom 		s = -1;
27527025Sbloom 	}
27627025Sbloom }
277