about summary refs log tree commit diff
path: root/resolv
diff options
context:
space:
mode:
Diffstat (limited to 'resolv')
-rw-r--r--resolv/res_send.c264
1 files changed, 127 insertions, 137 deletions
diff --git a/resolv/res_send.c b/resolv/res_send.c
index ca3e630868..18e54dbcda 100644
--- a/resolv/res_send.c
+++ b/resolv/res_send.c
@@ -73,6 +73,7 @@ static const char rcsid[] = "$BINDId: res_send.c,v 8.38 2000/03/30 20:16:51 vixi
  * Send query to name server and wait for reply.
  */
 
+#include <assert.h>
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/time.h>
@@ -808,7 +809,7 @@ send_dg(res_state statp,
         int ptimeout;
 	struct sockaddr_in6 from;
 	static int socket_pf = 0;
-	int fromlen, resplen, seconds, n, s;
+	int fromlen, resplen, seconds, n;
 
 	if (EXT(statp).nssocks[ns] == -1) {
 		/* only try IPv6 if IPv6 NS and if not failed before */
@@ -854,7 +855,7 @@ send_dg(res_state statp,
 		Dprint(statp->options & RES_DEBUG,
 		       (stdout, ";; new DG socket\n"))
 	}
-	s = EXT(statp).nssocks[ns];
+
 	/*
 	 * Compute time for the total operation.
 	 */
@@ -867,13 +868,25 @@ send_dg(res_state statp,
 	evConsTime(&timeout, seconds, 0);
 	evAddTime(&finish, &now, &timeout);
 	int need_recompute = 0;
- resend:
+	int nwritten = 0;
+	pfd[0].fd = EXT(statp).nssocks[ns];
+	pfd[0].events = POLLOUT;
+ wait:
+	if (need_recompute) {
+		evNowTime(&now);
+		if (evCmpTime(finish, now) <= 0) {
+			Perror(statp, stderr, "select", errno);
+			res_nclose(statp);
+			return (0);
+		}
+		evSubTime(&timeout, &finish, &now);
+	}
         /* Convert struct timespec in milliseconds.  */
 	ptimeout = timeout.tv_sec * 1000 + timeout.tv_nsec / 1000000;
 
-	pfd[0].fd = s;
-	pfd[0].events = POLLOUT;
-	n = __poll (pfd, 1, 0);
+	n = 0;
+	if (nwritten == 0)
+	  n = __poll (pfd, 1, 0);
 	if (__builtin_expect (n == 0, 0)) {
 		n = __poll (pfd, 1, ptimeout);
 		need_recompute = 1;
@@ -890,7 +903,7 @@ send_dg(res_state statp,
 			evNowTime(&now);
 			if (evCmpTime(finish, now) > 0) {
 				evSubTime(&timeout, &finish, &now);
-				goto resend;
+				goto wait;
 			}
 		}
 		Perror(statp, stderr, "select", errno);
@@ -898,149 +911,126 @@ send_dg(res_state statp,
 		return (0);
 	}
 	__set_errno (0);
-	if (send(s, (char*)buf, buflen, 0) != buflen) {
-		if (errno == EINTR || errno == EAGAIN)
-			goto recompute_resend;
-		Perror(statp, stderr, "send", errno);
-		res_nclose(statp);
-		return (0);
-	}
-
- wait:
-	if (need_recompute) {
-		evNowTime(&now);
-		if (evCmpTime(finish, now) <= 0) {
-		err_return:
-			Perror(statp, stderr, "select", errno);
+	if (pfd[0].revents & POLLOUT) {
+		if (send(pfd[0].fd, (char*)buf, buflen, 0) != buflen) {
+			if (errno == EINTR || errno == EAGAIN)
+				goto recompute_resend;
+			Perror(statp, stderr, "send", errno);
 			res_nclose(statp);
 			return (0);
 		}
-		evSubTime(&timeout, &finish, &now);
-	}
-        /* Convert struct timespec in milliseconds.  */
-	ptimeout = timeout.tv_sec * 1000 + timeout.tv_nsec / 1000000;
+		pfd[0].events = POLLIN;
+		++nwritten;
+		goto wait;
+	} else {
+		assert(pfd[0].revents & POLLIN);
 
-	pfd[0].events = POLLIN;
-	n = __poll (pfd, 1, ptimeout);
-	if (n == 0) {
-		Dprint(statp->options & RES_DEBUG, (stdout,
-						    ";; timeout receiving\n"));
+		fromlen = sizeof(struct sockaddr_in6);
+		if (anssiz < MAXPACKET
+		    && anscp
+		    && (ioctl (pfd[0].fd, FIONREAD, &resplen) < 0
+		|| anssiz < resplen)) {
+			ans = malloc (MAXPACKET);
+			if (ans == NULL)
+				ans = *ansp;
+			else {
+				anssiz = MAXPACKET;
+				*anssizp = MAXPACKET;
+				*ansp = ans;
+				*anscp = ans;
+				anhp = (HEADER *) ans;
+			}
+		}
+		resplen = recvfrom(pfd[0].fd, (char*)ans, anssiz,0,
+				   (struct sockaddr *)&from, &fromlen);
+		if (resplen <= 0) {
+			if (errno == EINTR || errno == EAGAIN) {
+				need_recompute = 1;
+				goto wait;
+			}
+			Perror(statp, stderr, "recvfrom", errno);
+			res_nclose(statp);
+			return (0);
+		}
 		*gotsomewhere = 1;
-		return (0);
-	}
-	if (n < 0) {
-		if (errno == EINTR) {
-			need_recompute = 1;
+		if (resplen < HFIXEDSZ) {
+			/*
+			 * Undersized message.
+			 */
+			Dprint(statp->options & RES_DEBUG,
+			       (stdout, ";; undersized: %d\n",
+				resplen));
+			*terrno = EMSGSIZE;
+			res_nclose(statp);
+			return (0);
+		}
+		if (hp->id != anhp->id) {
+			/*
+			 * response from old query, ignore it.
+			 * XXX - potential security hazard could
+			 *	 be detected here.
+			 */
+			DprintQ((statp->options & RES_DEBUG) ||
+				(statp->pfcode & RES_PRF_REPLY),
+				(stdout, ";; old answer:\n"),
+				ans, (resplen > anssiz) ? anssiz : resplen);
 			goto wait;
 		}
-		goto err_return;
-	}
-	__set_errno (0);
-	fromlen = sizeof(struct sockaddr_in6);
-	if (anssiz < MAXPACKET
-	    && anscp
-	    && (ioctl (s, FIONREAD, &resplen) < 0
-		|| anssiz < resplen)) {
-		ans = malloc (MAXPACKET);
-		if (ans == NULL)
-			ans = *ansp;
-		else {
-			anssiz = MAXPACKET;
-			*anssizp = MAXPACKET;
-			*ansp = ans;
-			*anscp = ans;
-			anhp = (HEADER *) ans;
+		if (!(statp->options & RES_INSECURE1) &&
+		    !res_ourserver_p(statp, &from)) {
+			/*
+			 * response from wrong server? ignore it.
+			 * XXX - potential security hazard could
+			 *	 be detected here.
+			 */
+			DprintQ((statp->options & RES_DEBUG) ||
+				(statp->pfcode & RES_PRF_REPLY),
+				(stdout, ";; not our server:\n"),
+				ans, (resplen > anssiz) ? anssiz : resplen);
+			goto wait;
 		}
-	}
-	resplen = recvfrom(s, (char*)ans, anssiz,0,
-			   (struct sockaddr *)&from, &fromlen);
-	if (resplen <= 0) {
-		if (errno == EINTR || errno == EAGAIN) {
-			need_recompute = 1;
+		if (!(statp->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((statp->options & RES_DEBUG) ||
+				(statp->pfcode & RES_PRF_REPLY),
+				(stdout, ";; wrong query name:\n"),
+				ans, (resplen > anssiz) ? anssiz : resplen);
 			goto wait;
 		}
-		Perror(statp, stderr, "recvfrom", errno);
-		res_nclose(statp);
-		return (0);
-	}
-	*gotsomewhere = 1;
-	if (resplen < HFIXEDSZ) {
-		/*
-		 * Undersized message.
-		 */
-		Dprint(statp->options & RES_DEBUG,
-		       (stdout, ";; undersized: %d\n",
-			resplen));
-		*terrno = EMSGSIZE;
-		res_nclose(statp);
-		return (0);
-	}
-	if (hp->id != anhp->id) {
-		/*
-		 * response from old query, ignore it.
-		 * XXX - potential security hazard could
-		 *	 be detected here.
-		 */
-		DprintQ((statp->options & RES_DEBUG) ||
-			(statp->pfcode & RES_PRF_REPLY),
-			(stdout, ";; old answer:\n"),
-			ans, (resplen > anssiz) ? anssiz : resplen);
-		goto wait;
-	}
-	if (!(statp->options & RES_INSECURE1) &&
-	    !res_ourserver_p(statp, &from)) {
-		/*
-		 * response from wrong server? ignore it.
-		 * XXX - potential security hazard could
-		 *	 be detected here.
-		 */
-		DprintQ((statp->options & RES_DEBUG) ||
-			(statp->pfcode & RES_PRF_REPLY),
-			(stdout, ";; not our server:\n"),
-			ans, (resplen > anssiz) ? anssiz : resplen);
-		goto wait;
-	}
-	if (!(statp->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((statp->options & RES_DEBUG) ||
-			(statp->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(statp->options & RES_DEBUG,
-			(stdout, "server rejected query:\n"),
-			ans, (resplen > anssiz) ? anssiz : resplen);
-		res_nclose(statp);
-		/* don't retry if called from dig */
-		if (!statp->pfcode)
-			return (0);
-	}
-	if (!(statp->options & RES_IGNTC) && anhp->tc) {
+		if (anhp->rcode == SERVFAIL ||
+		    anhp->rcode == NOTIMP ||
+		    anhp->rcode == REFUSED) {
+			DprintQ(statp->options & RES_DEBUG,
+				(stdout, "server rejected query:\n"),
+				ans, (resplen > anssiz) ? anssiz : resplen);
+			res_nclose(statp);
+			/* don't retry if called from dig */
+			if (!statp->pfcode)
+				return (0);
+		}
+		if (!(statp->options & RES_IGNTC) && anhp->tc) {
+			/*
+			 * To get the rest of answer,
+			 * use TCP with same server.
+			 */
+			Dprint(statp->options & RES_DEBUG,
+			       (stdout, ";; truncated answer\n"));
+			*v_circuit = 1;
+			res_nclose(statp);
+			return (1);
+		}
 		/*
-		 * To get the rest of answer,
-		 * use TCP with same server.
+		 * All is well, or the error is fatal.  Signal that the
+		 * next nameserver ought not be tried.
 		 */
-		Dprint(statp->options & RES_DEBUG,
-		       (stdout, ";; truncated answer\n"));
-		*v_circuit = 1;
-		res_nclose(statp);
-		return (1);
+		return (resplen);
 	}
-	/*
-	 * All is well, or the error is fatal.  Signal that the
-	 * next nameserver ought not be tried.
-	 */
-	return (resplen);
 }
 
 #ifdef DEBUG