|
|
1.1 root 1:
2: /*
3: * Copyright (c) 1985 Regents of the University of California.
4: * All rights reserved. The Berkeley software License Agreement
5: * specifies the terms and conditions for redistribution.
6: */
7:
8: #if defined(LIBC_SCCS) && !defined(lint)
9: static char sccsid[] = "@(#)res_send.c 6.14 (Berkeley) 7/2/86";
10: #endif LIBC_SCCS and not lint
11:
12: /*
13: * Send query to name server and wait for reply.
14: */
15:
16: #include <sys/param.h>
17: #include <sys/time.h>
18: #include <sys/socket.h>
19: #include <sys/uio.h>
20: #include <netinet/in.h>
21: #include <stdio.h>
22: #include <errno.h>
23: #include <arpa/nameser.h>
24: #include <resolv.h>
25:
26: extern int errno;
27:
28: static int s = -1; /* socket used for communications */
29:
30: #define KEEPOPEN (RES_USEVC|RES_STAYOPEN)
31:
32: res_send(buf, buflen, answer, anslen)
33: char *buf;
34: int buflen;
35: char *answer;
36: int anslen;
37: {
38: register int n;
39: int retry, v_circuit, resplen, ns;
40: int gotsomewhere = 0;
41: u_short id, len;
42: char *cp;
43: fd_set dsmask;
44: struct timeval timeout;
45: HEADER *hp = (HEADER *) buf;
46: HEADER *anhp = (HEADER *) answer;
47: struct iovec iov[2];
48: int terrno = ETIMEDOUT;
49:
50: #ifdef DEBUG
51: if (_res.options & RES_DEBUG) {
52: printf("res_send()\n");
53: p_query(buf);
54: }
55: #endif DEBUG
56: if (!(_res.options & RES_INIT))
57: if (res_init() == -1) {
58: return(-1);
59: }
60: v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
61: id = hp->id;
62: /*
63: * Send request, RETRY times, or until successful
64: */
65: for (retry = _res.retry; retry > 0; retry--) {
66: for (ns = 0; ns < _res.nscount; ns++) {
67: #ifdef DEBUG
68: if (_res.options & RES_DEBUG)
69: printf("Querying server (# %d) address = %s\n", ns+1,
70: inet_ntoa(_res.nsaddr_list[ns].sin_addr.s_addr));
71: #endif DEBUG
72: if (v_circuit) {
73: /*
74: * Use virtual circuit.
75: */
76: if (s < 0) {
77: s = socket(AF_INET, SOCK_STREAM, 0);
78: if (s < 0) {
79: terrno = errno;
80: #ifdef DEBUG
81: if (_res.options & RES_DEBUG)
82: perror("socket failed");
83: #endif DEBUG
84: continue;
85: }
86: if (connect(s, &(_res.nsaddr_list[ns]),
87: sizeof(struct sockaddr)) < 0) {
88: terrno = errno;
89: #ifdef DEBUG
90: if (_res.options & RES_DEBUG)
91: perror("connect failed");
92: #endif DEBUG
93: (void) close(s);
94: s = -1;
95: continue;
96: }
97: }
98: /*
99: * Send length & message
100: */
101: len = htons((u_short)buflen);
102: iov[0].iov_base = (caddr_t)&len;
103: iov[0].iov_len = sizeof(len);
104: iov[1].iov_base = buf;
105: iov[1].iov_len = buflen;
106: if (writev(s, iov, 2) != sizeof(len) + buflen) {
107: terrno = errno;
108: #ifdef DEBUG
109: if (_res.options & RES_DEBUG)
110: perror("write failed");
111: #endif DEBUG
112: (void) close(s);
113: s = -1;
114: continue;
115: }
116: /*
117: * Receive length & response
118: */
119: cp = answer;
120: len = sizeof(short);
121: while (len != 0 &&
122: (n = read(s, (char *)cp, (int)len)) > 0) {
123: cp += n;
124: len -= n;
125: }
126: if (n <= 0) {
127: terrno = errno;
128: #ifdef DEBUG
129: if (_res.options & RES_DEBUG)
130: perror("read failed");
131: #endif DEBUG
132: (void) close(s);
133: s = -1;
134: continue;
135: }
136: cp = answer;
137: resplen = len = ntohs(*(u_short *)cp);
138: while (len != 0 &&
139: (n = read(s, (char *)cp, (int)len)) > 0) {
140: cp += n;
141: len -= n;
142: }
143: if (n <= 0) {
144: terrno = errno;
145: #ifdef DEBUG
146: if (_res.options & RES_DEBUG)
147: perror("read failed");
148: #endif DEBUG
149: (void) close(s);
150: s = -1;
151: continue;
152: }
153: } else {
154: /*
155: * Use datagrams.
156: */
157: if (s < 0)
158: s = socket(AF_INET, SOCK_DGRAM, 0);
159: #if BSD >= 43
160: if (connect(s, &_res.nsaddr_list[ns],
161: sizeof(struct sockaddr)) < 0 ||
162: send(s, buf, buflen, 0) != buflen) {
163: #ifdef DEBUG
164: if (_res.options & RES_DEBUG)
165: perror("connect");
166: #endif DEBUG
167: continue;
168: }
169: #else BSD
170: if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns],
171: sizeof(struct sockaddr)) != buflen) {
172: #ifdef DEBUG
173: if (_res.options & RES_DEBUG)
174: perror("sendto");
175: #endif DEBUG
176: continue;
177: }
178: #endif BSD
179: /*
180: * Wait for reply
181: */
182: timeout.tv_sec = (_res.retrans << (_res.retry - retry))
183: / _res.nscount;
184: if (timeout.tv_sec <= 0)
185: timeout.tv_sec = 1;
186: timeout.tv_usec = 0;
187: wait:
188: FD_ZERO(&dsmask);
189: FD_SET(s, &dsmask);
190: n = select(s+1, &dsmask, (fd_set *)NULL,
191: (fd_set *)NULL, &timeout);
192: if (n < 0) {
193: #ifdef DEBUG
194: if (_res.options & RES_DEBUG)
195: perror("select");
196: #endif DEBUG
197: continue;
198: }
199: if (n == 0) {
200: /*
201: * timeout
202: */
203: #ifdef DEBUG
204: if (_res.options & RES_DEBUG)
205: printf("timeout\n");
206: #endif DEBUG
207: gotsomewhere = 1;
208: continue;
209: }
210: if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
211: #ifdef DEBUG
212: if (_res.options & RES_DEBUG)
213: perror("recvfrom");
214: #endif DEBUG
215: continue;
216: }
217: gotsomewhere = 1;
218: if (id != anhp->id) {
219: /*
220: * response from old query, ignore it
221: */
222: #ifdef DEBUG
223: if (_res.options & RES_DEBUG) {
224: printf("old answer:\n");
225: p_query(answer);
226: }
227: #endif DEBUG
228: goto wait;
229: }
230: if (!(_res.options & RES_IGNTC) && anhp->tc) {
231: /*
232: * get rest of answer
233: */
234: #ifdef DEBUG
235: if (_res.options & RES_DEBUG)
236: printf("truncated answer\n");
237: #endif DEBUG
238: (void) close(s);
239: s = -1;
240: /*
241: * retry decremented on continue
242: * to desired starting value
243: */
244: retry = _res.retry + 1;
245: v_circuit = 1;
246: continue;
247: }
248: }
249: #ifdef DEBUG
250: if (_res.options & RES_DEBUG) {
251: printf("got answer:\n");
252: p_query(answer);
253: }
254: #endif DEBUG
255: /*
256: * We are going to assume that the first server is preferred
257: * over the rest (i.e. it is on the local machine) and only
258: * keep that one open.
259: */
260: if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) {
261: return (resplen);
262: } else {
263: (void) close(s);
264: s = -1;
265: return (resplen);
266: }
267: }
268: }
269: if (s >= 0) {
270: (void) close(s);
271: s = -1;
272: }
273: if (v_circuit == 0)
274: if (gotsomewhere == 0)
275: errno = ECONNREFUSED;
276: else
277: errno = ETIMEDOUT;
278: else
279: errno = terrno;
280: return (-1);
281: }
282:
283: /*
284: * This routine is for closing the socket if a virtual circuit is used and
285: * the program wants to close it. This provides support for endhostent()
286: * which expects to close the socket.
287: *
288: * This routine is not expected to be user visible.
289: */
290: _res_close()
291: {
292: if (s != -1) {
293: (void) close(s);
294: s = -1;
295: }
296: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.