|
|
1.1 root 1: /*
2: * Copyright (c) 1985, 1989 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted
6: * provided that: (1) source distributions retain this entire copyright
7: * notice and comment, and (2) distributions including binaries display
8: * the following acknowledgement: ``This product includes software
9: * developed by the University of California, Berkeley and its contributors''
10: * in the documentation or other materials provided with the distribution
11: * and in all advertising materials mentioning features or use of this
12: * software. Neither the name of the University nor the names of its
13: * contributors may be used to endorse or promote products derived
14: * from this software without specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #if defined(LIBC_SCCS) && !defined(lint)
21: static char sccsid[] = "@(#)res_send.c 6.25 (Berkeley) 6/1/90";
22: #endif /* LIBC_SCCS and not lint */
23:
24: /*
25: * Send query to name server and wait for reply.
26: */
27:
28: #include <sys/param.h>
29: #include <sys/time.h>
30: #include <sys/socket.h>
31: #include <sys/uio.h>
32: #include <netinet/in.h>
33: #include <stdio.h>
34: #include <errno.h>
35: #include <arpa/nameser.h>
36: #include <resolv.h>
37:
38: extern int errno;
39:
40: static int s = -1; /* socket used for communications */
41: static struct sockaddr no_addr;
42:
43:
44: #ifndef FD_SET
45: #define NFDBITS 32
46: #define FD_SETSIZE 32
47: #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
48: #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
49: #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
50: #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
51: #endif
52:
53: res_send(buf, buflen, answer, anslen)
54: char *buf;
55: int buflen;
56: char *answer;
57: int anslen;
58: {
59: register int n;
60: int try, v_circuit, resplen, ns;
61: int gotsomewhere = 0, connected = 0;
62: int connreset = 0;
63: u_short id, len;
64: char *cp;
65: fd_set dsmask;
66: struct timeval timeout;
67: HEADER *hp = (HEADER *) buf;
68: HEADER *anhp = (HEADER *) answer;
69: struct iovec iov[2];
70: int terrno = ETIMEDOUT;
71: char junk[512];
72:
73: #ifdef DEBUG
74: if (_res.options & RES_DEBUG) {
75: printf("res_send()\n");
76: p_query(buf);
77: }
78: #endif DEBUG
79: if (!(_res.options & RES_INIT))
80: if (res_init() == -1) {
81: return(-1);
82: }
83: v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
84: id = hp->id;
85: /*
86: * Send request, RETRY times, or until successful
87: */
88: for (try = 0; try < _res.retry; try++) {
89: for (ns = 0; ns < _res.nscount; ns++) {
90: #ifdef DEBUG
91: if (_res.options & RES_DEBUG)
92: printf("Querying server (# %d) address = %s\n", ns+1,
93: inet_ntoa(_res.nsaddr_list[ns].sin_addr));
94: #endif DEBUG
95: usevc:
96: if (v_circuit) {
97: int truncated = 0;
98:
99: /*
100: * Use virtual circuit;
101: * at most one attempt per server.
102: */
103: try = _res.retry;
104: if (s < 0) {
105: s = socket(AF_INET, SOCK_STREAM, 0);
106: if (s < 0) {
107: terrno = errno;
108: #ifdef DEBUG
109: if (_res.options & RES_DEBUG)
110: perror("socket (vc) failed");
111: #endif DEBUG
112: continue;
113: }
114: if (connect(s, &(_res.nsaddr_list[ns]),
115: sizeof(struct sockaddr)) < 0) {
116: terrno = errno;
117: #ifdef DEBUG
118: if (_res.options & RES_DEBUG)
119: perror("connect failed");
120: #endif DEBUG
121: (void) close(s);
122: s = -1;
123: continue;
124: }
125: }
126: /*
127: * Send length & message
128: */
129: len = htons((u_short)buflen);
130: iov[0].iov_base = (caddr_t)&len;
131: iov[0].iov_len = sizeof(len);
132: iov[1].iov_base = buf;
133: iov[1].iov_len = buflen;
134: if (writev(s, iov, 2) != sizeof(len) + buflen) {
135: terrno = errno;
136: #ifdef DEBUG
137: if (_res.options & RES_DEBUG)
138: perror("write failed");
139: #endif DEBUG
140: (void) close(s);
141: s = -1;
142: continue;
143: }
144: /*
145: * Receive length & response
146: */
147: cp = answer;
148: len = sizeof(short);
149: while (len != 0 &&
150: (n = read(s, (char *)cp, (int)len)) > 0) {
151: cp += n;
152: len -= n;
153: }
154: if (n <= 0) {
155: terrno = errno;
156: #ifdef DEBUG
157: if (_res.options & RES_DEBUG)
158: perror("read failed");
159: #endif DEBUG
160: (void) close(s);
161: s = -1;
162: /*
163: * A long running process might get its TCP
164: * connection reset if the remote server was
165: * restarted. Requery the server instead of
166: * trying a new one. When there is only one
167: * server, this means that a query might work
168: * instead of failing. We only allow one reset
169: * per query to prevent looping.
170: */
171: if (terrno == ECONNRESET && !connreset) {
172: connreset = 1;
173: ns--;
174: }
175: continue;
176: }
177: cp = answer;
178: if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
179: #ifdef DEBUG
180: if (_res.options & RES_DEBUG)
181: fprintf(stderr, "response truncated\n");
182: #endif DEBUG
183: len = anslen;
184: truncated = 1;
185: } else
186: len = resplen;
187: while (len != 0 &&
188: (n = read(s, (char *)cp, (int)len)) > 0) {
189: cp += n;
190: len -= n;
191: }
192: if (n <= 0) {
193: terrno = errno;
194: #ifdef DEBUG
195: if (_res.options & RES_DEBUG)
196: perror("read failed");
197: #endif DEBUG
198: (void) close(s);
199: s = -1;
200: continue;
201: }
202: if (truncated) {
203: /*
204: * Flush rest of answer
205: * so connection stays in synch.
206: */
207: anhp->tc = 1;
208: len = resplen - anslen;
209: while (len != 0) {
210: n = (len > sizeof(junk) ?
211: sizeof(junk) : len);
212: if ((n = read(s, junk, n)) > 0)
213: len -= n;
214: else
215: break;
216: }
217: }
218: } else {
219: /*
220: * Use datagrams.
221: */
222: if (s < 0) {
223: s = socket(AF_INET, SOCK_DGRAM, 0);
224: if (s < 0) {
225: terrno = errno;
226: #ifdef DEBUG
227: if (_res.options & RES_DEBUG)
228: perror("socket (dg) failed");
229: #endif DEBUG
230: continue;
231: }
232: }
233: #if BSD >= 43
234: /*
235: * I'm tired of answering this question, so:
236: * On a 4.3BSD+ machine (client and server,
237: * actually), sending to a nameserver datagram
238: * port with no nameserver will cause an
239: * ICMP port unreachable message to be returned.
240: * If our datagram socket is "connected" to the
241: * server, we get an ECONNREFUSED error on the next
242: * socket operation, and select returns if the
243: * error message is received. We can thus detect
244: * the absence of a nameserver without timing out.
245: * If we have sent queries to at least two servers,
246: * however, we don't want to remain connected,
247: * as we wish to receive answers from the first
248: * server to respond.
249: */
250: if (_res.nscount == 1 || (try == 0 && ns == 0)) {
251: /*
252: * Don't use connect if we might
253: * still receive a response
254: * from another server.
255: */
256: if (connected == 0) {
257: if (connect(s, &_res.nsaddr_list[ns],
258: sizeof(struct sockaddr)) < 0) {
259: #ifdef DEBUG
260: if (_res.options & RES_DEBUG)
261: perror("connect");
262: #endif DEBUG
263: continue;
264: }
265: connected = 1;
266: }
267: if (send(s, buf, buflen, 0) != buflen) {
268: #ifdef DEBUG
269: if (_res.options & RES_DEBUG)
270: perror("send");
271: #endif DEBUG
272: continue;
273: }
274: } else {
275: /*
276: * Disconnect if we want to listen
277: * for responses from more than one server.
278: */
279: if (connected) {
280: (void) connect(s, &no_addr,
281: sizeof(no_addr));
282: connected = 0;
283: }
284: #endif BSD
285: if (sendto(s, buf, buflen, 0,
286: &_res.nsaddr_list[ns],
287: sizeof(struct sockaddr)) != buflen) {
288: #ifdef DEBUG
289: if (_res.options & RES_DEBUG)
290: perror("sendto");
291: #endif DEBUG
292: continue;
293: }
294: #if BSD >= 43
295: }
296: #endif
297:
298: /*
299: * Wait for reply
300: */
301: timeout.tv_sec = (_res.retrans << try);
302: if (try > 0)
303: timeout.tv_sec /= _res.nscount;
304: if (timeout.tv_sec <= 0)
305: timeout.tv_sec = 1;
306: timeout.tv_usec = 0;
307: wait:
308: FD_ZERO(&dsmask);
309: FD_SET(s, &dsmask);
310: n = select(s+1, &dsmask, (fd_set *)NULL,
311: (fd_set *)NULL, &timeout);
312: if (n < 0) {
313: #ifdef DEBUG
314: if (_res.options & RES_DEBUG)
315: perror("select");
316: #endif DEBUG
317: continue;
318: }
319: if (n == 0) {
320: /*
321: * timeout
322: */
323: #ifdef DEBUG
324: if (_res.options & RES_DEBUG)
325: printf("timeout\n");
326: #endif DEBUG
327: #if BSD >= 43
328: gotsomewhere = 1;
329: #endif
330: continue;
331: }
332: if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
333: #ifdef DEBUG
334: if (_res.options & RES_DEBUG)
335: perror("recvfrom");
336: #endif DEBUG
337: continue;
338: }
339: gotsomewhere = 1;
340: if (id != anhp->id) {
341: /*
342: * response from old query, ignore it
343: */
344: #ifdef DEBUG
345: if (_res.options & RES_DEBUG) {
346: printf("old answer:\n");
347: p_query(answer);
348: }
349: #endif DEBUG
350: goto wait;
351: }
352: if (!(_res.options & RES_IGNTC) && anhp->tc) {
353: /*
354: * get rest of answer;
355: * use TCP with same server.
356: */
357: #ifdef DEBUG
358: if (_res.options & RES_DEBUG)
359: printf("truncated answer\n");
360: #endif DEBUG
361: (void) close(s);
362: s = -1;
363: v_circuit = 1;
364: goto usevc;
365: }
366: }
367: #ifdef DEBUG
368: if (_res.options & RES_DEBUG) {
369: printf("got answer:\n");
370: p_query(answer);
371: }
372: #endif DEBUG
373: /*
374: * If using virtual circuits, we assume that the first server
375: * is preferred * over the rest (i.e. it is on the local
376: * machine) and only keep that one open.
377: * If we have temporarily opened a virtual circuit,
378: * or if we haven't been asked to keep a socket open,
379: * close the socket.
380: */
381: if ((v_circuit &&
382: ((_res.options & RES_USEVC) == 0 || ns != 0)) ||
383: (_res.options & RES_STAYOPEN) == 0) {
384: (void) close(s);
385: s = -1;
386: }
387: return (resplen);
388: }
389: }
390: if (s >= 0) {
391: (void) close(s);
392: s = -1;
393: }
394: if (v_circuit == 0)
395: if (gotsomewhere == 0)
396: errno = ECONNREFUSED; /* no nameservers found */
397: else
398: errno = ETIMEDOUT; /* no answer obtained */
399: else
400: errno = terrno;
401: return (-1);
402: }
403:
404: /*
405: * This routine is for closing the socket if a virtual circuit is used and
406: * the program wants to close it. This provides support for endhostent()
407: * which expects to close the socket.
408: *
409: * This routine is not expected to be user visible.
410: */
411: _res_close()
412: {
413: if (s != -1) {
414: (void) close(s);
415: s = -1;
416: }
417: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.