xref: /csrg-svn/lib/libc/net/res_send.c (revision 25354)
1 
2 /*
3  * Copyright (c) 1985 Regents of the University of California.
4  * All rights reserved.  The Berkeley software License Agreement
5  * specifies the terms and conditions for redistribution.
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)res_send.c	6.1 (Berkeley) 10/31/85";
10 #endif not lint
11 
12 /*
13  * Send query to name server and wait for reply.
14  */
15 
16 #include <sys/types.h>
17 #include <sys/time.h>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <stdio.h>
21 #include <errno.h>
22 #include <arpa/nameser.h>
23 #include <arpa/resolv.h>
24 
25 extern int errno;
26 
27 res_send(buf, buflen, answer, anslen)
28 	char *buf;
29 	int buflen;
30 	char *answer;
31 	int anslen;
32 {
33 	register int n;
34 	int s, retry, v_circuit, resplen, ns;
35 	u_short id, len;
36 	char *cp;
37 	int dsmask;
38 	struct timeval timeout;
39 	HEADER *hp = (HEADER *) buf;
40 	HEADER *anhp = (HEADER *) answer;
41 
42 #ifdef DEBUG
43 	if (_res.options & RES_DEBUG) {
44 		printf("res_send()\n");
45 		p_query(buf);
46 	}
47 #endif DEBUG
48 	if (!(_res.options & RES_INIT))
49 		if (res_init() == -1) {
50 			return(-1);
51 		}
52 	s = -1;
53 	v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
54 	id = hp->id;
55 	/*
56 	 * Send request, RETRY times, or until successful
57 	 */
58 	for (retry = _res.retry; --retry >= 0; ) {
59 	   for (ns = 0; ns < _res.nscount; ns++) {
60 #ifdef DEBUG
61 		if (_res.options & RES_DEBUG)
62 			printf("Querying server (# %d) address = %s\n", ns+1,
63 			      inet_ntoa(_res.nsaddr_list[ns].sin_addr.s_addr));
64 #endif DEBUG
65 		if (v_circuit) {
66 			/*
67 			 * Use virtual circuit.
68 			 */
69 			if (s < 0)
70 				s = socket(AF_INET, SOCK_STREAM, 0);
71 			if (connect(s, &(_res.nsaddr_list[ns]),
72 			   sizeof(struct sockaddr)) < 0) {
73 #ifdef DEBUG
74 				if (_res.options & RES_DEBUG)
75 					printf("connect failed %d\n", errno);
76 #endif DEBUG
77 				(void) close(s);
78 				s = -1;
79 				continue;
80 			}
81 			/*
82 			 * Send length & message
83 			 */
84 			len = htons(buflen);
85 			if (write(s, &len, sizeof(len)) != sizeof(len) ||
86 				    write(s, buf, buflen) != buflen) {
87 #ifdef DEBUG
88 				if (_res.options & RES_DEBUG)
89 					printf("write failed %d\n", errno);
90 #endif DEBUG
91 				(void) close(s);
92 				s = -1;
93 				continue;
94 			}
95 			/*
96 			 * Receive length & response
97 			 */
98 			cp = answer;
99 			len = sizeof(short);
100 			while (len > 0 && (n = read(s, cp, len)) > 0) {
101 				cp += n;
102 				len -= n;
103 			}
104 			if (n <= 0) {
105 #ifdef DEBUG
106 				if (_res.options & RES_DEBUG)
107 					printf("read failed %d\n", errno);
108 #endif DEBUG
109 				(void) close(s);
110 				s = -1;
111 				continue;
112 			}
113 			cp = answer;
114 			resplen = len = ntohs(*(short *)cp);
115 			while (len > 0 && (n = read(s, cp, len)) > 0) {
116 				cp += n;
117 				len -= n;
118 			}
119 			if (n <= 0) {
120 #ifdef DEBUG
121 				if (_res.options & RES_DEBUG)
122 					printf("read failed %d\n", errno);
123 #endif DEBUG
124 				(void) close(s);
125 				s = -1;
126 				continue;
127 			}
128 		} else {
129 			/*
130 			 * Use datagrams.
131 			 */
132 			if (s < 0)
133 				s = socket(AF_INET, SOCK_DGRAM, 0);
134 			if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns],
135 			    sizeof(struct sockaddr)) != buflen) {
136 #ifdef DEBUG
137 				if (_res.options & RES_DEBUG)
138 					printf("sendto errno = %d\n", errno);
139 #endif DEBUG
140 			}
141 			/*
142 			 * Wait for reply
143 			 */
144 			timeout.tv_sec =
145 				((_res.retrans * _res.retry) / _res.nscount);
146 			timeout.tv_usec = 0;
147 			dsmask = 1 << s;
148 			n = select(s+1, &dsmask, 0, 0, &timeout);
149 			if (n < 0) {
150 #ifdef DEBUG
151 				if (_res.options & RES_DEBUG)
152 					printf("select errno = %d\n", errno);
153 #endif DEBUG
154 				continue;
155 			}
156 			if (n == 0) {
157 				/*
158 				 * timeout
159 				 */
160 #ifdef DEBUG
161 				if (_res.options & RES_DEBUG)
162 					printf("timeout\n");
163 #endif DEBUG
164 				continue;
165 			}
166 			if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
167 #ifdef DEBUG
168 				if (_res.options & RES_DEBUG)
169 					printf("recvfrom, errno=%d\n", errno);
170 #endif DEBUG
171 				continue;
172 			}
173 			if (id != anhp->id) {
174 				/*
175 				 * response from old query, ignore it
176 				 */
177 #ifdef DEBUG
178 				if (_res.options & RES_DEBUG) {
179 					printf("old answer:\n");
180 					p_query(answer);
181 				}
182 #endif DEBUG
183 				continue;
184 			}
185 			if (!(_res.options & RES_IGNTC) && anhp->tc) {
186 				/*
187 				 * get rest of answer
188 				 */
189 #ifdef DEBUG
190 				if (_res.options & RES_DEBUG)
191 					printf("truncated answer\n");
192 #endif DEBUG
193 				(void) close(s);
194 				s = -1;
195 				retry = _res.retry;
196 				v_circuit = 1;
197 				continue;
198 			}
199 		}
200 #ifdef DEBUG
201 		if (_res.options & RES_DEBUG) {
202 			printf("got answer:\n");
203 			p_query(answer);
204 		}
205 #endif DEBUG
206 		(void) close(s);
207 		return (resplen);
208 	   }
209 	}
210 	(void) close(s);
211 	errno = ETIMEDOUT;
212 	return (-1);
213 }
214