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