change the writes to a writev for tcp, performance improves drasticly
[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)
679f3274 9static char sccsid[] = "@(#)res_send.c 6.12 (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>
679f3274 19#include <sys/uio.h>
616a94ba
RC
20#include <netinet/in.h>
21#include <stdio.h>
22#include <errno.h>
27df2740 23#include <arpa/nameser.h>
f94b2f50 24#include <resolv.h>
616a94ba
RC
25
26extern int errno;
27
3126f4c0
JB
28static int s = -1; /* socket used for communications */
29
a5d4a4c0
JB
30#define KEEPOPEN (RES_USEVC|RES_STAYOPEN)
31
31f0ead0 32res_send(buf, buflen, answer, anslen)
616a94ba
RC
33 char *buf;
34 int buflen;
35 char *answer;
36 int anslen;
37{
38 register int n;
a5d4a4c0 39 int retry, v_circuit, resplen, ns;
92a82fe4 40 int gotsomewhere = 0;
616a94ba
RC
41 u_short id, len;
42 char *cp;
43 int dsmask;
44 struct timeval timeout;
45 HEADER *hp = (HEADER *) buf;
46 HEADER *anhp = (HEADER *) answer;
679f3274 47 struct iovec iov[2];
616a94ba 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 */
09af7f8a 64 for (retry = _res.retry; retry > 0; retry--) {
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);
679f3274
JB
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) {
ae94a224 104#ifdef DEBUG
616a94ba 105 if (_res.options & RES_DEBUG)
747d796e 106 perror("write failed");
0b8992ca 107#endif DEBUG
616a94ba
RC
108 (void) close(s);
109 s = -1;
110 continue;
111 }
112 /*
113 * Receive length & response
114 */
115 cp = answer;
116 len = sizeof(short);
679f3274 117 while (len != 0 &&
747d796e 118 (n = read(s, (char *)cp, (int)len)) > 0) {
616a94ba
RC
119 cp += n;
120 len -= n;
121 }
122 if (n <= 0) {
ae94a224 123#ifdef DEBUG
616a94ba 124 if (_res.options & RES_DEBUG)
747d796e 125 perror("read failed");
0b8992ca 126#endif DEBUG
616a94ba
RC
127 (void) close(s);
128 s = -1;
129 continue;
130 }
131 cp = answer;
3126f4c0 132 resplen = len = ntohs(*(u_short *)cp);
679f3274 133 while (len != 0 &&
747d796e 134 (n = read(s, (char *)cp, (int)len)) > 0) {
616a94ba
RC
135 cp += n;
136 len -= n;
137 }
138 if (n <= 0) {
ae94a224 139#ifdef DEBUG
616a94ba 140 if (_res.options & RES_DEBUG)
747d796e 141 perror("read failed");
0b8992ca 142#endif DEBUG
616a94ba
RC
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);
92a82fe4 153#if BSD >= 43
87b12937
MK
154 if (connect(s, &_res.nsaddr_list[ns],
155 sizeof(struct sockaddr)) < 0 ||
156 send(s, buf, buflen, 0) != buflen) {
ae94a224 157#ifdef DEBUG
747d796e
KD
158 if (_res.options & RES_DEBUG)
159 perror("connect");
0b8992ca 160#endif DEBUG
92a82fe4
MK
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
747d796e
KD
167 if (_res.options & RES_DEBUG)
168 perror("sendto");
92a82fe4
MK
169#endif DEBUG
170 continue;
616a94ba 171 }
92a82fe4 172#endif BSD
616a94ba 173 /*
747d796e 174 * Wait for reply
616a94ba 175 */
747d796e
KD
176 timeout.tv_sec = (_res.retrans << (_res.retry - retry))
177 / _res.nscount;
178 if (timeout.tv_sec <= 0)
179 timeout.tv_sec = 1;
616a94ba 180 timeout.tv_usec = 0;
87b12937 181wait:
616a94ba 182 dsmask = 1 << s;
679f3274
JB
183 n = select(s+1, &dsmask, (fd_set *)NULL,
184 (fd_set *)NULL, &timeout);
616a94ba 185 if (n < 0) {
ae94a224 186#ifdef DEBUG
616a94ba 187 if (_res.options & RES_DEBUG)
747d796e 188 perror("select");
0b8992ca 189#endif DEBUG
616a94ba
RC
190 continue;
191 }
192 if (n == 0) {
193 /*
194 * timeout
195 */
ae94a224 196#ifdef DEBUG
616a94ba
RC
197 if (_res.options & RES_DEBUG)
198 printf("timeout\n");
0b8992ca 199#endif DEBUG
92a82fe4 200 gotsomewhere = 1;
616a94ba
RC
201 continue;
202 }
dd7a6a73 203 if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
ae94a224 204#ifdef DEBUG
616a94ba 205 if (_res.options & RES_DEBUG)
747d796e 206 perror("recvfrom");
0b8992ca 207#endif DEBUG
616a94ba
RC
208 continue;
209 }
92a82fe4 210 gotsomewhere = 1;
616a94ba
RC
211 if (id != anhp->id) {
212 /*
213 * response from old query, ignore it
214 */
ae94a224 215#ifdef DEBUG
616a94ba 216 if (_res.options & RES_DEBUG) {
616a94ba 217 printf("old answer:\n");
616a94ba
RC
218 p_query(answer);
219 }
0b8992ca 220#endif DEBUG
87b12937 221 goto wait;
616a94ba
RC
222 }
223 if (!(_res.options & RES_IGNTC) && anhp->tc) {
224 /*
225 * get rest of answer
226 */
ae94a224 227#ifdef DEBUG
616a94ba
RC
228 if (_res.options & RES_DEBUG)
229 printf("truncated answer\n");
0b8992ca 230#endif DEBUG
616a94ba
RC
231 (void) close(s);
232 s = -1;
09af7f8a
KD
233 /*
234 * retry decremented on continue
235 * to desired starting value
236 */
237 retry = _res.retry + 1;
616a94ba
RC
238 v_circuit = 1;
239 continue;
240 }
241 }
ae94a224 242#ifdef DEBUG
616a94ba
RC
243 if (_res.options & RES_DEBUG) {
244 printf("got answer:\n");
245 p_query(answer);
246 }
0b8992ca 247#endif DEBUG
a5d4a4c0
JB
248 /*
249 * We are going to assume that the first server is preferred
250 * over the rest (i.e. it is on the local machine) and only
251 * keep that one open.
252 */
253 if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) {
254 return (resplen);
255 } else {
256 (void) close(s);
257 s = -1;
258 return (resplen);
259 }
0b8992ca 260 }
616a94ba 261 }
e96fe2f7 262 (void) close(s);
8f9e1de0 263 s = -1;
92a82fe4
MK
264 if (v_circuit == 0 && gotsomewhere == 0)
265 errno = ECONNREFUSED;
266 else
267 errno = ETIMEDOUT;
616a94ba
RC
268 return (-1);
269}
3126f4c0
JB
270
271/*
272 * This routine is for closing the socket if a virtual circuit is used and
273 * the program wants to close it. This provides support for endhostent()
274 * which expects to close the socket.
275 *
276 * This routine is not expected to be user visible.
277 */
278_res_close()
279{
280 if (s != -1) {
281 (void) close(s);
282 s = -1;
283 }
284}