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 | ||
8ea4199d | 8 | #ifndef lint |
87b12937 | 9 | static 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 | |
25 | extern int errno; | |
26 | ||
a5d4a4c0 JB |
27 | #define KEEPOPEN (RES_USEVC|RES_STAYOPEN) |
28 | ||
31f0ead0 | 29 | res_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 | 152 | wait: |
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 | } |