⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 res_send.c

📁 一个C源代码分析器
💻 C
📖 第 1 页 / 共 2 页
字号:
					_res_close();					goto next_ns;				}				vc = 1;			}			/*			 * Send length & message			 */			putshort((u_short)buflen, (u_char*)&len);			iov[0].iov_base = (caddr_t)&len;			iov[0].iov_len = INT16SZ;			iov[1].iov_base = (caddr_t)buf;			iov[1].iov_len = buflen;			if (writev(s, iov, 2) != (INT16SZ + buflen)) {				terrno = errno;				Perror(stderr, "write failed", errno);				badns |= (1<<ns);				_res_close();				goto next_ns;			}			/*			 * Receive length & response			 */			cp = ans;			len = INT16SZ;			while ((n = read(s, (char *)cp, (int)len)) > 0) {				cp += n;				if ((len -= n) <= 0)					break;			}			if (n <= 0) {				terrno = errno;				Perror(stderr, "read failed", errno);				_res_close();				/*				 * 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;					_res_close();					goto same_ns;				}				_res_close();				goto next_ns;			}			resplen = _getshort(ans);			if (resplen > anssiz) {				Dprint(_res.options & RES_DEBUG,				       (stdout, ";; response truncated\n")				       );				truncated = 1;				len = anssiz;			} else				len = resplen;			cp = ans;			while (len != 0 &&			       (n = read(s, (char *)cp, (int)len)) > 0			       ) {				cp += n;				len -= n;			}			if (n <= 0) {				terrno = errno;				Perror(stderr, "read(vc)", errno);				_res_close();				goto next_ns;			}			if (truncated) {				/*				 * Flush rest of answer				 * so connection stays in synch.				 */				anhp->tc = 1;				len = resplen - anssiz;				while (len != 0) {					char junk[512];					n = (len > sizeof(junk)					     ? sizeof(junk)					     : len);					if ((n = read(s, junk, n)) > 0)						len -= n;					else						break;				}			}		} else {			/*			 * Use datagrams.			 */			struct timeval	timeout;			fd_set		dsmask;			struct sockaddr_in from;			int		fromlen;			if ((s < 0) || vc) {				if (vc)					_res_close();				s = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC);				if (s < 0) { bad_dg_sock:				terrno = errno;					Perror(stderr, "socket(dg)", errno);					return (-1);				}				connected = 0;			}			/*			 * 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 (_res.nscount == 1 || (try == 0 && ns == 0)) {				/*				 * Connect only if we are sure we won't				 * receive a response from another server.				 */				if (!connected) {					if (connect(s,						    (struct sockaddr *)nsap,						    sizeof(struct sockaddr)						    ) < 0					    ) {						Aerror(stderr,						       "connect(dg)",						       errno, *nsap);						badns |= (1<<ns);						_res_close();						goto next_ns;					}					connected = 1;				}				if (send(s, buf, buflen, 0) != buflen) {					Perror(stderr, "send", errno);					badns |= (1<<ns);					_res_close();					goto next_ns;				}			} else {				/*				 * Disconnect if we want to listen				 * for responses from more than one server.				 */				if (connected) {#if defined(BSD) && (BSD >= 199103)					struct sockaddr_in no_addr;					no_addr.sin_family = AF_INET;					no_addr.sin_addr.s_addr = INADDR_ANY;					no_addr.sin_port = 0;					(void) connect(s,						       (struct sockaddr *)						        &no_addr,						       sizeof(no_addr));#else					int s1 = socket(AF_INET, SOCK_DGRAM,							PF_UNSPEC);					if (s1 < 0)						goto bad_dg_sock;					(void) dup2(s1, s);					(void) close(s1);					Dprint(_res.options & RES_DEBUG,					       (stdout, ";; new DG socket\n"))#endif					connected = 0;					errno = 0;				}				if (sendto(s, buf, buflen, 0,					   (struct sockaddr *)nsap,					   sizeof(struct sockaddr))				    != buflen) {					Aerror(stderr, "sendto", errno, *nsap);					badns |= (1<<ns);					_res_close();					goto next_ns;				}			}			/*			 * Wait for reply			 */			timeout.tv_sec = (_res.retrans << try);			if (try > 0)				timeout.tv_sec /= _res.nscount;			if ((long) 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) {				Perror(stderr, "select", errno);				_res_close();				goto next_ns;			}			if (n == 0) {				/*				 * timeout				 */				Dprint(_res.options & RES_DEBUG,				       (stdout, ";; timeout\n")				       );				gotsomewhere = 1;				_res_close();				goto next_ns;			}			fromlen = sizeof(struct sockaddr_in);			resplen = recvfrom(s, ans, anssiz, 0,					   (struct sockaddr *)&from, &fromlen);			if (resplen <= 0) {				Perror(stderr, "recvfrom", errno);				_res_close();				goto next_ns;			}			gotsomewhere = 1;			if (hp->id != anhp->id) {				/*				 * response from old query, ignore it.				 * XXX - potential security hazard could				 *	 be detected here.				 */				DprintQ((_res.options & RES_DEBUG) ||					(_res.pfcode & RES_PRF_REPLY),					(stdout, ";; old answer:\n"),					ans);				goto wait;			}#if CHECK_SRVR_ADDR			if (!(_res.options & RES_INSECURE1) &&			    !our_server(&from)) {				/*				 * response from wrong server? ignore it.				 * XXX - potential security hazard could				 *	 be detected here.				 */				DprintQ((_res.options & RES_DEBUG) ||					(_res.pfcode & RES_PRF_REPLY),					(stdout, ";; not our server:\n"),					ans);				goto wait;			}#endif			if (!(_res.options & RES_INSECURE2) &&			    !queries_match(buf, buf + buflen,					   ans, ans + anssiz)) {				/*				 * response contains wrong query? ignore it.				 * XXX - potential security hazard could				 *	 be detected here.				 */				DprintQ((_res.options & RES_DEBUG) ||					(_res.pfcode & RES_PRF_REPLY),					(stdout, ";; wrong query name:\n"),					ans);				goto wait;			}			if (anhp->rcode == SERVFAIL ||			    anhp->rcode == NOTIMP ||			    anhp->rcode == REFUSED) {				DprintQ(_res.options & RES_DEBUG,					(stdout, "server rejected query:\n"),					ans);				badns |= (1<<ns);				_res_close();				goto next_ns;			}			if (!(_res.options & RES_IGNTC) && anhp->tc) {				/*				 * get rest of answer;				 * use TCP with same server.				 */				Dprint(_res.options & RES_DEBUG,				       (stdout, ";; truncated answer\n")				       );				v_circuit = 1;				_res_close();				goto same_ns;			}		} /*if vc/dg*/		DprintQ((_res.options & RES_DEBUG) ||			(_res.pfcode & RES_PRF_REPLY),			(stdout, ";; got answer:\n"),			ans);		/*		 * 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) || ns != 0)) ||		    !(_res.options & RES_STAYOPEN)) {			_res_close();		}		if (Rhook) {			int done = 0, loops = 0;			do {				res_sendhookact act;				act = (*Rhook)(nsap,					       buf,					       buflen,					       ans,					       anssiz,					       &resplen);				switch (act) {				case res_goahead:				case res_done:					done = 1;					break;				case res_nextns:					_res_close();					goto next_ns;				case res_modified:					/* give the hook another try */					if (++loops < 42) /*doug adams*/						break;					/*FALLTHROUGH*/				case res_error:					/*FALLTHROUGH*/				default:					return (-1);				}			} while (!done);		}		return (resplen);    next_ns: ;	   } /*foreach ns*/	} /*foreach retry*/	_res_close();	if (!v_circuit) {		if (!gotsomewhere)			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 >= 0) {		(void) close(s);		s = -1;		connected = 0;		vc = 0;	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -