home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 8
/
FreshFishVol8-CD2.bin
/
bbs
/
comm
/
amitcp-3.0ß2.lha
/
AmiTCP
/
src
/
amitcp
/
api
/
res_send.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-04-02
|
12KB
|
431 lines
/*
* Copyright (c) 1985, 1989 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)res_send.c 6.27 (Berkeley) 2/24/91";
#endif /* LIBC_SCCS and not lint */
/*
* Send query to name server and wait for reply.
*/
#include <conf.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/errno.h>
#include <api/arpa_nameser.h>
#include <api/resolv.h>
#include <kern/amiga_includes.h>
#include <api/apicalls.h>
#include <api/amiga_api.h>
#include <kern/amiga_subr.h>
#include <kern/amiga_netdb.h>
#ifndef AMITCP /* AmiTCP has this in the SocketBase */
static int res_sock = -1; /* socket used for communications */
#endif
/* constant */
static const struct sockaddr no_addr = { sizeof(struct sockaddr), AF_INET, 0 };
#ifndef FD_SET
#define NFDBITS 32
#define FD_SETSIZE 32
#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
#endif
int
res_send(struct SocketBase * libPtr,
const char * buf,
int buflen,
char * answer,
int anslen)
{
register int n;
int try, v_circuit, resplen, nscount;
int gotsomewhere = 0, connected = 0;
int connreset = 0;
u_short id, len;
char *cp;
fd_set dsmask;
struct timeval timeout;
struct NameserventNode *ns;
struct sockaddr_in host;
HEADER *hp = (HEADER *) buf;
HEADER *anhp = (HEADER *) answer;
u_char terrno = ETIMEDOUT;
#define JUNK_SIZE 512
char junk[JUNK_SIZE]; /* buffer for trash data */
#ifdef RES_DEBUG
printf("res_send()\n");
__p_query(buf);
#endif /* RES_DEBUG */
v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
id = hp->id;
/*
* Send request, RETRY times, or until successful
*/
for (try = 0; try < _res.retry; try++) {
nscount = 0;
for (ns = (struct NameserventNode *)NDB->ndb_NameServers.mlh_Head;
ns->nsn_Node.mln_Succ;
ns = (struct NameserventNode *)ns->nsn_Node.mln_Succ) {
nscount++;
#ifdef RES_DEBUG
printf("Querying server #%d address = %s\n", nscount,
inet_ntoa(ns->nsn_Ent.ns_addr));
#endif /* RES_DEBUG */
host.sin_len = sizeof(host);
host.sin_family = AF_INET;
host.sin_port = NAMESERVER_PORT;
host.sin_addr = ns->nsn_Ent.ns_addr;
aligned_bzero_const(&host.sin_zero, sizeof(host.sin_zero));
usevc:
if (v_circuit) {
int truncated = 0;
/*
* Use virtual circuit;
* at most one attempt per server.
*/
try = _res.retry;
if (res_sock < 0) {
res_sock = socket(libPtr, AF_INET, SOCK_STREAM, 0);
if (res_sock < 0) {
terrno = readErrnoValue(libPtr);
#ifdef RES_DEBUG
perror("socket (vc) failed");
#endif /* RES_DEBUG */
continue;
}
if (connect(libPtr, res_sock,
(struct sockaddr *)&host,
sizeof(struct sockaddr)) < 0) {
terrno = readErrnoValue(libPtr);
#ifdef RES_DEBUG
perror("connect failed");
#endif /* RES_DEBUG */
(void) CloseSocket(libPtr, res_sock);
res_sock = -1;
continue;
}
}
/*
* Send length & message
*/
len = htons((u_short)buflen);
if ((send(libPtr, res_sock, (char *)&len, sizeof(len), 0)
!= sizeof(len)) ||
((send(libPtr, res_sock, (char *)buf, buflen, 0)
!= buflen))) {
terrno = readErrnoValue(libPtr);
#ifdef RES_DEBUG
perror("write failed");
#endif /* RES_DEBUG */
(void) CloseSocket(libPtr, res_sock);
res_sock = -1;
continue;
}
/*
* Receive length & response
*/
cp = answer;
len = sizeof(short);
while (len != 0 &&
(n = recv(libPtr, res_sock,
(char *)cp, (int)len, 0)) > 0) {
cp += n;
len -= n;
}
if (n <= 0) {
terrno = readErrnoValue(libPtr);
#ifdef RES_DEBUG
perror("read failed");
#endif /* RES_DEBUG */
(void) CloseSocket(libPtr, res_sock);
res_sock = -1;
/*
* A long running process might get its TCP
* connection reset if the remote server was
* restarted. Requery the server instead of
* trying a new one. When there is only one
* server, this means that a query might work
* instead of failing. We only allow one reset
* per query to prevent looping.
*/
if (terrno == ECONNRESET && !connreset) {
connreset = 1;
ns--;
}
continue;
}
cp = answer;
if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
#ifdef RES_DEBUG
fprintf(stderr, "response truncated\n");
#endif /* RES_DEBUG */
len = anslen;
truncated = 1;
} else
len = resplen;
while (len != 0 &&
(n = recv(libPtr, res_sock,
(char *)cp, (int)len, 0)) > 0) {
cp += n;
len -= n;
}
if (n <= 0) {
terrno = readErrnoValue(libPtr);
#ifdef RES_DEBUG
perror("read failed");
#endif /* RES_DEBUG */
(void) CloseSocket(libPtr, res_sock);
res_sock = -1;
continue;
}
if (truncated) {
/*
* Flush rest of answer
* so connection stays in synch.
*/
anhp->tc = 1;
len = resplen - anslen;
while (len != 0) {
n = (len > JUNK_SIZE ? JUNK_SIZE : len);
if ((n = recv(libPtr, res_sock,
junk, n, 0)) > 0)
len -= n;
else
break;
}
}
} else {
/*
* Use datagrams.
*/
if (res_sock < 0) {
res_sock = socket(libPtr, AF_INET, SOCK_DGRAM, 0);
if (res_sock < 0) {
terrno = readErrnoValue(libPtr);
#ifdef RES_DEBUG
perror("socket (dg) failed");
#endif /* RES_DEBUG */
continue;
}
}
/*
* I'm tired of answering this question, so:
* On a 4.3BSD+ machine (client and server,
* actually), sending to a nameserver datagram
* port with no nameserver will cause an
* ICMP port unreachable message to be returned.
* If our datagram socket is "connected" to the
* server, we get an ECONNREFUSED error on the next
* socket operation, and select returns if the
* error message is received. We can thus detect
* the absence of a nameserver without timing out.
* If we have sent queries to at least two servers,
* however, we don't want to remain connected,
* as we wish to receive answers from the first
* server to respond.
*/
if (tr