2 * Copyright (c) 1985, 1989 Regents of the University of California.
4 * Copyright (C) 2005 - 2007 The AROS Dev Team
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #if defined(LIBC_SCCS) && !defined(lint)
36 static char sccsid
[] = "@(#)res_send.c 6.27 (Berkeley) 2/24/91";
37 #endif /* LIBC_SCCS and not lint */
40 * Send query to name server and wait for reply.
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/malloc.h>
49 #include <sys/socket.h>
50 #include <netinet/in.h>
51 #include <sys/errno.h>
53 #include <arpa/nameser.h>
54 #include <api/resolv.h>
55 #include <kern/amiga_includes.h>
56 #include <api/apicalls.h>
57 #include <api/amiga_api.h>
58 #include <kern/amiga_subr.h>
59 #include <kern/amiga_netdb.h>
62 #ifndef AMITCP /* AmiTCP has this in the SocketBase */
63 static int res_sock
= -1; /* socket used for communications */
67 static const struct sockaddr no_addr
= { sizeof(struct sockaddr
), AF_INET
, { 0 } };
72 #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
73 #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
74 #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
75 #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
78 extern const char * const __sys_errlist
[];
79 #define Perror(string) Printf("%s: %s\n", string, __sys_errlist[readErrnoValue(libPtr)])
82 res_send(struct SocketBase
* libPtr
,
89 int try, v_circuit
, resplen
, nscount
;
90 int gotsomewhere
= 0, connected
= 0;
95 struct timeval timeout
;
97 struct sockaddr_in host
;
98 HEADER
*hp
= (HEADER
*) buf
;
99 HEADER
*anhp
= (HEADER
*) answer
;
100 u_char terrno
= ETIMEDOUT
;
101 #define JUNK_SIZE 512
102 char junk
[JUNK_SIZE
]; /* buffer for trash data */
104 #if defined(__AROS__)
105 D(bug("[AROSTCP](res_send.c) res_send()\n"));
106 D(bug("[AROSTCP](res_send.c) res_send: using socket %d\n", res_sock
));
110 printf("res_send()\n");
111 __p_query(buf
, libPtr
);
112 #endif /* RES_DEBUG */
114 v_circuit
= (_res
.options
& RES_USEVC
) || buflen
> PACKETSZ
;
117 * Send request, RETRY times, or until successful
119 for (try = 0; try < _res
.retry
; try++) {
120 #if defined(__AROS__)
121 D(bug("[AROSTCP](res_send.c) res_send: Attempt %d\n", try));
124 DRES(Printf("Retry #%ld\n",try);)
125 for (ns
= _res
.nsaddr_list
; ns
->s_addr
; ns
++) {
127 #if defined(__AROS__)
128 D(bug("[AROSTCP](res_send.c) res_send: Querying server #%ld address = %s\n", nscount
,
129 __inet_ntoa(ns
->s_addr
, libPtr
)));
133 Printf("Querying server #%ld address = %s\n", nscount
,
134 __Inet_NtoA(ns
->s_addr
, libPtr
));
135 #endif /* RES_DEBUG */
136 host
.sin_len
= sizeof(host
);
137 host
.sin_family
= AF_INET
;
138 host
.sin_port
= htons(NAMESERVER_PORT
);
139 host
.sin_addr
.s_addr
= ns
->s_addr
;
140 aligned_bzero_const(&host
.sin_zero
, sizeof(host
.sin_zero
));
143 #if defined(__AROS__)
144 D(bug("[AROSTCP](res_send.c) res_send: Using v_circuit\n"));
149 * Use virtual circuit;
150 * at most one attempt per server.
154 res_sock
= __socket(AF_INET
, SOCK_STREAM
, 0, libPtr
);
156 #if defined(__AROS__)
157 D(bug("[AROSTCP](res_send.c) res_send: Failed to create socket!!\n"));
158 terrno
= readErrnoValue(libPtr
);
161 Perror("socket (vc)");
162 #endif /* RES_DEBUG */
165 #if defined(__AROS__)
166 D(bug("[AROSTCP](res_send.c) res_send: created socket %d\n", res_sock
));
168 if (__connect(res_sock
,
169 (struct sockaddr
*)&host
,
170 sizeof(struct sockaddr
), libPtr
) < 0) {
171 #if defined(__AROS__)
172 D(bug("[AROSTCP](res_send.c) res_send: Failed to connect\n"));
174 terrno
= readErrnoValue(libPtr
);
176 Perror("connect (vc)");
177 #endif /* RES_DEBUG */
178 (void) __CloseSocket(res_sock
, libPtr
);
184 * Send length & message
186 len
= htons((u_short
)buflen
);
187 if ((__send(res_sock
, (char *)&len
, sizeof(len
), 0, libPtr
)
189 ((__send(res_sock
, (char *)buf
, buflen
, 0, libPtr
)
191 #if defined(__AROS__)
192 D(bug("[AROSTCP](res_send.c) res_send: Failed sending query\n"));
194 terrno
= readErrnoValue(libPtr
);
197 #endif /* RES_DEBUG */
198 (void) __CloseSocket(res_sock
, libPtr
);
203 * Receive length & response
208 (n
= __recv(res_sock
,
209 (char *)cp
, (int)len
, 0, libPtr
)) > 0) {
214 terrno
= readErrnoValue(libPtr
);
215 #if defined(__AROS__)
216 D(bug("[AROSTCP](res_send.c) res_send: Failed receiving response\n"));
220 #endif /* RES_DEBUG */
221 (void) __CloseSocket(res_sock
, libPtr
);
224 * A long running process might get its TCP
225 * connection reset if the remote server was
226 * restarted. Requery the server instead of
227 * trying a new one. When there is only one
228 * server, this means that a query might work
229 * instead of failing. We only allow one reset
230 * per query to prevent looping.
232 if (terrno
== ECONNRESET
&& !connreset
) {
239 if ((resplen
= ntohs(*(u_short
*)cp
)) > anslen
) {
240 #if defined(__AROS__)
241 D(bug("[AROSTCP](res_send.c) res_send: Truncated response\n"));
244 Printf("response truncated\n");
245 #endif /* RES_DEBUG */
251 (n
= __recv(res_sock
,
252 (char *)cp
, (int)len
, 0, libPtr
)) > 0) {
257 #if defined(__AROS__)
258 D(bug("[AROSTCP](res_send.c) res_send: Error receiving response\n"));
260 terrno
= readErrnoValue(libPtr
);
263 #endif /* RES_DEBUG */
264 (void) __CloseSocket(res_sock
, libPtr
);
270 * Flush rest of answer
271 * so connection stays in synch.
274 len
= resplen
- anslen
;
276 n
= (len
> JUNK_SIZE
? JUNK_SIZE
: len
);
277 if ((n
= __recv(res_sock
,
278 junk
, n
, 0, libPtr
)) > 0)
285 #if defined(__AROS__)
286 D(bug("[AROSTCP](res_send.c) res_send: Using datagrams\n"));
292 res_sock
= __socket(AF_INET
, SOCK_DGRAM
, 0, libPtr
);
294 #if defined(__AROS__)
295 D(bug("[AROSTCP](res_send.c) res_send: Failed to create socket\n"));
297 terrno
= readErrnoValue(libPtr
);
299 Perror("socket (dg)");
300 #endif /* RES_DEBUG */
305 * I'm tired of answering this question, so:
306 * On a 4.3BSD+ machine (client and server,
307 * actually), sending to a nameserver datagram
308 * port with no nameserver will cause an
309 * ICMP port unreachable message to be returned.
310 * If our datagram socket is "connected" to the
311 * server, we get an ECONNREFUSED error on the next
312 * socket operation, and select returns if the
313 * error message is received. We can thus detect
314 * the absence of a nameserver without timing out.
315 * If we have sent queries to at least two servers,
316 * however, we don't want to remain connected,
317 * as we wish to receive answers from the first
320 /* TODO*: see comment here .. */
321 /* This piece of code still behaves slightly wrong in
322 case of ECONNREFUSED error. On next retry socket will
323 be in disconnected state and instead of getting
324 ECONNREFUSED again we'll timeout in WaitSelect() and
325 get ETIMEDOUT. However, this is not critical and is
326 queued for future - Pavel Fedin*/
327 if (try == 0 && nscount
== 1) {
329 * Don't use connect if we might
330 * still receive a response
331 * from another server.
333 if (connected
== 0) {
334 if (__connect(res_sock
,
335 (struct sockaddr
*)&host
,
336 sizeof(struct sockaddr
),
338 #if defined(__AROS__)
339 D(bug("[AROSTCP](res_send.c) res_send: Error connecting\n"));
342 Perror("connect (dg)");
343 #endif /* RES_DEBUG */
349 buf
, buflen
, 0, libPtr
) != buflen
) {
350 #if defined(__AROS__)
351 D(bug("[AROSTCP](res_send.c) res_send: Error sending\n"));
355 #endif /* RES_DEBUG */
360 * Disconnect if we want to listen
361 * for responses from more than one server.
364 (void) __connect(res_sock
, &no_addr
,
365 sizeof(no_addr
), libPtr
);
368 if (__sendto(res_sock
, buf
, buflen
, 0,
369 (struct sockaddr
*)&host
,
370 sizeof(struct sockaddr
), libPtr
) != buflen
) {
371 #if defined(__AROS__)
372 D(bug("[AROSTCP](res_send.c) res_send: [__sendto] Error\n"));
375 Perror("sendto (dg)");
376 #endif /* RES_DEBUG */
384 timeout
.tv_sec
= (_res
.retrans
<< try);
386 timeout
.tv_sec
/= nscount
;
387 if (timeout
.tv_sec
<= 0)
392 FD_SET(res_sock
, &dsmask
);
393 n
= __WaitSelect(res_sock
+1, &dsmask
, NULL
,
394 NULL
, &timeout
, NULL
, libPtr
);
396 #if defined(__AROS__)
397 D(bug("[AROSTCP](res_send.c) res_send: [__WaitSelect] Error\n"));
401 #endif /* RES_DEBUG */
403 terrno
= readErrnoValue(libPtr
);
404 if (terrno
== EINTR
) {
405 #if defined(__AROS__)
406 D(bug("[AROSTCP](res_send.c) res_send: closing socket\n"));
408 __CloseSocket(res_sock
, libPtr
);
418 #if defined(__AROS__)
419 D(bug("[AROSTCP](res_send.c) res_send: Timeout!\n"));
423 #endif /* RES_DEBUG */
429 if ((resplen
= __recv(res_sock
,
430 answer
, anslen
, 0, libPtr
)) <= 0) {
431 #if defined(__AROS__)
432 D(bug("[AROSTCP](res_send.c) res_send: Error receiving\n"));
436 #endif /* RES_DEBUG */
440 if (id
!= anhp
->id
) {
442 * response from old query, ignore it
445 Printf("old answer:\n");
446 __p_query(answer
, libPtr
);
447 #endif /* RES_DEBUG */
450 if (!(_res
.options
& RES_IGNTC
) && anhp
->tc
) {
452 * get rest of answer;
453 * use TCP with same server.
455 #if defined(__AROS__)
456 D(bug("[AROSTCP](res_send.c) res_send: Response is truncated\n"));
459 Printf("truncated answer\n");
460 #endif /* RES_DEBUG */
461 (void)__CloseSocket(res_sock
, libPtr
);
468 #if defined(__AROS__)
469 D(bug("[AROSTCP](res_send.c) res_send: Received answer\n"));
473 Printf("got answer:\n");
474 __p_query(answer
, libPtr
);
475 #endif /* RES_DEBUG */
477 * If using virtual circuits, we assume that the first server
478 * is preferred * over the rest (i.e. it is on the local
479 * machine) and only keep that one open.
480 * If we have temporarily opened a virtual circuit,
481 * or if we haven't been asked to keep a socket open,
485 ((_res
.options
& RES_USEVC
) == 0 || ns
->s_addr
!= 0)) ||
486 (_res
.options
& RES_STAYOPEN
) == 0) {
487 #if defined(__AROS__)
488 D(bug("[AROSTCP](res_send.c) res_send: Closing socket\n"));
490 (void) __CloseSocket(res_sock
, libPtr
);
497 #if defined(__AROS__)
498 D(bug("[AROSTCP](res_send.c) res_send: Closing open socket\n"));
500 (void) __CloseSocket(res_sock
, libPtr
);
506 if (gotsomewhere
== 0)
508 #if defined(__AROS__)
509 D(bug("[AROSTCP](res_send.c) res_send: No NAMESERVERs Found!\n"));
511 writeErrnoValue(libPtr
, ECONNREFUSED
); /* no nameservers found */
515 #if defined(__AROS__)
516 D(bug("[AROSTCP](res_send.c) res_send: No Response!\n"));
518 writeErrnoValue(libPtr
, ETIMEDOUT
); /* no answer obtained */
521 else writeErrnoValue(libPtr
, terrno
);
523 #if defined(__AROS__)
524 D(bug("[AROSTCP](res_send.c) res_send: Finished\n"));
527 DRES(Perror("res_send()");)
532 * This routine is for closing the socket if a virtual circuit is used and
533 * the program wants to close it. This provides support for endhostent()
534 * which expects to close the socket.
536 * This routine is not expected to be user visible.
539 _res_close(struct SocketBase
* libPtr
)
541 #if defined(__AROS__)
542 D(bug("[AROSTCP](res_send.c) _res_close()\n"));
544 if (res_sock
!= -1) {
545 #if defined(__AROS__)
546 D(bug("[AROSTCP](res_send.c) _res_close: Closing socket\n"));
548 (void) __CloseSocket(res_sock
, libPtr
);