Commit | Line | Data |
---|---|---|
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 | 9 | static 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 | |
25 | extern int errno; | |
26 | ||
3126f4c0 JB |
27 | static int s = -1; /* socket used for communications */ |
28 | ||
a5d4a4c0 JB |
29 | #define KEEPOPEN (RES_USEVC|RES_STAYOPEN) |
30 | ||
31f0ead0 | 31 | res_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 | 176 | wait: |
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 | } |