tools/adflib: build only host variant which is used by Sam440 target
[AROS.git] / workbench / network / stacks / AROSTCP / bsdsocket / api / res_send.c
blob821e714cb91ffb2a01345034e6a94af6c78bdb59
1 /*
2 * Copyright (c) 1985, 1989 Regents of the University of California.
3 * All rights reserved.
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
8 * are met:
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.
43 #include <conf.h>
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/malloc.h>
48 #include <sys/time.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>
60 #include <stdio.h>
62 #ifndef AMITCP /* AmiTCP has this in the SocketBase */
63 static int res_sock = -1; /* socket used for communications */
64 #endif
66 /* constant */
67 static const struct sockaddr no_addr = { sizeof(struct sockaddr), AF_INET, { 0 } };
69 #ifndef FD_SET
70 #define NFDBITS 32
71 #define FD_SETSIZE 32
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)))
76 #endif
78 extern const char * const __sys_errlist[];
79 #define Perror(string) Printf("%s: %s\n", string, __sys_errlist[readErrnoValue(libPtr)])
81 int
82 res_send(struct SocketBase * libPtr,
83 const char * buf,
84 int buflen,
85 char * answer,
86 int anslen)
88 register int n;
89 int try, v_circuit, resplen, nscount;
90 int gotsomewhere = 0, connected = 0;
91 int connreset = 0;
92 u_short id, len;
93 char *cp;
94 fd_set dsmask;
95 struct timeval timeout;
96 struct in_addr *ns;
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));
107 #endif
109 #ifdef RES_DEBUG
110 printf("res_send()\n");
111 __p_query(buf, libPtr);
112 #endif /* RES_DEBUG */
114 v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
115 id = hp->id;
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));
122 #endif
123 nscount = 0;
124 DRES(Printf("Retry #%ld\n",try);)
125 for (ns = _res.nsaddr_list; ns->s_addr; ns++) {
126 nscount++;
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)));
130 #endif
132 #ifdef RES_DEBUG
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));
141 usevc:
142 if (v_circuit) {
143 #if defined(__AROS__)
144 D(bug("[AROSTCP](res_send.c) res_send: Using v_circuit\n"));
145 #endif
146 int truncated = 0;
149 * Use virtual circuit;
150 * at most one attempt per server.
152 try = _res.retry;
153 if (res_sock < 0) {
154 res_sock = __socket(AF_INET, SOCK_STREAM, 0, libPtr);
155 if (res_sock < 0) {
156 #if defined(__AROS__)
157 D(bug("[AROSTCP](res_send.c) res_send: Failed to create socket!!\n"));
158 terrno = readErrnoValue(libPtr);
159 #endif
160 #ifdef RES_DEBUG
161 Perror("socket (vc)");
162 #endif /* RES_DEBUG */
163 continue;
165 #if defined(__AROS__)
166 D(bug("[AROSTCP](res_send.c) res_send: created socket %d\n", res_sock));
167 #endif
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"));
173 #endif
174 terrno = readErrnoValue(libPtr);
175 #ifdef RES_DEBUG
176 Perror("connect (vc)");
177 #endif /* RES_DEBUG */
178 (void) __CloseSocket(res_sock, libPtr);
179 res_sock = -1;
180 continue;
184 * Send length & message
186 len = htons((u_short)buflen);
187 if ((__send(res_sock, (char *)&len, sizeof(len), 0, libPtr)
188 != sizeof(len)) ||
189 ((__send(res_sock, (char *)buf, buflen, 0, libPtr)
190 != buflen))) {
191 #if defined(__AROS__)
192 D(bug("[AROSTCP](res_send.c) res_send: Failed sending query\n"));
193 #endif
194 terrno = readErrnoValue(libPtr);
195 #ifdef RES_DEBUG
196 Perror("write(vc)");
197 #endif /* RES_DEBUG */
198 (void) __CloseSocket(res_sock, libPtr);
199 res_sock = -1;
200 continue;
203 * Receive length & response
205 cp = answer;
206 len = sizeof(short);
207 while (len != 0 &&
208 (n = __recv(res_sock,
209 (char *)cp, (int)len, 0, libPtr)) > 0) {
210 cp += n;
211 len -= n;
213 if (n <= 0) {
214 terrno = readErrnoValue(libPtr);
215 #if defined(__AROS__)
216 D(bug("[AROSTCP](res_send.c) res_send: Failed receiving response\n"));
217 #endif
218 #ifdef RES_DEBUG
219 Perror("read (vc)");
220 #endif /* RES_DEBUG */
221 (void) __CloseSocket(res_sock, libPtr);
222 res_sock = -1;
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) {
233 connreset = 1;
234 ns--;
236 continue;
238 cp = answer;
239 if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
240 #if defined(__AROS__)
241 D(bug("[AROSTCP](res_send.c) res_send: Truncated response\n"));
242 #endif
243 #ifdef RES_DEBUG
244 Printf("response truncated\n");
245 #endif /* RES_DEBUG */
246 len = anslen;
247 truncated = 1;
248 } else
249 len = resplen;
250 while (len != 0 &&
251 (n = __recv(res_sock,
252 (char *)cp, (int)len, 0, libPtr)) > 0) {
253 cp += n;
254 len -= n;
256 if (n <= 0) {
257 #if defined(__AROS__)
258 D(bug("[AROSTCP](res_send.c) res_send: Error receiving response\n"));
259 #endif
260 terrno = readErrnoValue(libPtr);
261 #ifdef RES_DEBUG
262 Perror("read (vc)");
263 #endif /* RES_DEBUG */
264 (void) __CloseSocket(res_sock, libPtr);
265 res_sock = -1;
266 continue;
268 if (truncated) {
270 * Flush rest of answer
271 * so connection stays in synch.
273 anhp->tc = 1;
274 len = resplen - anslen;
275 while (len != 0) {
276 n = (len > JUNK_SIZE ? JUNK_SIZE : len);
277 if ((n = __recv(res_sock,
278 junk, n, 0, libPtr)) > 0)
279 len -= n;
280 else
281 break;
284 } else {
285 #if defined(__AROS__)
286 D(bug("[AROSTCP](res_send.c) res_send: Using datagrams\n"));
287 #endif
289 * Use datagrams.
291 if (res_sock < 0) {
292 res_sock = __socket(AF_INET, SOCK_DGRAM, 0, libPtr);
293 if (res_sock < 0) {
294 #if defined(__AROS__)
295 D(bug("[AROSTCP](res_send.c) res_send: Failed to create socket\n"));
296 #endif
297 terrno = readErrnoValue(libPtr);
298 #ifdef RES_DEBUG
299 Perror("socket (dg)");
300 #endif /* RES_DEBUG */
301 continue;
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
318 * server to respond.
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),
337 libPtr) < 0) {
338 #if defined(__AROS__)
339 D(bug("[AROSTCP](res_send.c) res_send: Error connecting\n"));
340 #endif
341 #ifdef RES_DEBUG
342 Perror("connect (dg)");
343 #endif /* RES_DEBUG */
344 continue;
346 connected = 1;
348 if (__send(res_sock,
349 buf, buflen, 0, libPtr) != buflen) {
350 #if defined(__AROS__)
351 D(bug("[AROSTCP](res_send.c) res_send: Error sending\n"));
352 #endif
353 #ifdef RES_DEBUG
354 Perror("send (dg)");
355 #endif /* RES_DEBUG */
356 continue;
358 } else {
360 * Disconnect if we want to listen
361 * for responses from more than one server.
363 if (connected) {
364 (void) __connect(res_sock, &no_addr,
365 sizeof(no_addr), libPtr);
366 connected = 0;
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"));
373 #endif
374 #ifdef RES_DEBUG
375 Perror("sendto (dg)");
376 #endif /* RES_DEBUG */
377 continue;
382 * Wait for reply
384 timeout.tv_sec = (_res.retrans << try);
385 if (try > 0)
386 timeout.tv_sec /= nscount;
387 if (timeout.tv_sec <= 0)
388 timeout.tv_sec = 1;
389 timeout.tv_usec = 0;
390 wait:
391 FD_ZERO(&dsmask);
392 FD_SET(res_sock, &dsmask);
393 n = __WaitSelect(res_sock+1, &dsmask, NULL,
394 NULL, &timeout, NULL, libPtr);
395 if (n < 0) {
396 #if defined(__AROS__)
397 D(bug("[AROSTCP](res_send.c) res_send: [__WaitSelect] Error\n"));
398 #endif
399 #ifdef RES_DEBUG
400 Perror("select");
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"));
407 #endif
408 __CloseSocket(res_sock, libPtr);
409 res_sock = -1;
410 return (-1);
412 continue;
414 if (n == 0) {
416 * timeout
418 #if defined(__AROS__)
419 D(bug("[AROSTCP](res_send.c) res_send: Timeout!\n"));
420 #endif
421 #ifdef RES_DEBUG
422 Printf("timeout\n");
423 #endif /* RES_DEBUG */
424 #if 1 || BSD >= 43
425 gotsomewhere = 1;
426 #endif
427 continue;
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"));
433 #endif
434 #ifdef RES_DEBUG
435 Perror("recv (dg)");
436 #endif /* RES_DEBUG */
437 continue;
439 gotsomewhere = 1;
440 if (id != anhp->id) {
442 * response from old query, ignore it
444 #ifdef RES_DEBUG
445 Printf("old answer:\n");
446 __p_query(answer, libPtr);
447 #endif /* RES_DEBUG */
448 goto wait;
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"));
457 #endif
458 #ifdef RES_DEBUG
459 Printf("truncated answer\n");
460 #endif /* RES_DEBUG */
461 (void)__CloseSocket(res_sock, libPtr);
462 res_sock = -1;
463 v_circuit = 1;
464 goto usevc;
468 #if defined(__AROS__)
469 D(bug("[AROSTCP](res_send.c) res_send: Received answer\n"));
470 #endif
472 #ifdef RES_DEBUG
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,
482 * close the socket.
484 if ((v_circuit &&
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"));
489 #endif
490 (void) __CloseSocket(res_sock, libPtr);
491 res_sock = -1;
493 return (resplen);
496 if (res_sock >= 0) {
497 #if defined(__AROS__)
498 D(bug("[AROSTCP](res_send.c) res_send: Closing open socket\n"));
499 #endif
500 (void) __CloseSocket(res_sock, libPtr);
501 res_sock = -1;
504 if (v_circuit == 0)
506 if (gotsomewhere == 0)
508 #if defined(__AROS__)
509 D(bug("[AROSTCP](res_send.c) res_send: No NAMESERVERs Found!\n"));
510 #endif
511 writeErrnoValue(libPtr, ECONNREFUSED); /* no nameservers found */
513 else
515 #if defined(__AROS__)
516 D(bug("[AROSTCP](res_send.c) res_send: No Response!\n"));
517 #endif
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"));
525 #endif
527 DRES(Perror("res_send()");)
528 return (-1);
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.
538 void
539 _res_close(struct SocketBase * libPtr)
541 #if defined(__AROS__)
542 D(bug("[AROSTCP](res_send.c) _res_close()\n"));
543 #endif
544 if (res_sock != -1) {
545 #if defined(__AROS__)
546 D(bug("[AROSTCP](res_send.c) _res_close: Closing socket\n"));
547 #endif
548 (void) __CloseSocket(res_sock, libPtr);
549 res_sock = -1;