📄 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 _MINIXstatic 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 + -