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

📄 res_send.c

📁 KPIT GNU Tools is a set of GNU development tools for Renesas microcontrollers.
💻 C
📖 第 1 页 / 共 2 页
字号:
			 * Send length & message			 */			putshort((u_short)buflen, (u_char*)&len);#if !defined(_ELIX_LEVEL) || _ELIX_LEVEL >= 2			{			struct iovec iov[2];			iov[0].iov_base = (caddr_t)&len;			iov[0].iov_len = INT16SZ;			iov[1].iov_base = (caddr_t)buf;			iov[1].iov_len = buflen;			rc = writev(s, iov, 2);			}#else /* EL/IX level 1 */			{			char *tmpbuf;			tmpbuf = malloc (INT16SZ + buflen);			memcpy (tmpbuf, &len, INT16SZ);			memcpy (tmpbuf + INT16SZ, buf, buflen);			rc = write (s, tmpbuf, INT16SZ + buflen);			}#endif /* EL/IX level 1 */			if (rc != (INT16SZ + buflen)) {				terrno = errno;				Perror(stderr, "write failed", errno);				badns |= (1 << ns);				res_close();				goto next_ns;			}			/*			 * Receive length & response			 */ read_len:			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 = ns_get16(ans);			if (resplen > anssiz) {				Dprint(_res.options & RES_DEBUG,				       (stdout, ";; response truncated\n")				       );				truncated = 1;				len = anssiz;			} else				len = resplen;			if (len < HFIXEDSZ) {				/*				 * Undersized message.				 */				Dprint(_res.options & RES_DEBUG,				       (stdout, ";; undersized: %d\n", len));				terrno = EMSGSIZE;				badns |= (1 << ns);				res_close();				goto next_ns;			}			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[PACKETSZ];					n = (len > sizeof(junk)					     ? sizeof(junk)					     : len);					if ((n = read(s, junk, n)) > 0)						len -= n;					else						break;				}			}			/*			 * The calling applicating has bailed out of			 * a previous call and failed to arrange to have			 * the circuit closed or the server has got			 * itself confused. Anyway drop the packet and			 * wait for the correct one.			 */			if (hp->id != anhp->id) {				DprintQ((_res.options & RES_DEBUG) ||					(_res.pfcode & RES_PRF_REPLY),					(stdout, ";; old answer (unexpected):\n"),					ans, (resplen>anssiz)?anssiz:resplen);				goto read_len;			}		} else {			/*			 * Use datagrams.			 */			struct pollfd pfd[1];			int ptimeout;			struct timespec ts;			struct timeval timeout, ctv;			struct sockaddr_storage from;			int fromlen;			if (s < 0 || vc || af != nsap->sa_family) {				if (vc)					res_close();				af = nsap->sa_family;				s = socket(af, SOCK_DGRAM, 0);				if (s < 0) {#ifndef CAN_RECONNECT bad_dg_sock:#endif					terrno = errno;					Perror(stderr, "socket(dg)", errno);					badns |= (1 << ns);					res_close();					goto next_ns;				}				connected = 0;			}#ifndef CANNOT_CONNECT_DGRAM			/*			 * 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.			 *			 * When the option "insecure1" is specified, we'd			 * rather expect to see responses from an "unknown"			 * address.  In order to let the kernel accept such			 * responses, do not connect the socket here.			 * XXX: or do we need an explicit option to disable			 * connecting?			 */			if (!(_res.options & RES_INSECURE1) &&			    (_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, nsap, salen) < 0) {						Aerror(stderr,						       "connect(dg)",						       errno, nsap);						badns |= (1 << ns);						res_close();						goto next_ns;					}					connected = 1;				}				if (send(s, (char*)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) {#ifdef CAN_RECONNECT					/* XXX: any errornous address */					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, SOCK_DGRAM,0);					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 /* CAN_RECONNECT */					connected = 0;					errno = 0;				}#endif /* !CANNOT_CONNECT_DGRAM */				if (sendto(s, (char*)buf, buflen, 0,					   nsap, salen) != buflen) {					Aerror(stderr, "sendto", errno, nsap);					badns |= (1 << ns);					res_close();					goto next_ns;				}#ifndef CANNOT_CONNECT_DGRAM			}#endif /* !CANNOT_CONNECT_DGRAM */			/*			 * 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;			TIMEVAL_TO_TIMESPEC(&timeout, &ts);			(void) gettimeofday(&ctv, NULL);			timeradd(&timeout, &ctv, &timeout);		       /* Convert struct timespec in milliseconds.  */		       ptimeout = timeout.tv_sec * 1000 + timeout.tv_usec / 1000;    wait:		       pfd[0].fd = s;		       pfd[0].events = POLLIN;		       n = poll (pfd, 1, ptimeout);			if (s < 0) {				Perror(stderr, "s out-of-bounds", EMFILE);				res_close();				goto next_ns;			}			if (n < 0) {				if (errno == EINTR) {					(void) gettimeofday(&ctv, NULL);					if (timercmp(&ctv, &timeout, <)) {						timersub(&timeout, &ctv, &ctv);						TIMEVAL_TO_TIMESPEC(&ctv, &ts);						goto wait;					}				}				Perror(stderr, "poll", 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;			}			errno = 0;			fromlen = sizeof(from);			resplen = recvfrom(s, (char*)ans, anssiz, 0,					   (struct sockaddr *)&from, &fromlen);			if (resplen <= 0) {				Perror(stderr, "recvfrom", errno);				res_close();				goto next_ns;			}			gotsomewhere = 1;			if (resplen < HFIXEDSZ) {				/*				 * Undersized message.				 */				Dprint(_res.options & RES_DEBUG,				       (stdout, ";; undersized: %d\n",					resplen));				terrno = EMSGSIZE;				badns |= (1 << ns);				res_close();				goto next_ns;			}			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, (resplen>anssiz)?anssiz:resplen);				goto wait;			}#ifdef CHECK_SRVR_ADDR			if (!(_res.options & RES_INSECURE1) &&			    !res_isourserver((struct sockaddr_in *)&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, (resplen>anssiz)?anssiz:resplen);				goto wait;			}#endif			if (!(_res.options & RES_INSECURE2) &&			    !res_queriesmatch(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, (resplen>anssiz)?anssiz:resplen);				goto wait;			}			if (anhp->rcode == SERVFAIL ||			    anhp->rcode == NOTIMP ||			    anhp->rcode == REFUSED) {				DprintQ(_res.options & RES_DEBUG,					(stdout, "server rejected query:\n"),					ans, (resplen>anssiz)?anssiz:resplen);				badns |= (1 << ns);				res_close();				/* don't retry if called from dig */				if (!_res.pfcode)					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*/		Dprint((_res.options & RES_DEBUG) ||		       ((_res.pfcode & RES_PRF_REPLY) &&			(_res.pfcode & RES_PRF_HEAD1)),		       (stdout, ";; got answer:\n"));#if 0		DprintQ((_res.options & RES_DEBUG) ||			(_res.pfcode & RES_PRF_REPLY),			(stdout, ""),			ans, (resplen>anssiz)?anssiz:resplen);#endif		/*		 * 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)((struct sockaddr_in *)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:					close(kq);					return (-1);				}			} while (!done);		}		close(kq);		return (resplen);    next_ns: ;	   } /*foreach ns*/	} /*foreach retry*/	res_close();	close(kq);	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. */voidres_close(){	if (s >= 0) {		(void)close(s);		s = -1;		connected = 0;		vc = 0;		af = 0;	}}/* * Weak aliases for applications that use certain private entry points, * and fail to include <resolv.h>. */#undef res_close__weak_reference(__res_close, _res_close);#undef res_send__weak_reference(__res_send, res_send);

⌨️ 快捷键说明

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