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