integrate changes from bind 4.9 (most of them); continue to use address
[unix-history] / usr / src / lib / libc / net / res_send.c
CommitLineData
882ceeb2 1/*-
e9e1a1f3 2 * Copyright (c) 1985, 1989 Regents of the University of California.
6b2f9dd0
KB
3 * All rights reserved.
4 *
269a7923 5 * %sccs.include.redist.c%
882ceeb2
MK
6 * -
7 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies, and that
12 * the name of Digital Equipment Corporation not be used in advertising or
13 * publicity pertaining to distribution of the document or software without
14 * specific, written prior permission.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
17 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
19 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
20 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
21 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
22 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
23 * SOFTWARE.
24 * -
25 * --Copyright--
b423e985
RC
26 */
27
2ce81398 28#if defined(LIBC_SCCS) && !defined(lint)
882ceeb2
MK
29static char sccsid[] = "@(#)res_send.c 6.28 (Berkeley) %G%";
30static char rcsid[] = "$Id: res_send.c,v 4.9.1.1 1993/05/02 22:43:03 vixie Rel $";
6b2f9dd0 31#endif /* LIBC_SCCS and not lint */
8ea4199d 32
616a94ba
RC
33/*
34 * Send query to name server and wait for reply.
35 */
36
04a773cb 37#include <sys/param.h>
616a94ba
RC
38#include <sys/time.h>
39#include <sys/socket.h>
679f3274 40#include <sys/uio.h>
616a94ba 41#include <netinet/in.h>
24fac7d8 42#include <arpa/nameser.h>
882ceeb2 43#include <arpa/inet.h>
616a94ba
RC
44#include <stdio.h>
45#include <errno.h>
f94b2f50 46#include <resolv.h>
24fac7d8
KB
47#include <unistd.h>
48#include <string.h>
616a94ba 49
3126f4c0 50static int s = -1; /* socket used for communications */
9bb3997d 51static struct sockaddr no_addr;
15537e14
KD
52
53#ifndef FD_SET
54#define NFDBITS 32
55#define FD_SETSIZE 32
56#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
57#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
58#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
59#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
60#endif
3126f4c0 61
31f0ead0 62res_send(buf, buflen, answer, anslen)
24fac7d8 63 const char *buf;
616a94ba
RC
64 int buflen;
65 char *answer;
66 int anslen;
67{
68 register int n;
e9e1a1f3 69 int try, v_circuit, resplen, ns;
2344735f 70 int gotsomewhere = 0, connected = 0;
17b5e053 71 int connreset = 0;
616a94ba
RC
72 u_short id, len;
73 char *cp;
ac3ceb42 74 fd_set dsmask;
616a94ba
RC
75 struct timeval timeout;
76 HEADER *hp = (HEADER *) buf;
77 HEADER *anhp = (HEADER *) answer;
882ceeb2 78 u_int badns; /* XXX NSMAX can't exceed #/bits per this */
679f3274 79 struct iovec iov[2];
1ea504e8 80 int terrno = ETIMEDOUT;
2344735f 81 char junk[512];
616a94ba 82
ae94a224 83#ifdef DEBUG
882ceeb2
MK
84 if ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY)) {
85 printf(";; res_send()\n");
371d3c9b 86 __p_query(buf);
616a94ba 87 }
882ceeb2 88#endif
31f0ead0 89 if (!(_res.options & RES_INIT))
ae94a224
JB
90 if (res_init() == -1) {
91 return(-1);
92 }
616a94ba
RC
93 v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
94 id = hp->id;
882ceeb2 95 badns = 0;
616a94ba
RC
96 /*
97 * Send request, RETRY times, or until successful
98 */
e9e1a1f3 99 for (try = 0; try < _res.retry; try++) {
882ceeb2
MK
100 for (ns = 0; ns < _res.nscount; ns++) {
101 if (badns & (1<<ns))
102 continue;
0b8992ca
KD
103#ifdef DEBUG
104 if (_res.options & RES_DEBUG)
882ceeb2
MK
105 printf(";; Querying server (# %d) address = %s\n",
106 ns+1,
107 inet_ntoa(_res.nsaddr_list[ns].sin_addr));
108#endif
e9e1a1f3 109 usevc:
616a94ba 110 if (v_circuit) {
2344735f
MK
111 int truncated = 0;
112
616a94ba 113 /*
e9e1a1f3
MK
114 * Use virtual circuit;
115 * at most one attempt per server.
616a94ba 116 */
e9e1a1f3 117 try = _res.retry;
a5d4a4c0 118 if (s < 0) {
616a94ba 119 s = socket(AF_INET, SOCK_STREAM, 0);
92a82fe4 120 if (s < 0) {
1ea504e8 121 terrno = errno;
92a82fe4
MK
122#ifdef DEBUG
123 if (_res.options & RES_DEBUG)
f7d00d5e 124 perror("socket (vc) failed");
882ceeb2 125#endif
92a82fe4
MK
126 continue;
127 }
24fac7d8
KB
128 if (connect(s,
129 (struct sockaddr *)&(_res.nsaddr_list[ns]),
130 sizeof(struct sockaddr)) < 0) {
1ea504e8 131 terrno = errno;
ae94a224 132#ifdef DEBUG
a5d4a4c0 133 if (_res.options & RES_DEBUG)
747d796e 134 perror("connect failed");
882ceeb2 135#endif
a5d4a4c0
JB
136 (void) close(s);
137 s = -1;
138 continue;
139 }
616a94ba
RC
140 }
141 /*
142 * Send length & message
143 */
3126f4c0 144 len = htons((u_short)buflen);
679f3274
JB
145 iov[0].iov_base = (caddr_t)&len;
146 iov[0].iov_len = sizeof(len);
24fac7d8 147 iov[1].iov_base = (char *)buf;
679f3274
JB
148 iov[1].iov_len = buflen;
149 if (writev(s, iov, 2) != sizeof(len) + buflen) {
1ea504e8 150 terrno = errno;
ae94a224 151#ifdef DEBUG
616a94ba 152 if (_res.options & RES_DEBUG)
747d796e 153 perror("write failed");
882ceeb2 154#endif
616a94ba
RC
155 (void) close(s);
156 s = -1;
157 continue;
158 }
159 /*
160 * Receive length & response
161 */
162 cp = answer;
163 len = sizeof(short);
679f3274 164 while (len != 0 &&
747d796e 165 (n = read(s, (char *)cp, (int)len)) > 0) {
616a94ba
RC
166 cp += n;
167 len -= n;
168 }
169 if (n <= 0) {
1ea504e8 170 terrno = errno;
ae94a224 171#ifdef DEBUG
616a94ba 172 if (_res.options & RES_DEBUG)
747d796e 173 perror("read failed");
882ceeb2 174#endif
616a94ba
RC
175 (void) close(s);
176 s = -1;
17b5e053
JB
177 /*
178 * A long running process might get its TCP
179 * connection reset if the remote server was
180 * restarted. Requery the server instead of
181 * trying a new one. When there is only one
182 * server, this means that a query might work
183 * instead of failing. We only allow one reset
184 * per query to prevent looping.
185 */
186 if (terrno == ECONNRESET && !connreset) {
187 connreset = 1;
188 ns--;
189 }
616a94ba
RC
190 continue;
191 }
192 cp = answer;
2344735f
MK
193 if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
194#ifdef DEBUG
195 if (_res.options & RES_DEBUG)
882ceeb2
MK
196 fprintf(stderr,
197 ";; response truncated\n");
198#endif
2344735f
MK
199 len = anslen;
200 truncated = 1;
201 } else
202 len = resplen;
679f3274 203 while (len != 0 &&
747d796e 204 (n = read(s, (char *)cp, (int)len)) > 0) {
616a94ba
RC
205 cp += n;
206 len -= n;
207 }
208 if (n <= 0) {
1ea504e8 209 terrno = errno;
ae94a224 210#ifdef DEBUG
616a94ba 211 if (_res.options & RES_DEBUG)
747d796e 212 perror("read failed");
882ceeb2 213#endif
616a94ba
RC
214 (void) close(s);
215 s = -1;
216 continue;
217 }
2344735f
MK
218 if (truncated) {
219 /*
220 * Flush rest of answer
221 * so connection stays in synch.
222 */
223 anhp->tc = 1;
224 len = resplen - anslen;
225 while (len != 0) {
226 n = (len > sizeof(junk) ?
227 sizeof(junk) : len);
228 if ((n = read(s, junk, n)) > 0)
229 len -= n;
230 else
231 break;
232 }
233 }
616a94ba
RC
234 } else {
235 /*
236 * Use datagrams.
237 */
f7d00d5e 238 if (s < 0) {
616a94ba 239 s = socket(AF_INET, SOCK_DGRAM, 0);
f7d00d5e
JB
240 if (s < 0) {
241 terrno = errno;
242#ifdef DEBUG
243 if (_res.options & RES_DEBUG)
244 perror("socket (dg) failed");
882ceeb2 245#endif
f7d00d5e
JB
246 continue;
247 }
248 }
e9e1a1f3
MK
249 /*
250 * I'm tired of answering this question, so:
251 * On a 4.3BSD+ machine (client and server,
252 * actually), sending to a nameserver datagram
253 * port with no nameserver will cause an
254 * ICMP port unreachable message to be returned.
255 * If our datagram socket is "connected" to the
256 * server, we get an ECONNREFUSED error on the next
257 * socket operation, and select returns if the
258 * error message is received. We can thus detect
259 * the absence of a nameserver without timing out.
260 * If we have sent queries to at least two servers,
261 * however, we don't want to remain connected,
262 * as we wish to receive answers from the first
263 * server to respond.
264 */
265 if (_res.nscount == 1 || (try == 0 && ns == 0)) {
7a8f7802 266 /*
9bb3997d
MK
267 * Don't use connect if we might
268 * still receive a response
269 * from another server.
7a8f7802 270 */
2344735f 271 if (connected == 0) {
882ceeb2
MK
272 if (connect(s,
273 (struct sockaddr *)
274 &_res.nsaddr_list[ns],
2344735f
MK
275 sizeof(struct sockaddr)) < 0) {
276#ifdef DEBUG
277 if (_res.options & RES_DEBUG)
278 perror("connect");
882ceeb2 279#endif
2344735f
MK
280 continue;
281 }
282 connected = 1;
283 }
284 if (send(s, buf, buflen, 0) != buflen) {
ae94a224 285#ifdef DEBUG
7a8f7802 286 if (_res.options & RES_DEBUG)
2344735f 287 perror("send");
882ceeb2 288#endif
7a8f7802
KD
289 continue;
290 }
fee59cfd
MK
291 } else {
292 /*
293 * Disconnect if we want to listen
294 * for responses from more than one server.
295 */
296 if (connected) {
297 (void) connect(s, &no_addr,
298 sizeof(no_addr));
299 connected = 0;
300 }
fee59cfd 301 if (sendto(s, buf, buflen, 0,
24fac7d8 302 (struct sockaddr *)&_res.nsaddr_list[ns],
fee59cfd 303 sizeof(struct sockaddr)) != buflen) {
92a82fe4 304#ifdef DEBUG
fee59cfd
MK
305 if (_res.options & RES_DEBUG)
306 perror("sendto");
882ceeb2 307#endif
fee59cfd
MK
308 continue;
309 }
616a94ba 310 }
7a8f7802 311
616a94ba 312 /*
747d796e 313 * Wait for reply
616a94ba 314 */
e9e1a1f3
MK
315 timeout.tv_sec = (_res.retrans << try);
316 if (try > 0)
317 timeout.tv_sec /= _res.nscount;
882ceeb2 318 if ((long) timeout.tv_sec <= 0)
747d796e 319 timeout.tv_sec = 1;
616a94ba 320 timeout.tv_usec = 0;
87b12937 321wait:
ac3ceb42
KD
322 FD_ZERO(&dsmask);
323 FD_SET(s, &dsmask);
679f3274
JB
324 n = select(s+1, &dsmask, (fd_set *)NULL,
325 (fd_set *)NULL, &timeout);
616a94ba 326 if (n < 0) {
ae94a224 327#ifdef DEBUG
616a94ba 328 if (_res.options & RES_DEBUG)
747d796e 329 perror("select");
882ceeb2 330#endif
616a94ba
RC
331 continue;
332 }
333 if (n == 0) {
334 /*
335 * timeout
336 */
ae94a224 337#ifdef DEBUG
616a94ba 338 if (_res.options & RES_DEBUG)
882ceeb2 339 printf(";; timeout\n");
e9e1a1f3 340#endif
882ceeb2 341 gotsomewhere = 1;
616a94ba
RC
342 continue;
343 }
dd7a6a73 344 if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
ae94a224 345#ifdef DEBUG
616a94ba 346 if (_res.options & RES_DEBUG)
747d796e 347 perror("recvfrom");
882ceeb2 348#endif
616a94ba
RC
349 continue;
350 }
92a82fe4 351 gotsomewhere = 1;
616a94ba
RC
352 if (id != anhp->id) {
353 /*
354 * response from old query, ignore it
355 */
ae94a224 356#ifdef DEBUG
882ceeb2
MK
357 if ((_res.options & RES_DEBUG) ||
358 (_res.pfcode & RES_PRF_REPLY)) {
359 printf(";; old answer:\n");
371d3c9b 360 __p_query(answer);
616a94ba 361 }
882ceeb2 362#endif
87b12937 363 goto wait;
616a94ba 364 }
882ceeb2
MK
365 if (anhp->rcode == SERVFAIL || anhp->rcode == NOTIMP ||
366 anhp->rcode == REFUSED) {
367#ifdef DEBUG
368 if (_res.options & RES_DEBUG) {
369 printf("server rejected query:\n");
370 __p_query(answer);
371 }
372#endif
373 badns |= (1<<ns);
374 continue;
375 }
616a94ba
RC
376 if (!(_res.options & RES_IGNTC) && anhp->tc) {
377 /*
e9e1a1f3
MK
378 * get rest of answer;
379 * use TCP with same server.
616a94ba 380 */
ae94a224 381#ifdef DEBUG
616a94ba 382 if (_res.options & RES_DEBUG)
882ceeb2
MK
383 printf(";; truncated answer\n");
384#endif
616a94ba
RC
385 (void) close(s);
386 s = -1;
616a94ba 387 v_circuit = 1;
e9e1a1f3 388 goto usevc;
616a94ba
RC
389 }
390 }
ae94a224 391#ifdef DEBUG
882ceeb2
MK
392 if (_res.options & RES_DEBUG)
393 printf(";; got answer:\n");
394 if ((_res.options & RES_DEBUG) ||
395 (_res.pfcode & RES_PRF_REPLY))
371d3c9b 396 __p_query(answer);
882ceeb2 397#endif
a5d4a4c0 398 /*
e9e1a1f3
MK
399 * If using virtual circuits, we assume that the first server
400 * is preferred * over the rest (i.e. it is on the local
401 * machine) and only keep that one open.
402 * If we have temporarily opened a virtual circuit,
403 * or if we haven't been asked to keep a socket open,
404 * close the socket.
a5d4a4c0 405 */
e9e1a1f3
MK
406 if ((v_circuit &&
407 ((_res.options & RES_USEVC) == 0 || ns != 0)) ||
408 (_res.options & RES_STAYOPEN) == 0) {
a5d4a4c0
JB
409 (void) close(s);
410 s = -1;
a5d4a4c0 411 }
fee59cfd 412 return (resplen);
0b8992ca 413 }
616a94ba 414 }
1ea504e8
JB
415 if (s >= 0) {
416 (void) close(s);
417 s = -1;
418 }
419 if (v_circuit == 0)
420 if (gotsomewhere == 0)
e9e1a1f3 421 errno = ECONNREFUSED; /* no nameservers found */
1ea504e8 422 else
e9e1a1f3 423 errno = ETIMEDOUT; /* no answer obtained */
92a82fe4 424 else
1ea504e8 425 errno = terrno;
616a94ba
RC
426 return (-1);
427}
3126f4c0
JB
428
429/*
430 * This routine is for closing the socket if a virtual circuit is used and
431 * the program wants to close it. This provides support for endhostent()
432 * which expects to close the socket.
433 *
434 * This routine is not expected to be user visible.
435 */
436_res_close()
437{
438 if (s != -1) {
439 (void) close(s);
440 s = -1;
441 }
442}