6811333 Remove prom_printf() message in emlxs driver
[opensolaris.git] / usr / src / lib / libresolv / res_send.c
blob6bd187b2107c7c0f49540e3cee3f187a1045be0f
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
33 * All Rights Reserved
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
37 * contributors.
40 #pragma ident "%Z%%M% %I% %E% SMI"
43 * Send query to name server and wait for reply.
46 #include <sys/param.h>
47 #include <sys/time.h>
48 #include <sys/socket.h>
49 #include <sys/uio.h>
50 #include <sys/stat.h>
51 #include <netinet/in.h>
52 #include <stdio.h>
53 #include <errno.h>
54 #include <arpa/nameser.h>
55 #include <resolv.h>
58 static int s = -1; /* socket used for communications */
59 static struct sockaddr no_addr;
62 #ifndef FD_SET
63 #define NFDBITS 32
64 #define FD_SETSIZE 32
65 #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
66 #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
67 #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
68 #ifdef SYSV
69 #define FD_ZERO(p) memset((void *)(p), 0, sizeof (*(p)))
70 #else
71 #define FD_ZERO(p) bzero((char *)(p), sizeof (*(p)))
72 #endif
73 #endif
76 * 1247019: Kludge to time out quickly if there is no /etc/resolv.conf
77 * and a TCP connection to the local DNS server fails.
80 static int _confcheck()
82 int ns;
83 struct stat rc_stat;
84 struct sockaddr_in ns_sin;
87 /* First, we check to see if /etc/resolv.conf exists.
88 * If it doesn't, then localhost is mostlikely to be
89 * the nameserver.
91 if (stat(_PATH_RESCONF, &rc_stat) == -1 && errno == ENOENT) {
93 /* Next, we check to see if _res.nsaddr is set to loopback.
94 * If it isn't, it has been altered by the application
95 * explicitly and we then want to bail with success.
97 if (_res.nsaddr.sin_addr.S_un.S_addr == htonl(INADDR_LOOPBACK)) {
99 /* Lastly, we try to connect to the TCP port of the
100 * nameserver. If this fails, then we know that
101 * DNS is misconfigured and we can quickly exit.
103 ns = socket(AF_INET, SOCK_STREAM, 0);
104 IN_SET_LOOPBACK_ADDR(&ns_sin);
105 ns_sin.sin_port = htons(NAMESERVER_PORT);
106 if (connect(ns, (struct sockaddr *) &ns_sin,
107 sizeof ns_sin) == -1) {
108 close(ns);
109 return(-1);
111 else {
112 close(ns);
113 return(0);
117 return(0);
120 return (0);
124 res_send(buf, buflen, answer, anslen)
125 char *buf;
126 int buflen;
127 char *answer;
128 int anslen;
130 register int n;
131 int try, v_circuit, resplen, ns;
132 int gotsomewhere = 0, connected = 0;
133 int connreset = 0;
134 u_short id, len;
135 char *cp;
136 fd_set dsmask;
137 struct timeval timeout;
138 HEADER *hp = (HEADER *) buf;
139 HEADER *anhp = (HEADER *) answer;
140 struct iovec iov[2];
141 int terrno = ETIMEDOUT;
142 char junk[512];
144 #ifdef DEBUG
145 if (_res.options & RES_DEBUG) {
146 printf("res_send()\n");
147 p_query(buf);
149 #endif
150 if (!(_res.options & RES_INIT))
151 if (res_init() == -1) {
152 return (-1);
155 /* 1247019: Check to see if we can bailout quickly. */
156 if (_confcheck() == -1)
157 return(-1);
159 v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
160 id = hp->id;
162 * Send request, RETRY times, or until successful
164 for (try = 0; try < _res.retry; try++) {
165 for (ns = 0; ns < _res.nscount; ns++) {
166 #ifdef DEBUG
167 if (_res.options & RES_DEBUG)
168 printf("Querying server (# %d) address = %s\n",
169 ns+1, inet_ntoa(_res.nsaddr_list[ns].sin_addr));
170 #endif
171 usevc:
172 if (v_circuit) {
173 int truncated = 0;
176 * Use virtual circuit;
177 * at most one attempt per server.
179 try = _res.retry;
180 if (s < 0) {
181 s = _socket(AF_INET, SOCK_STREAM, 0);
182 if (s < 0) {
183 terrno = errno;
184 #ifdef DEBUG
185 if (_res.options & RES_DEBUG) {
186 perror("socket (vc) failed");
188 #endif
189 continue;
191 if (connect(s, (struct sockaddr *) &_res.nsaddr_list[ns],
192 sizeof (struct sockaddr)) < 0) {
193 terrno = errno;
194 #ifdef DEBUG
195 if (_res.options & RES_DEBUG) {
196 perror("connect failed");
198 #endif
199 (void) close(s);
200 s = -1;
201 continue;
205 * Send length & message
207 len = htons((u_short)buflen);
208 iov[0].iov_base = (caddr_t)&len;
209 iov[0].iov_len = sizeof (len);
210 iov[1].iov_base = buf;
211 iov[1].iov_len = buflen;
212 if (writev(s, iov, 2) != sizeof (len) +
213 buflen) {
214 terrno = errno;
215 #ifdef DEBUG
216 if (_res.options & RES_DEBUG)
217 perror("write failed");
218 #endif
219 (void) close(s);
220 s = -1;
221 continue;
224 * Receive length & response
226 cp = answer;
227 len = sizeof (short);
228 while (len != 0 && (n = read
229 (s, (char *)cp, (int)len)) > 0) {
230 cp += n;
231 len -= n;
233 if (n <= 0) {
234 terrno = errno;
235 #ifdef DEBUG
236 if (_res.options & RES_DEBUG)
237 perror("read failed");
238 #endif
239 (void) close(s);
240 s = -1;
242 * A long running process might get its TCP
243 * connection reset if the remote server was
244 * restarted. Requery the server instead of
245 * trying a new one. When there is only one
246 * server, this means that a query might work
247 * instead of failing. We only allow one reset
248 * per query to prevent looping.
250 if (terrno == ECONNRESET &&
251 !connreset) {
252 connreset = 1;
253 ns--;
255 continue;
257 cp = answer;
258 if ((resplen = ntohs(*(u_short *)cp)) >
259 anslen) {
260 #ifdef DEBUG
261 if (_res.options & RES_DEBUG)
262 fprintf(stderr,
263 "response truncated\n");
264 #endif
265 len = anslen;
266 truncated = 1;
267 } else
268 len = resplen;
269 while (len != 0 &&
270 (n = read(s, (char *)cp,
271 (int)len)) > 0) {
272 cp += n;
273 len -= n;
275 if (n <= 0) {
276 terrno = errno;
277 #ifdef DEBUG
278 if (_res.options & RES_DEBUG)
279 perror("read failed");
280 #endif
281 (void) close(s);
282 s = -1;
283 continue;
285 if (truncated) {
287 * Flush rest of answer
288 * so connection stays in synch.
290 anhp->tc = 1;
291 len = resplen - anslen;
293 * set the value of resplen to anslen,
294 * this is done because the caller
295 * assumes resplen contains the size of
296 * message read into the "answer" buffer
297 * passed in.
299 resplen = anslen;
301 while (len != 0) {
302 n = (len > sizeof (junk) ?
303 sizeof (junk) : len);
304 if ((n = read(s, junk, n)) > 0)
305 len -= n;
306 else
307 break;
310 } else {
312 * Use datagrams.
314 if (s < 0) {
315 s = _socket(AF_INET, SOCK_DGRAM, 0);
316 if (s < 0) {
317 terrno = errno;
318 #ifdef DEBUG
319 if (_res.options & RES_DEBUG) {
320 perror("socket (dg) failed");
322 #endif
323 continue;
326 #if BSD >= 43
328 * I'm tired of answering this question, so:
329 * On a 4.3BSD+ machine (client and server,
330 * actually), sending to a nameserver datagram
331 * port with no nameserver will cause an
332 * ICMP port unreachable message to be returned.
333 * If our datagram socket is "connected" to the
334 * server, we get an ECONNREFUSED error on the next
335 * socket operation, and select returns if the
336 * error message is received. We can thus detect
337 * the absence of a nameserver without timing out.
338 * If we have sent queries to at least two servers,
339 * however, we don't want to remain connected,
340 * as we wish to receive answers from the first
341 * server to respond.
343 if (_res.nscount == 1 ||
344 (try == 0 && ns == 0)) {
346 * Don't use connect if we might
347 * still receive a response
348 * from another server.
350 if (connected == 0) {
351 if (connect(s,
352 (struct sockaddr *) &_res.nsaddr_list[ns],
353 sizeof (struct sockaddr)) < 0) {
354 #ifdef DEBUG
355 if (_res.options &
356 RES_DEBUG) {
357 perror("connect");
359 #endif
360 continue;
362 connected = 1;
364 if (send(s, buf, buflen, 0) != buflen) {
365 #ifdef DEBUG
366 if (_res.options & RES_DEBUG)
367 perror("send");
368 #endif
369 continue;
371 } else {
373 * Disconnect if we want to listen for
374 * responses from more than one server.
376 if (connected) {
377 (void) connect(s, &no_addr,
378 sizeof (no_addr));
379 connected = 0;
381 #endif /* BSD */
382 if (sendto(s, buf, buflen, 0,
383 (struct sockaddr *) &_res.nsaddr_list[ns],
384 sizeof (struct sockaddr)) != buflen) {
385 #ifdef DEBUG
386 if (_res.options & RES_DEBUG)
387 perror("sendto");
388 #endif
389 continue;
391 #if BSD >= 43
393 #endif
396 * Wait for reply
398 timeout.tv_sec = (_res.retrans << try);
399 if (try > 0)
400 timeout.tv_sec /= _res.nscount;
401 if (timeout.tv_sec <= 0)
402 timeout.tv_sec = 1;
403 timeout.tv_usec = 0;
404 wait:
405 FD_ZERO(&dsmask);
406 FD_SET(s, &dsmask);
407 n = select(s+1, &dsmask, (fd_set *)NULL,
408 (fd_set *)NULL, &timeout);
409 if (n < 0) {
410 #ifdef DEBUG
411 if (_res.options & RES_DEBUG)
412 perror("select");
413 #endif
414 continue;
416 if (n == 0) {
418 * timeout
420 #ifdef DEBUG
421 if (_res.options & RES_DEBUG)
422 printf("timeout\n");
423 #endif
424 #if BSD >= 43
425 gotsomewhere = 1;
426 #endif
427 continue;
429 if ((resplen = recv(s, answer, anslen, 0))
430 <= 0) {
431 #ifdef DEBUG
432 if (_res.options & RES_DEBUG)
433 perror("recvfrom");
434 #endif
435 continue;
437 gotsomewhere = 1;
438 if (id != anhp->id) {
440 * response from old query, ignore it
442 #ifdef DEBUG
443 if (_res.options & RES_DEBUG) {
444 printf("old answer:\n");
445 p_query(answer);
447 #endif
448 goto wait;
450 if (!(_res.options & RES_IGNTC) && anhp->tc) {
452 * get rest of answer;
453 * use TCP with same server.
455 #ifdef DEBUG
456 if (_res.options & RES_DEBUG)
457 printf("truncated answer\n");
458 #endif
459 (void) close(s);
460 s = -1;
461 v_circuit = 1;
462 goto usevc;
465 #ifdef DEBUG
466 if (_res.options & RES_DEBUG) {
467 printf("got answer:\n");
468 p_query(answer);
470 #endif
472 * If using virtual circuits, we assume that the first server
473 * is preferred * over the rest (i.e. it is on the local
474 * machine) and only keep that one open.
475 * If we have temporarily opened a virtual circuit,
476 * or if we haven't been asked to keep a socket open,
477 * close the socket.
479 if ((v_circuit &&
480 ((_res.options & RES_USEVC) == 0 || ns != 0)) ||
481 (_res.options & RES_STAYOPEN) == 0) {
482 (void) close(s);
483 s = -1;
485 return (resplen);
488 if (s >= 0) {
489 (void) close(s);
490 s = -1;
492 if (v_circuit == 0)
493 if (gotsomewhere == 0)
494 errno = ECONNREFUSED; /* no nameservers found */
495 else
496 errno = ETIMEDOUT; /* no answer obtained */
497 else
498 errno = terrno;
499 return (-1);
503 * This routine is for closing the socket if a virtual circuit is used and
504 * the program wants to close it. This provides support for endhostent()
505 * which expects to close the socket.
507 * This routine is not expected to be user visible.
509 void
510 _res_close()
512 if (s != -1) {
513 (void) close(s);
514 s = -1;