use connect on dg sockets to allow unreachable reporting;
[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
8ea4199d 8#ifndef lint
87b12937 9static char sccsid[] = "@(#)res_send.c 6.3 (Berkeley) %G%";
8ea4199d
DF
10#endif not lint
11
616a94ba
RC
12/*
13 * Send query to name server and wait for reply.
14 */
15
16#include <sys/types.h>
17#include <sys/time.h>
18#include <sys/socket.h>
19#include <netinet/in.h>
20#include <stdio.h>
21#include <errno.h>
27df2740
KD
22#include <arpa/nameser.h>
23#include <arpa/resolv.h>
616a94ba
RC
24
25extern int errno;
26
a5d4a4c0
JB
27#define KEEPOPEN (RES_USEVC|RES_STAYOPEN)
28
31f0ead0 29res_send(buf, buflen, answer, anslen)
616a94ba
RC
30 char *buf;
31 int buflen;
32 char *answer;
33 int anslen;
34{
35 register int n;
a5d4a4c0
JB
36 int retry, v_circuit, resplen, ns;
37 static int s = -1;
616a94ba
RC
38 u_short id, len;
39 char *cp;
40 int dsmask;
41 struct timeval timeout;
42 HEADER *hp = (HEADER *) buf;
43 HEADER *anhp = (HEADER *) answer;
44
ae94a224 45#ifdef DEBUG
616a94ba 46 if (_res.options & RES_DEBUG) {
31f0ead0 47 printf("res_send()\n");
616a94ba
RC
48 p_query(buf);
49 }
0b8992ca 50#endif DEBUG
31f0ead0 51 if (!(_res.options & RES_INIT))
ae94a224
JB
52 if (res_init() == -1) {
53 return(-1);
54 }
616a94ba
RC
55 v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
56 id = hp->id;
57 /*
58 * Send request, RETRY times, or until successful
59 */
60 for (retry = _res.retry; --retry >= 0; ) {
0b8992ca
KD
61 for (ns = 0; ns < _res.nscount; ns++) {
62#ifdef DEBUG
63 if (_res.options & RES_DEBUG)
64 printf("Querying server (# %d) address = %s\n", ns+1,
65 inet_ntoa(_res.nsaddr_list[ns].sin_addr.s_addr));
66#endif DEBUG
616a94ba
RC
67 if (v_circuit) {
68 /*
69 * Use virtual circuit.
70 */
a5d4a4c0 71 if (s < 0) {
616a94ba 72 s = socket(AF_INET, SOCK_STREAM, 0);
a5d4a4c0
JB
73 if (connect(s, &(_res.nsaddr_list[ns]),
74 sizeof(struct sockaddr)) < 0) {
ae94a224 75#ifdef DEBUG
a5d4a4c0
JB
76 if (_res.options & RES_DEBUG)
77 printf("connect failed %d\n",errno);
0b8992ca 78#endif DEBUG
a5d4a4c0
JB
79 (void) close(s);
80 s = -1;
81 continue;
82 }
616a94ba
RC
83 }
84 /*
85 * Send length & message
86 */
87 len = htons(buflen);
88 if (write(s, &len, sizeof(len)) != sizeof(len) ||
0b8992ca 89 write(s, buf, buflen) != buflen) {
ae94a224 90#ifdef DEBUG
616a94ba
RC
91 if (_res.options & RES_DEBUG)
92 printf("write failed %d\n", errno);
0b8992ca 93#endif DEBUG
616a94ba
RC
94 (void) close(s);
95 s = -1;
96 continue;
97 }
98 /*
99 * Receive length & response
100 */
101 cp = answer;
102 len = sizeof(short);
103 while (len > 0 && (n = read(s, cp, len)) > 0) {
104 cp += n;
105 len -= n;
106 }
107 if (n <= 0) {
ae94a224 108#ifdef DEBUG
616a94ba
RC
109 if (_res.options & RES_DEBUG)
110 printf("read failed %d\n", errno);
0b8992ca 111#endif DEBUG
616a94ba
RC
112 (void) close(s);
113 s = -1;
114 continue;
115 }
116 cp = answer;
117 resplen = len = ntohs(*(short *)cp);
118 while (len > 0 && (n = read(s, cp, len)) > 0) {
119 cp += n;
120 len -= n;
121 }
122 if (n <= 0) {
ae94a224 123#ifdef DEBUG
616a94ba
RC
124 if (_res.options & RES_DEBUG)
125 printf("read failed %d\n", errno);
0b8992ca 126#endif DEBUG
616a94ba
RC
127 (void) close(s);
128 s = -1;
129 continue;
130 }
131 } else {
132 /*
133 * Use datagrams.
134 */
135 if (s < 0)
136 s = socket(AF_INET, SOCK_DGRAM, 0);
87b12937
MK
137 if (connect(s, &_res.nsaddr_list[ns],
138 sizeof(struct sockaddr)) < 0 ||
139 send(s, buf, buflen, 0) != buflen) {
ae94a224 140#ifdef DEBUG
0b8992ca 141 if (_res.options & RES_DEBUG)
87b12937
MK
142 printf("connect/send errno = %d\n",
143 errno);
0b8992ca 144#endif DEBUG
616a94ba
RC
145 }
146 /*
147 * Wait for reply
148 */
0b8992ca
KD
149 timeout.tv_sec =
150 ((_res.retrans * _res.retry) / _res.nscount);
616a94ba 151 timeout.tv_usec = 0;
87b12937 152wait:
616a94ba
RC
153 dsmask = 1 << s;
154 n = select(s+1, &dsmask, 0, 0, &timeout);
155 if (n < 0) {
ae94a224 156#ifdef DEBUG
616a94ba
RC
157 if (_res.options & RES_DEBUG)
158 printf("select errno = %d\n", errno);
0b8992ca 159#endif DEBUG
616a94ba
RC
160 continue;
161 }
162 if (n == 0) {
163 /*
164 * timeout
165 */
ae94a224 166#ifdef DEBUG
616a94ba
RC
167 if (_res.options & RES_DEBUG)
168 printf("timeout\n");
0b8992ca 169#endif DEBUG
616a94ba
RC
170 continue;
171 }
dd7a6a73 172 if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
ae94a224 173#ifdef DEBUG
616a94ba
RC
174 if (_res.options & RES_DEBUG)
175 printf("recvfrom, errno=%d\n", errno);
0b8992ca 176#endif DEBUG
616a94ba
RC
177 continue;
178 }
179 if (id != anhp->id) {
180 /*
181 * response from old query, ignore it
182 */
ae94a224 183#ifdef DEBUG
616a94ba 184 if (_res.options & RES_DEBUG) {
616a94ba 185 printf("old answer:\n");
616a94ba
RC
186 p_query(answer);
187 }
0b8992ca 188#endif DEBUG
87b12937 189 goto wait;
616a94ba
RC
190 }
191 if (!(_res.options & RES_IGNTC) && anhp->tc) {
192 /*
193 * get rest of answer
194 */
ae94a224 195#ifdef DEBUG
616a94ba
RC
196 if (_res.options & RES_DEBUG)
197 printf("truncated answer\n");
0b8992ca 198#endif DEBUG
616a94ba
RC
199 (void) close(s);
200 s = -1;
201 retry = _res.retry;
202 v_circuit = 1;
203 continue;
204 }
205 }
ae94a224 206#ifdef DEBUG
616a94ba
RC
207 if (_res.options & RES_DEBUG) {
208 printf("got answer:\n");
209 p_query(answer);
210 }
0b8992ca 211#endif DEBUG
a5d4a4c0
JB
212 /*
213 * We are going to assume that the first server is preferred
214 * over the rest (i.e. it is on the local machine) and only
215 * keep that one open.
216 */
217 if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) {
218 return (resplen);
219 } else {
220 (void) close(s);
221 s = -1;
222 return (resplen);
223 }
0b8992ca 224 }
616a94ba 225 }
e96fe2f7 226 (void) close(s);
31b63904 227 errno = ETIMEDOUT;
616a94ba
RC
228 return (-1);
229}