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