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