|
|
1.1 root 1: /*
2: * Copyright (c) 1985 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 the above copyright notice and this paragraph are
7: * duplicated in all such forms and that any documentation,
8: * advertising materials, and other materials related to such
9: * distribution and use acknowledge that the software was developed
10: * by the University of California, Berkeley. The name of the
11: * University may not be used to endorse or promote products derived
12: * from this software without specific prior written permission.
13: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16: */
17:
18: #if defined(LIBC_SCCS) && !defined(lint)
19: static char sccsid[] = "@(#)res_send.c 6.21 (Berkeley) 6/27/88";
20: #endif /* LIBC_SCCS and not lint */
21:
22: /*
23: * Send query to name server and wait for reply.
24: */
25:
26: #include <sys/param.h>
27: #include <sys/time.h>
28: #include <sys/socket.h>
29: #include <sys/uio.h>
30: #include <netinet/in.h>
31: #include <stdio.h>
32: #include <errno.h>
33: #include <arpa/nameser.h>
34: #include <resolv.h>
35:
36: extern int errno;
37:
38: static int s = -1; /* socket used for communications */
39: static struct sockaddr no_addr;
40:
41:
42: #ifndef FD_SET
43: #define NFDBITS 32
44: #define FD_SETSIZE 32
45: #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
46: #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
47: #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
48: #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
49: #endif
50:
51: #define KEEPOPEN (RES_USEVC|RES_STAYOPEN)
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 retry, v_circuit, resplen, ns;
61: int gotsomewhere = 0, connected = 0;
62: u_short id, len;
63: char *cp;
64: fd_set dsmask;
65: struct timeval timeout;
66: HEADER *hp = (HEADER *) buf;
67: HEADER *anhp = (HEADER *) answer;
68: struct iovec iov[2];
69: int terrno = ETIMEDOUT;
70: char junk[512];
71:
72: #ifdef DEBUG
73: if (_res.options & RES_DEBUG) {
74: printf("res_send()\n");
75: p_query(buf);
76: }
77: #endif DEBUG
78: if (!(_res.options & RES_INIT))
79: if (res_init() == -1) {
80: return(-1);
81: }
82: v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
83: id = hp->id;
84: /*
85: * Send request, RETRY times, or until successful
86: */
87: for (retry = _res.retry; retry > 0; retry--) {
88: for (ns = 0; ns < _res.nscount; ns++) {
89: #ifdef DEBUG
90: if (_res.options & RES_DEBUG)
91: printf("Querying server (# %d) address = %s\n", ns+1,
92: inet_ntoa(_res.nsaddr_list[ns].sin_addr));
93: #endif DEBUG
94: if (v_circuit) {
95: int truncated = 0;
96:
97: /*
98: * Use virtual circuit.
99: */
100: if (s < 0) {
101: s = socket(AF_INET, SOCK_STREAM, 0);
102: if (s < 0) {
103: terrno = errno;
104: #ifdef DEBUG
105: if (_res.options & RES_DEBUG)
106: perror("socket failed");
107: #endif DEBUG
108: continue;
109: }
110: if (connect(s, &(_res.nsaddr_list[ns]),
111: sizeof(struct sockaddr)) < 0) {
112: terrno = errno;
113: #ifdef DEBUG
114: if (_res.options & RES_DEBUG)
115: perror("connect failed");
116: #endif DEBUG
117: (void) close(s);
118: s = -1;
119: continue;
120: }
121: }
122: /*
123: * Send length & message
124: */
125: len = htons((u_short)buflen);
126: iov[0].iov_base = (caddr_t)&len;
127: iov[0].iov_len = sizeof(len);
128: iov[1].iov_base = buf;
129: iov[1].iov_len = buflen;
130: if (writev(s, iov, 2) != sizeof(len) + buflen) {
131: terrno = errno;
132: #ifdef DEBUG
133: if (_res.options & RES_DEBUG)
134: perror("write failed");
135: #endif DEBUG
136: (void) close(s);
137: s = -1;
138: continue;
139: }
140: /*
141: * Receive length & response
142: */
143: cp = answer;
144: len = sizeof(short);
145: while (len != 0 &&
146: (n = read(s, (char *)cp, (int)len)) > 0) {
147: cp += n;
148: len -= n;
149: }
150: if (n <= 0) {
151: terrno = errno;
152: #ifdef DEBUG
153: if (_res.options & RES_DEBUG)
154: perror("read failed");
155: #endif DEBUG
156: (void) close(s);
157: s = -1;
158: continue;
159: }
160: cp = answer;
161: if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
162: #ifdef DEBUG
163: if (_res.options & RES_DEBUG)
164: fprintf(stderr, "response truncated\n");
165: #endif DEBUG
166: len = anslen;
167: truncated = 1;
168: } else
169: len = resplen;
170: while (len != 0 &&
171: (n = read(s, (char *)cp, (int)len)) > 0) {
172: cp += n;
173: len -= n;
174: }
175: if (n <= 0) {
176: terrno = errno;
177: #ifdef DEBUG
178: if (_res.options & RES_DEBUG)
179: perror("read failed");
180: #endif DEBUG
181: (void) close(s);
182: s = -1;
183: continue;
184: }
185: if (truncated) {
186: /*
187: * Flush rest of answer
188: * so connection stays in synch.
189: */
190: anhp->tc = 1;
191: len = resplen - anslen;
192: while (len != 0) {
193: n = (len > sizeof(junk) ?
194: sizeof(junk) : len);
195: if ((n = read(s, junk, n)) > 0)
196: len -= n;
197: else
198: break;
199: }
200: }
201: } else {
202: /*
203: * Use datagrams.
204: */
205: if (s < 0)
206: s = socket(AF_INET, SOCK_DGRAM, 0);
207: #if BSD >= 43
208: if (_res.nscount == 1 || retry == _res.retry) {
209: /*
210: * Don't use connect if we might
211: * still receive a response
212: * from another server.
213: */
214: if (connected == 0) {
215: if (connect(s, &_res.nsaddr_list[ns],
216: sizeof(struct sockaddr)) < 0) {
217: #ifdef DEBUG
218: if (_res.options & RES_DEBUG)
219: perror("connect");
220: #endif DEBUG
221: continue;
222: }
223: connected = 1;
224: }
225: if (send(s, buf, buflen, 0) != buflen) {
226: #ifdef DEBUG
227: if (_res.options & RES_DEBUG)
228: perror("send");
229: #endif DEBUG
230: continue;
231: }
232: } else {
233: /*
234: * Disconnect if we want to listen
235: * for responses from more than one server.
236: */
237: if (connected) {
238: (void) connect(s, &no_addr,
239: sizeof(no_addr));
240: connected = 0;
241: }
242: #endif BSD
243: if (sendto(s, buf, buflen, 0,
244: &_res.nsaddr_list[ns],
245: sizeof(struct sockaddr)) != buflen) {
246: #ifdef DEBUG
247: if (_res.options & RES_DEBUG)
248: perror("sendto");
249: #endif DEBUG
250: continue;
251: }
252: #if BSD >= 43
253: }
254: #endif
255:
256: /*
257: * Wait for reply
258: */
259: timeout.tv_sec = (_res.retrans << (_res.retry - retry))
260: / _res.nscount;
261: if (timeout.tv_sec <= 0)
262: timeout.tv_sec = 1;
263: timeout.tv_usec = 0;
264: wait:
265: FD_ZERO(&dsmask);
266: FD_SET(s, &dsmask);
267: n = select(s+1, &dsmask, (fd_set *)NULL,
268: (fd_set *)NULL, &timeout);
269: if (n < 0) {
270: #ifdef DEBUG
271: if (_res.options & RES_DEBUG)
272: perror("select");
273: #endif DEBUG
274: continue;
275: }
276: if (n == 0) {
277: /*
278: * timeout
279: */
280: #ifdef DEBUG
281: if (_res.options & RES_DEBUG)
282: printf("timeout\n");
283: #endif DEBUG
284: gotsomewhere = 1;
285: continue;
286: }
287: if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
288: #ifdef DEBUG
289: if (_res.options & RES_DEBUG)
290: perror("recvfrom");
291: #endif DEBUG
292: continue;
293: }
294: gotsomewhere = 1;
295: if (id != anhp->id) {
296: /*
297: * response from old query, ignore it
298: */
299: #ifdef DEBUG
300: if (_res.options & RES_DEBUG) {
301: printf("old answer:\n");
302: p_query(answer);
303: }
304: #endif DEBUG
305: goto wait;
306: }
307: if (!(_res.options & RES_IGNTC) && anhp->tc) {
308: /*
309: * get rest of answer
310: */
311: #ifdef DEBUG
312: if (_res.options & RES_DEBUG)
313: printf("truncated answer\n");
314: #endif DEBUG
315: (void) close(s);
316: s = -1;
317: /*
318: * retry decremented on continue
319: * to desired starting value
320: */
321: retry = _res.retry + 1;
322: v_circuit = 1;
323: continue;
324: }
325: }
326: #ifdef DEBUG
327: if (_res.options & RES_DEBUG) {
328: printf("got answer:\n");
329: p_query(answer);
330: }
331: #endif DEBUG
332: /*
333: * We are going to assume that the first server is preferred
334: * over the rest (i.e. it is on the local machine) and only
335: * keep that one open.
336: */
337: if ((_res.options & KEEPOPEN) == 0 || ns != 0) {
338: (void) close(s);
339: s = -1;
340: }
341: return (resplen);
342: }
343: }
344: if (s >= 0) {
345: (void) close(s);
346: s = -1;
347: }
348: if (v_circuit == 0)
349: if (gotsomewhere == 0)
350: errno = ECONNREFUSED;
351: else
352: errno = ETIMEDOUT;
353: else
354: errno = terrno;
355: return (-1);
356: }
357:
358: /*
359: * This routine is for closing the socket if a virtual circuit is used and
360: * the program wants to close it. This provides support for endhostent()
361: * which expects to close the socket.
362: *
363: * This routine is not expected to be user visible.
364: */
365: _res_close()
366: {
367: if (s != -1) {
368: (void) close(s);
369: s = -1;
370: }
371: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.