Accept freebsd as OS.
[glibc/history.git] / resolv / res_send.c
blob65763fddb87692739ca819fbb2deefacc0f15276
1 /*
2 * ++Copyright++ 1985, 1989
3 * -
4 * Copyright (c) 1985, 1989 Regents of the University of California.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 * -
35 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
37 * Permission to use, copy, modify, and distribute this software for any
38 * purpose with or without fee is hereby granted, provided that the above
39 * copyright notice and this permission notice appear in all copies, and that
40 * the name of Digital Equipment Corporation not be used in advertising or
41 * publicity pertaining to distribution of the document or software without
42 * specific, written prior permission.
44 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
45 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
46 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
47 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
48 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
49 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
50 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
51 * SOFTWARE.
52 * -
53 * --Copyright--
56 #if defined(LIBC_SCCS) && !defined(lint)
57 static char sccsid[] = "@(#)res_send.c 6.27 (Berkeley) 2/24/91";
58 static char rcsid[] = "$Id$";
59 #endif /* LIBC_SCCS and not lint */
62 * Send query to name server and wait for reply.
65 #include <sys/param.h>
66 #include <sys/time.h>
67 #include <sys/socket.h>
68 #include <sys/uio.h>
69 #include <netinet/in.h>
70 #include <arpa/nameser.h>
71 #include <arpa/inet.h>
72 #include <stdio.h>
73 #include <errno.h>
74 #include <resolv.h>
75 #include "../conf/portability.h"
77 static int s = -1; /* socket used for communications */
78 static struct sockaddr no_addr;
80 #ifndef FD_SET
81 #define NFDBITS 32
82 #define FD_SETSIZE 32
83 #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
84 #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
85 #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
86 #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
87 #endif
89 res_send(buf, buflen, answer, anslen)
90 const char *buf;
91 int buflen;
92 char *answer;
93 int anslen;
95 register int n;
96 int try, v_circuit, resplen, ns;
97 int gotsomewhere = 0, connected = 0;
98 int connreset = 0;
99 u_short id, len;
100 char *cp;
101 fd_set dsmask;
102 struct timeval timeout;
103 HEADER *hp = (HEADER *) buf;
104 HEADER *anhp = (HEADER *) answer;
105 u_int badns; /* XXX NSMAX can't exceed #/bits per this */
106 struct iovec iov[2];
107 int terrno = ETIMEDOUT;
108 char junk[512];
110 #ifdef DEBUG
111 if ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY)) {
112 printf(";; res_send()\n");
113 __p_query(buf);
115 #endif
116 if (!(_res.options & RES_INIT))
117 if (res_init() == -1) {
118 return(-1);
120 v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
121 id = hp->id;
122 badns = 0;
124 * Send request, RETRY times, or until successful
126 for (try = 0; try < _res.retry; try++) {
127 for (ns = 0; ns < _res.nscount; ns++) {
128 if (badns & (1<<ns))
129 continue;
130 #ifdef DEBUG
131 if (_res.options & RES_DEBUG)
132 printf(";; Querying server (# %d) address = %s\n",
133 ns+1,
134 inet_ntoa(_res.nsaddr_list[ns].sin_addr));
135 #endif
136 usevc:
137 if (v_circuit) {
138 int truncated = 0;
141 * Use virtual circuit;
142 * at most one attempt per server.
144 try = _res.retry;
145 if (s < 0) {
146 s = socket(AF_INET, SOCK_STREAM, 0);
147 if (s < 0) {
148 terrno = errno;
149 #ifdef DEBUG
150 if (_res.options & RES_DEBUG)
151 perror("socket (vc) failed");
152 #endif
153 continue;
155 if (connect(s,
156 (struct sockaddr *)&(_res.nsaddr_list[ns]),
157 sizeof(struct sockaddr)) < 0) {
158 terrno = errno;
159 #ifdef DEBUG
160 if (_res.options & RES_DEBUG)
161 perror("connect failed");
162 #endif
163 (void) close(s);
164 s = -1;
165 continue;
169 * Send length & message
171 len = htons((u_short)buflen);
172 iov[0].iov_base = (caddr_t)&len;
173 iov[0].iov_len = sizeof(len);
174 iov[1].iov_base = (char *)buf;
175 iov[1].iov_len = buflen;
176 if (writev(s, iov, 2) != sizeof(len) + buflen) {
177 terrno = errno;
178 #ifdef DEBUG
179 if (_res.options & RES_DEBUG)
180 perror("write failed");
181 #endif
182 (void) close(s);
183 s = -1;
184 continue;
187 * Receive length & response
189 cp = answer;
190 len = sizeof(short);
191 while (len != 0 &&
192 (n = read(s, (char *)cp, (int)len)) > 0) {
193 cp += n;
194 len -= n;
196 if (n <= 0) {
197 terrno = errno;
198 #ifdef DEBUG
199 if (_res.options & RES_DEBUG)
200 perror("read failed");
201 #endif
202 (void) close(s);
203 s = -1;
205 * A long running process might get its TCP
206 * connection reset if the remote server was
207 * restarted. Requery the server instead of
208 * trying a new one. When there is only one
209 * server, this means that a query might work
210 * instead of failing. We only allow one reset
211 * per query to prevent looping.
213 if (terrno == ECONNRESET && !connreset) {
214 connreset = 1;
215 ns--;
217 continue;
219 cp = answer;
220 if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
221 #ifdef DEBUG
222 if (_res.options & RES_DEBUG)
223 fprintf(stderr,
224 ";; response truncated\n");
225 #endif
226 len = anslen;
227 truncated = 1;
228 } else
229 len = resplen;
230 while (len != 0 &&
231 (n = read(s, (char *)cp, (int)len)) > 0) {
232 cp += n;
233 len -= n;
235 if (n <= 0) {
236 terrno = errno;
237 #ifdef DEBUG
238 if (_res.options & RES_DEBUG)
239 perror("read failed");
240 #endif
241 (void) close(s);
242 s = -1;
243 continue;
245 if (truncated) {
247 * Flush rest of answer
248 * so connection stays in synch.
250 anhp->tc = 1;
251 len = resplen - anslen;
252 while (len != 0) {
253 n = (len > sizeof(junk) ?
254 sizeof(junk) : len);
255 if ((n = read(s, junk, n)) > 0)
256 len -= n;
257 else
258 break;
261 } else {
263 * Use datagrams.
265 if (s < 0) {
266 s = socket(AF_INET, SOCK_DGRAM, 0);
267 if (s < 0) {
268 terrno = errno;
269 #ifdef DEBUG
270 if (_res.options & RES_DEBUG)
271 perror("socket (dg) failed");
272 #endif
273 continue;
276 #if BSD >= 43
278 * I'm tired of answering this question, so:
279 * On a 4.3BSD+ machine (client and server,
280 * actually), sending to a nameserver datagram
281 * port with no nameserver will cause an
282 * ICMP port unreachable message to be returned.
283 * If our datagram socket is "connected" to the
284 * server, we get an ECONNREFUSED error on the next
285 * socket operation, and select returns if the
286 * error message is received. We can thus detect
287 * the absence of a nameserver without timing out.
288 * If we have sent queries to at least two servers,
289 * however, we don't want to remain connected,
290 * as we wish to receive answers from the first
291 * server to respond.
293 if (_res.nscount == 1 || (try == 0 && ns == 0)) {
295 * Don't use connect if we might
296 * still receive a response
297 * from another server.
299 if (connected == 0) {
300 if (connect(s,
301 (struct sockaddr *)
302 &_res.nsaddr_list[ns],
303 sizeof(struct sockaddr)
304 ) < 0) {
305 #ifdef DEBUG
306 if (_res.options & RES_DEBUG)
307 perror("connect");
308 #endif
309 continue;
311 connected = 1;
313 if (send(s, buf, buflen, 0) != buflen) {
314 #ifdef DEBUG
315 if (_res.options & RES_DEBUG)
316 perror("send");
317 #endif
318 continue;
320 } else {
322 * Disconnect if we want to listen
323 * for responses from more than one server.
325 if (connected) {
326 (void) connect(s, &no_addr,
327 sizeof(no_addr));
328 connected = 0;
330 #endif /* BSD */
331 if (sendto(s, buf, buflen, 0,
332 (struct sockaddr *)&_res.nsaddr_list[ns],
333 sizeof(struct sockaddr)) != buflen) {
334 #ifdef DEBUG
335 if (_res.options & RES_DEBUG)
336 perror("sendto");
337 #endif
338 continue;
340 #if BSD >= 43
342 #endif
345 * Wait for reply
347 timeout.tv_sec = (_res.retrans << try);
348 if (try > 0)
349 timeout.tv_sec /= _res.nscount;
350 if ((long) timeout.tv_sec <= 0)
351 timeout.tv_sec = 1;
352 timeout.tv_usec = 0;
353 wait:
354 FD_ZERO(&dsmask);
355 FD_SET(s, &dsmask);
356 n = select(s+1, &dsmask, (fd_set *)NULL,
357 (fd_set *)NULL, &timeout);
358 if (n < 0) {
359 #ifdef DEBUG
360 if (_res.options & RES_DEBUG)
361 perror("select");
362 #endif
363 continue;
365 if (n == 0) {
367 * timeout
369 #ifdef DEBUG
370 if (_res.options & RES_DEBUG)
371 printf(";; timeout\n");
372 #endif
373 #if BSD >= 43
374 gotsomewhere = 1;
375 #endif
376 continue;
378 if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
379 #ifdef DEBUG
380 if (_res.options & RES_DEBUG)
381 perror("recvfrom");
382 #endif
383 continue;
385 gotsomewhere = 1;
386 if (id != anhp->id) {
388 * response from old query, ignore it
390 #ifdef DEBUG
391 if ((_res.options & RES_DEBUG) ||
392 (_res.pfcode & RES_PRF_REPLY)) {
393 printf(";; old answer:\n");
394 __p_query(answer);
396 #endif
397 goto wait;
399 if (anhp->rcode == SERVFAIL
400 || anhp->rcode == NOTIMP
401 || anhp->rcode == REFUSED) {
402 #ifdef DEBUG
403 if (_res.options & RES_DEBUG) {
404 printf("server rejected query:\n");
405 __p_query(answer);
407 #endif DEBUG
408 badns |= (1<<ns);
409 continue;
411 if (!(_res.options & RES_IGNTC) && anhp->tc) {
413 * get rest of answer;
414 * use TCP with same server.
416 #ifdef DEBUG
417 if (_res.options & RES_DEBUG)
418 printf(";; truncated answer\n");
419 #endif
420 (void) close(s);
421 s = -1;
422 v_circuit = 1;
423 goto usevc;
426 #ifdef DEBUG
427 if (_res.options & RES_DEBUG)
428 printf(";; got answer:\n");
429 if ((_res.options & RES_DEBUG)
430 || (_res.pfcode & RES_PRF_REPLY)) {
431 __p_query(answer);
433 #endif
435 * If using virtual circuits, we assume that the first server
436 * is preferred * over the rest (i.e. it is on the local
437 * machine) and only keep that one open.
438 * If we have temporarily opened a virtual circuit,
439 * or if we haven't been asked to keep a socket open,
440 * close the socket.
442 if ((v_circuit &&
443 ((_res.options & RES_USEVC) == 0 || ns != 0)) ||
444 (_res.options & RES_STAYOPEN) == 0) {
445 (void) close(s);
446 s = -1;
448 return (resplen);
451 if (s >= 0) {
452 (void) close(s);
453 s = -1;
455 if (v_circuit == 0)
456 if (gotsomewhere == 0)
457 errno = ECONNREFUSED; /* no nameservers found */
458 else
459 errno = ETIMEDOUT; /* no answer obtained */
460 else
461 errno = terrno;
462 return (-1);
466 * This routine is for closing the socket if a virtual circuit is used and
467 * the program wants to close it. This provides support for endhostent()
468 * which expects to close the socket.
470 * This routine is not expected to be user visible.
472 _res_close()
474 if (s != -1) {
475 (void) close(s);
476 s = -1;