📄 res_send.c
字号:
/* * 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 * SUCH DAMAGE. */#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. */#if !_MINIX#include <sys/param.h>#include <sys/time.h>#include <sys/socket.h>#include <sys/uio.h>#include <netinet/in.h>#include <arpa/nameser.h>#include <stdio.h>#include <errno.h>#include <resolv.h>#include <unistd.h>#include <string.h>#else /* _MINIX */#include <sys/types.h>#include <sys/ioctl.h>#include <sys/stat.h>#include <assert.h>#include <errno.h>#include <fcntl.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <net/hton.h>#include <net/netlib.h>#include <net/gen/in.h>#include <net/gen/inet.h>#include <net/gen/netdb.h>#include <net/gen/nameser.h>#include <net/gen/resolv.h>#include <net/gen/tcp.h>#include <net/gen/tcp_io.h>#include <net/gen/udp.h>#include <net/gen/udp_hdr.h>#include <net/gen/udp_io.h>typedef u16_t u_short;static int tcp_connect _ARGS(( ipaddr_t host, Tcpport_t port, int *terrno ));static int tcpip_writeall _ARGS(( int fd, const char *buf, size_t siz ));static int udp_connect _ARGS(( void ));static int udp_sendto _ARGS(( int fd, const char *buf, unsigned buflen, ipaddr_t addr, Udpport_t port ));static int udp_receive _ARGS(( int fd, char *buf, unsigned buflen, time_t timeout ));static void alarm_handler _ARGS(( int sig ));#endif /* !_MINIX */static int s = -1; /* socket used for communications */#if !_MINIXstatic struct sockaddr no_addr;#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 /* FD_SET */#endif /* _MINIX */res_send(buf, buflen, answer, anslen) const char *buf; int buflen; char *answer; int anslen;{ register int n; int try, v_circuit, resplen, ns; int gotsomewhere = 0, connected = 0; int connreset = 0;#if !_MINIX u_short id, len;#else /* _MINIX */ u16_t id, len;#endif /* !_MINIX */ char *cp;#if !_MINIX fd_set dsmask; struct timeval timeout; HEADER *hp = (HEADER *) buf; HEADER *anhp = (HEADER *) answer; struct iovec iov[2];#else /* _MINIX */ time_t timeout; dns_hdr_t *hp = (dns_hdr_t *) buf; dns_hdr_t *anhp = (dns_hdr_t *) answer;#endif /* !_MINIX */ int terrno = ETIMEDOUT; char junk[512];#ifdef DEBUG if (_res.options & RES_DEBUG) { printf("res_send()\n"); __p_query(buf); }#endif /* DEBUG */ if (!(_res.options & RES_INIT)) if (res_init() == -1) { return(-1); } v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;#if !_MINIX id = hp->id;#else /* _MINIX */ id = hp->dh_id;#endif /* !_MINIX */ /* * Send request, RETRY times, or until successful */ for (try = 0; try < _res.retry; try++) { for (ns = 0; ns < _res.nscount; ns++) {#ifdef DEBUG#if !_MINIX if (_res.options & RES_DEBUG) printf("Querying server (# %d) address = %s\n", ns+1, inet_ntoa(_res.nsaddr_list[ns].sin_addr));#else /* _MINIX */ if (_res.options & RES_DEBUG) printf("Querying server (# %d) address = %s\n", ns+1, inet_ntoa(_res.nsaddr_list[ns]));#endif /* !_MINIX */#endif /* DEBUG */ usevc: if (v_circuit) {#if !_MINIX int truncated = 0; /* * Use virtual circuit; * at most one attempt per server. */ try = _res.retry; if (s < 0) { s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) { terrno = errno;#ifdef DEBUG if (_res.options & RES_DEBUG) perror("socket (vc) failed");#endif /* DEBUG */ continue; } if (connect(s, (struct sockaddr *)&(_res.nsaddr_list[ns]), sizeof(struct sockaddr)) < 0) { terrno = errno;#ifdef DEBUG if (_res.options & RES_DEBUG) perror("connect failed");#endif /* DEBUG */ (void) close(s); s = -1; continue; } } /* * Send length & message */ len = htons((u_short)buflen); iov[0].iov_base = (caddr_t)&len; iov[0].iov_len = sizeof(len); iov[1].iov_base = (char *)buf; iov[1].iov_len = buflen; if (writev(s, iov, 2) != sizeof(len) + buflen) { terrno = errno;#ifdef DEBUG if (_res.options & RES_DEBUG) perror("write failed");#endif /* DEBUG */ (void) close(s); s = -1; continue; } /* * Receive length & response */ cp = answer; len = sizeof(short); while (len != 0 && (n = read(s, (char *)cp, (int)len)) > 0) { cp += n; len -= n; } if (n <= 0) { terrno = errno;#ifdef DEBUG if (_res.options & RES_DEBUG) perror("read failed");#endif /* DEBUG */ (void) close(s); s = -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 DEBUG if (_res.options & RES_DEBUG) fprintf(stderr, "response truncated\n");#endif /* DEBUG */ len = anslen; truncated = 1; } else len = resplen; while (len != 0 && (n = read(s, (char *)cp, (int)len)) > 0) { cp += n; len -= n; } if (n <= 0) { terrno = errno;#ifdef DEBUG if (_res.options & RES_DEBUG) perror("read failed");#endif /* DEBUG */ (void) close(s); s = -1; continue; } if (truncated) { /* * Flush rest of answer * so connection stays in synch. */ anhp->tc = 1; len = resplen - anslen; while (len != 0) { n = (len > sizeof(junk) ? sizeof(junk) : len); if ((n = read(s, junk, n)) > 0) len -= n; else break; } }#else /* _MINIX */ int truncated = 0; int nbytes; /* * Use virtual circuit; * at most one attempt per server. */ try = _res.retry; if (s < 0) { s= tcp_connect(_res.nsaddr_list[ns], _res.nsport_list[ns], &terrno); if (s == -1) continue; } /* * Send length & message */ len = htons((u_short)buflen); nbytes= tcpip_writeall(s, (char *)&len, sizeof(len)); if (nbytes != sizeof(len)) { terrno= errno;#ifdef DEBUG if (_res.options & RES_DEBUG) fprintf(stderr, "write failed: %s\n", strerror(terrno));#endif /* DEBUG */ close(s); s= -1; continue; } nbytes= tcpip_writeall(s, buf, buflen); if (nbytes != buflen) { terrno= errno;#ifdef DEBUG if (_res.options & RES_DEBUG) fprintf(stderr, "write failed: %s\n", strerror(terrno));#endif /* DEBUG */ close(s); s= -1; continue; } /* * Receive length & response */ cp = answer; len = sizeof(short); while (len != 0) { n = read(s, (char *)cp, (int)len); if (n <= 0) break; cp += n; assert(len >= n); len -= n; } if (len) { terrno = errno;#ifdef DEBUG if (_res.options & RES_DEBUG) fprintf(stderr, "read failed: %s\n", strerror(terrno));#endif /* DEBUG */ close(s); s= -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 DEBUG if (_res.options & RES_DEBUG) fprintf(stderr, "response truncated\n");#endif /* DEBUG */ len = anslen; truncated = 1; } else len = resplen; while (len != 0) { n= read(s, (char *)cp, (int)len); if (n <= 0) break; cp += n; assert(len >= n); len -= n; } if (len) { terrno = errno;#ifdef DEBUG if (_res.options & RES_DEBUG) fprintf(stderr, "read failed: %s\n", strerror(terrno));#endif /* DEBUG */ close(s); s= -1; continue; } if (truncated) { /* * Flush rest of answer * so connection stays in synch. */ anhp->dh_flag1 |= DHF_TC; len = resplen - anslen; while (len != 0) { n = (len > sizeof(junk) ? sizeof(junk) : len); n = read(s, junk, n); if (n <= 0) { assert(len >= n); len -= n; } else break; } }#endif /* _MINIX */ } else {#if !_MINIX /* * Use datagrams. */ if (s < 0) { s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { terrno = errno;#ifdef DEBUG if (_res.options & RES_DEBUG) perror("socket (dg) failed");#endif /* DEBUG */ continue; } }#if BSD >= 43 /* * I'm tired of answering this question, so: * On a 4.3BSD+ machine (client and server,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -