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.13 (Berkeley) 5/7/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:
49: #ifdef DEBUG
50: if (_res.options & RES_DEBUG) {
51: printf("res_send()\n");
52: p_query(buf);
53: }
54: #endif DEBUG
55: if (!(_res.options & RES_INIT))
56: if (res_init() == -1) {
57: return(-1);
58: }
59: v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
60: id = hp->id;
61: /*
62: * Send request, RETRY times, or until successful
63: */
64: for (retry = _res.retry; retry > 0; retry--) {
65: for (ns = 0; ns < _res.nscount; ns++) {
66: #ifdef DEBUG
67: if (_res.options & RES_DEBUG)
68: printf("Querying server (# %d) address = %s\n", ns+1,
69: inet_ntoa(_res.nsaddr_list[ns].sin_addr.s_addr));
70: #endif DEBUG
71: if (v_circuit) {
72: /*
73: * Use virtual circuit.
74: */
75: if (s < 0) {
76: s = socket(AF_INET, SOCK_STREAM, 0);
77: if (s < 0) {
78: #ifdef DEBUG
79: if (_res.options & RES_DEBUG)
80: perror("socket failed");
81: #endif DEBUG
82: continue;
83: }
84: if (connect(s, &(_res.nsaddr_list[ns]),
85: sizeof(struct sockaddr)) < 0) {
86: #ifdef DEBUG
87: if (_res.options & RES_DEBUG)
88: perror("connect failed");
89: #endif DEBUG
90: (void) close(s);
91: s = -1;
92: continue;
93: }
94: }
95: /*
96: * Send length & message
97: */
98: len = htons((u_short)buflen);
99: iov[0].iov_base = (caddr_t)&len;
100: iov[0].iov_len = sizeof(len);
101: iov[1].iov_base = buf;
102: iov[1].iov_len = buflen;
103: if (writev(s, iov, 2) != sizeof(len) + buflen) {
104: #ifdef DEBUG
105: if (_res.options & RES_DEBUG)
106: perror("write failed");
107: #endif DEBUG
108: (void) close(s);
109: s = -1;
110: continue;
111: }
112: /*
113: * Receive length & response
114: */
115: cp = answer;
116: len = sizeof(short);
117: while (len != 0 &&
118: (n = read(s, (char *)cp, (int)len)) > 0) {
119: cp += n;
120: len -= n;
121: }
122: if (n <= 0) {
123: #ifdef DEBUG
124: if (_res.options & RES_DEBUG)
125: perror("read failed");
126: #endif DEBUG
127: (void) close(s);
128: s = -1;
129: continue;
130: }
131: cp = answer;
132: resplen = len = ntohs(*(u_short *)cp);
133: while (len != 0 &&
134: (n = read(s, (char *)cp, (int)len)) > 0) {
135: cp += n;
136: len -= n;
137: }
138: if (n <= 0) {
139: #ifdef DEBUG
140: if (_res.options & RES_DEBUG)
141: perror("read failed");
142: #endif DEBUG
143: (void) close(s);
144: s = -1;
145: continue;
146: }
147: } else {
148: /*
149: * Use datagrams.
150: */
151: if (s < 0)
152: s = socket(AF_INET, SOCK_DGRAM, 0);
153: #if BSD >= 43
154: if (connect(s, &_res.nsaddr_list[ns],
155: sizeof(struct sockaddr)) < 0 ||
156: send(s, buf, buflen, 0) != buflen) {
157: #ifdef DEBUG
158: if (_res.options & RES_DEBUG)
159: perror("connect");
160: #endif DEBUG
161: continue;
162: }
163: #else BSD
164: if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns],
165: sizeof(struct sockaddr)) != buflen) {
166: #ifdef DEBUG
167: if (_res.options & RES_DEBUG)
168: perror("sendto");
169: #endif DEBUG
170: continue;
171: }
172: #endif BSD
173: /*
174: * Wait for reply
175: */
176: timeout.tv_sec = (_res.retrans << (_res.retry - retry))
177: / _res.nscount;
178: if (timeout.tv_sec <= 0)
179: timeout.tv_sec = 1;
180: timeout.tv_usec = 0;
181: wait:
182: FD_ZERO(&dsmask);
183: FD_SET(s, &dsmask);
184: n = select(s+1, &dsmask, (fd_set *)NULL,
185: (fd_set *)NULL, &timeout);
186: if (n < 0) {
187: #ifdef DEBUG
188: if (_res.options & RES_DEBUG)
189: perror("select");
190: #endif DEBUG
191: continue;
192: }
193: if (n == 0) {
194: /*
195: * timeout
196: */
197: #ifdef DEBUG
198: if (_res.options & RES_DEBUG)
199: printf("timeout\n");
200: #endif DEBUG
201: gotsomewhere = 1;
202: continue;
203: }
204: if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
205: #ifdef DEBUG
206: if (_res.options & RES_DEBUG)
207: perror("recvfrom");
208: #endif DEBUG
209: continue;
210: }
211: gotsomewhere = 1;
212: if (id != anhp->id) {
213: /*
214: * response from old query, ignore it
215: */
216: #ifdef DEBUG
217: if (_res.options & RES_DEBUG) {
218: printf("old answer:\n");
219: p_query(answer);
220: }
221: #endif DEBUG
222: goto wait;
223: }
224: if (!(_res.options & RES_IGNTC) && anhp->tc) {
225: /*
226: * get rest of answer
227: */
228: #ifdef DEBUG
229: if (_res.options & RES_DEBUG)
230: printf("truncated answer\n");
231: #endif DEBUG
232: (void) close(s);
233: s = -1;
234: /*
235: * retry decremented on continue
236: * to desired starting value
237: */
238: retry = _res.retry + 1;
239: v_circuit = 1;
240: continue;
241: }
242: }
243: #ifdef DEBUG
244: if (_res.options & RES_DEBUG) {
245: printf("got answer:\n");
246: p_query(answer);
247: }
248: #endif DEBUG
249: /*
250: * We are going to assume that the first server is preferred
251: * over the rest (i.e. it is on the local machine) and only
252: * keep that one open.
253: */
254: if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) {
255: return (resplen);
256: } else {
257: (void) close(s);
258: s = -1;
259: return (resplen);
260: }
261: }
262: }
263: (void) close(s);
264: s = -1;
265: if (v_circuit == 0 && gotsomewhere == 0)
266: errno = ECONNREFUSED;
267: else
268: errno = ETIMEDOUT;
269: return (-1);
270: }
271:
272: /*
273: * This routine is for closing the socket if a virtual circuit is used and
274: * the program wants to close it. This provides support for endhostent()
275: * which expects to close the socket.
276: *
277: * This routine is not expected to be user visible.
278: */
279: _res_close()
280: {
281: if (s != -1) {
282: (void) close(s);
283: s = -1;
284: }
285: }
Defined functions
Defined variables
s
defined in line
28; used 32 times
- in line 75-77(3),
84,
90-91(2),
103-109(3),
118,
127-128(2),
134,
143-144(2),
151-156(4),
164,
183-184(2),
204,
232-233(2),
257-264(4),
281-283(3)
sccsid
defined in line
9;
never used
Defined macros