📄 res_send.c
字号:
* 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 (_res.nscount == 1 || (try == 0 && ns == 0)) {
/*
* Don't use connect if we might
* still receive a response
* from another server.
*/
if (connected == 0) {
if (connect(s, (struct sockaddr *)&_res.nsaddr_list[ns],
sizeof(struct sockaddr)) < 0) {
#ifdef DEBUG
if (_res.options & RES_DEBUG)
perror("connect");
#endif /* DEBUG */
continue;
}
connected = 1;
}
if (send(s, buf, buflen, 0) != buflen) {
#ifdef DEBUG
if (_res.options & RES_DEBUG)
perror("send");
#endif /* DEBUG */
continue;
}
} else {
/*
* Disconnect if we want to listen
* for responses from more than one server.
*/
if (connected) {
(void) connect(s, &no_addr,
sizeof(no_addr));
connected = 0;
}
#endif /* BSD */
if (sendto(s, buf, buflen, 0,
(struct sockaddr *)&_res.nsaddr_list[ns],
sizeof(struct sockaddr)) != buflen) {
#ifdef DEBUG
if (_res.options & RES_DEBUG)
perror("sendto");
#endif /* DEBUG */
continue;
}
#if BSD >= 43
}
#endif /* BSD */
/*
* Wait for reply
*/
timeout.tv_sec = (_res.retrans << try);
if (try > 0)
timeout.tv_sec /= _res.nscount;
if (timeout.tv_sec <= 0)
timeout.tv_sec = 1;
timeout.tv_usec = 0;
wait:
FD_ZERO(&dsmask);
FD_SET(s, &dsmask);
n = select(s+1, &dsmask, (fd_set *)NULL,
(fd_set *)NULL, &timeout);
if (n < 0) {
#ifdef DEBUG
if (_res.options & RES_DEBUG)
perror("select");
#endif /* DEBUG */
continue;
}
if (n == 0) {
/*
* timeout
*/
#ifdef DEBUG
if (_res.options & RES_DEBUG)
printf("timeout\n");
#endif /* DEBUG */
#if BSD >= 43
gotsomewhere = 1;
#endif
continue;
}
if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
#ifdef DEBUG
if (_res.options & RES_DEBUG)
perror("recvfrom");
#endif /* DEBUG */
continue;
}
gotsomewhere = 1;
if (id != anhp->id) {
/*
* response from old query, ignore it
*/
#ifdef DEBUG
if (_res.options & RES_DEBUG) {
printf("old answer:\n");
__p_query(answer);
}
#endif /* DEBUG */
goto wait;
}
if (!(_res.options & RES_IGNTC) && anhp->tc) {
/*
* get rest of answer;
* use TCP with same server.
*/
#ifdef DEBUG
if (_res.options & RES_DEBUG)
printf("truncated answer\n");
#endif /* DEBUG */
(void) close(s);
s = -1;
v_circuit = 1;
goto usevc;
}
#else /* _MINIX */
/*
* Use datagrams.
*/
if (s < 0) {
s = udp_connect();
if (s < 0) {
terrno = errno;
#ifdef DEBUG
if (_res.options & RES_DEBUG)
perror("udp_connect failed");
#endif /* DEBUG */
continue;
}
}
if (udp_sendto(s, buf, buflen, _res.nsaddr_list[ns],
_res.nsport_list[ns]) != buflen) {
#ifdef DEBUG
if (_res.options & RES_DEBUG)
perror("sendto");
#endif /* DEBUG */
continue;
}
/*
* Wait for reply
*/
timeout= (_res.retrans << try);
if (try > 0)
timeout /= _res.nscount;
if (timeout <= 0)
timeout= 1;
wait:
if ((resplen= udp_receive(s, answer, anslen, timeout))
== -1)
{
if (errno == EINTR)
{
/*
* timeout
*/
#ifdef DEBUG
if (_res.options & RES_DEBUG)
printf("timeout\n");
#endif /* DEBUG */
gotsomewhere = 1;
}
else
{
#ifdef DEBUG
if (_res.options & RES_DEBUG)
perror("udp_receive");
#endif /* DEBUG */
}
continue;
}
gotsomewhere = 1;
if (id != anhp->dh_id) {
/*
* response from old query, ignore it
*/
#ifdef DEBUG
if (_res.options & RES_DEBUG) {
printf("old answer:\n");
__p_query(answer);
}
#endif /* DEBUG */
goto wait;
}
if (!(_res.options & RES_IGNTC) &&
(anhp->dh_flag1 & DHF_TC)) {
/*
* get rest of answer;
* use TCP with same server.
*/
#ifdef DEBUG
if (_res.options & RES_DEBUG)
printf("truncated answer\n");
#endif /* DEBUG */
(void) close(s);
s = -1;
v_circuit = 1;
goto usevc;
}
#endif /* !_MINIX */
}
#ifdef DEBUG
if (_res.options & RES_DEBUG) {
printf("got answer:\n");
__p_query(answer);
}
#endif /* DEBUG */
/*
* If using virtual circuits, we assume that the first server
* is preferred * over the rest (i.e. it is on the local
* machine) and only keep that one open.
* If we have temporarily opened a virtual circuit,
* or if we haven't been asked to keep a socket open,
* close the socket.
*/
if ((v_circuit &&
((_res.options & RES_USEVC) == 0 || ns != 0)) ||
(_res.options & RES_STAYOPEN) == 0) {
(void) close(s);
s = -1;
}
return (resplen);
}
}
if (s >= 0) {
(void) close(s);
s = -1;
}
if (v_circuit == 0)
if (gotsomewhere == 0)
errno = ECONNREFUSED; /* no nameservers found */
else
errno = ETIMEDOUT; /* no answer obtained */
else
errno = terrno;
return (-1);
}
/*
* This routine is for closing the socket if a virtual circuit is used and
* the program wants to close it. This provides support for endhostent()
* which expects to close the socket.
*
* This routine is not expected to be user visible.
*/
void
_res_close()
{
if (s != -1) {
(void) close(s);
s = -1;
}
}
#if _MINIX
static int tcp_connect(host, port, terrno)
ipaddr_t host;
tcpport_t port;
int *terrno;
{
char *dev_name;
int fd;
int error;
nwio_tcpconf_t tcpconf;
nwio_tcpcl_t clopt;
dev_name= getenv("TCP_DEVICE");
if (!dev_name)
dev_name= TCP_DEVICE;
fd= open(dev_name, O_RDWR);
if (fd == -1)
{
*terrno= errno;
return -1;
}
tcpconf.nwtc_flags= NWTC_EXCL | NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP;
tcpconf.nwtc_remaddr= host;
tcpconf.nwtc_remport= port;
error= ioctl(fd, NWIOSTCPCONF, &tcpconf);
if (error == -1)
{
*terrno= errno;
close(fd);
return -1;
}
clopt.nwtcl_flags= 0;
error= ioctl(fd, NWIOTCPCONN, &clopt);
if (error == -1)
{
*terrno= errno;
close(fd);
return -1;
}
*terrno= 0;
return fd;
}
static int tcpip_writeall(fd, buf, siz)
int fd;
const char *buf;
size_t siz;
{
size_t siz_org;
int nbytes;
siz_org= siz;
while (siz)
{
nbytes= write(fd, buf, siz);
if (nbytes <= 0)
return siz_org-siz;
assert(siz >= nbytes);
buf += nbytes;
siz -= nbytes;
}
return siz_org;
}
static int udp_connect()
{
nwio_udpopt_t udpopt;
char *dev_name;
int fd, r, terrno;
dev_name= getenv("UDP_DEVICE");
if (!dev_name)
dev_name= UDP_DEVICE;
fd= open(dev_name, O_RDWR);
if (fd == -1)
return -1;
udpopt.nwuo_flags= NWUO_COPY | NWUO_LP_SEL | NWUO_EN_LOC |
NWUO_EN_BROAD | NWUO_RP_ANY | NWUO_RA_ANY | NWUO_RWDATALL |
NWUO_DI_IPOPT;
r= ioctl(fd, NWIOSUDPOPT, &udpopt);
if (r == -1)
{
terrno= errno;
close(fd);
errno= terrno;
return -1;
}
return fd;
}
static int udp_sendto(fd, buf, buflen, addr, port)
int fd;
const char *buf;
unsigned buflen;
ipaddr_t addr;
udpport_t port;
{
char *newbuf;
udp_io_hdr_t *udp_io_hdr;
int r, terrno;
newbuf= malloc(sizeof(*udp_io_hdr) + buflen);
if (newbuf == NULL)
{
errno= ENOMEM;
return -1;
}
udp_io_hdr= (udp_io_hdr_t *)newbuf;
udp_io_hdr->uih_dst_addr= addr;
udp_io_hdr->uih_dst_port= port;
udp_io_hdr->uih_ip_opt_len= 0;
udp_io_hdr->uih_data_len= buflen;
memcpy(newbuf + sizeof(*udp_io_hdr), buf, buflen);
r= write(fd, newbuf, sizeof(*udp_io_hdr) + buflen);
terrno= errno;
free(newbuf);
if (r >= sizeof(*udp_io_hdr))
r -= sizeof(*udp_io_hdr);
errno= terrno;
return r;
}
static void alarm_handler(sig)
int sig;
{
signal(SIGALRM, alarm_handler);
alarm(1);
}
static int udp_receive(fd, buf, buflen, timeout)
int fd;
char *buf;
unsigned buflen;
time_t timeout;
{
char *newbuf;
udp_io_hdr_t *udp_io_hdr;
int r, terrno;
void (*u_handler) _ARGS(( int sig ));
time_t u_timeout;
newbuf= malloc(sizeof(*udp_io_hdr) + buflen);
if (newbuf == NULL)
{
errno= ENOMEM;
return -1;
}
u_handler= signal(SIGALRM, alarm_handler);
u_timeout= alarm(timeout);
r= read(fd, newbuf, sizeof(*udp_io_hdr) + buflen);
terrno= errno;
if (r < 0 || r <= sizeof(*udp_io_hdr))
{
if (r > 0)
r= 0;
free(newbuf);
alarm(0);
signal(SIGALRM, u_handler);
alarm(u_timeout);
errno= terrno;
return r;
}
memcpy(buf, newbuf + sizeof(*udp_io_hdr), r - sizeof(*udp_io_hdr));
free(newbuf);
alarm(0);
signal(SIGALRM, u_handler);
alarm(u_timeout);
return r-sizeof(*udp_io_hdr);
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -