summary refs log tree commit diff
path: root/resolv
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2009-04-07 02:00:27 +0000
committerUlrich Drepper <drepper@redhat.com>2009-04-07 02:00:27 +0000
commitae06191038e8757bc9ba637c7c94f2e02817b43b (patch)
tree67e37d19c72eeffa82c97e4d40732dfedce930f1 /resolv
parent735be400144a70658c635382a74653582d50c835 (diff)
downloadglibc-ae06191038e8757bc9ba637c7c94f2e02817b43b.tar.gz
glibc-ae06191038e8757bc9ba637c7c94f2e02817b43b.tar.xz
glibc-ae06191038e8757bc9ba637c7c94f2e02817b43b.zip
* resolv/resolv.h (RES_SNGLKUP): Define. cvs/fedora-glibc-20090407T0545
	* resolv/res_init.c (res_setoptions): Recognize single-request option.
	* resolv/res_send.c (send_dg): If we sent two requests at once and
	only get one reply before timeout switch to mode where we send the
	second request only after the first answer has been received.
Diffstat (limited to 'resolv')
-rw-r--r--resolv/res_init.c3
-rw-r--r--resolv/res_send.c37
-rw-r--r--resolv/resolv.h1
3 files changed, 30 insertions, 11 deletions
diff --git a/resolv/res_init.c b/resolv/res_init.c
index 2bf830cc95..8841fe9faa 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -540,6 +540,9 @@ res_setoptions(res_state statp, const char *options, const char *source) {
 			statp->options |= RES_NOCHECKNAME;
                 } else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) {
 			statp->options |= RES_USE_EDNS0;
+                } else if (!strncmp(cp, "single-request",
+				    sizeof("single-request") - 1)) {
+			statp->options |= RES_SNGLKUP;
 		} else {
 			/* XXX - print a warning here? */
 		}
diff --git a/resolv/res_send.c b/resolv/res_send.c
index f75a26ec23..0490b52fca 100644
--- a/resolv/res_send.c
+++ b/resolv/res_send.c
@@ -923,12 +923,12 @@ send_dg(res_state statp,
 	struct pollfd pfd[1];
         int ptimeout;
 	struct sockaddr_in6 from;
-	int resplen, seconds, n;
+	int resplen, n;
 
 	if (EXT(statp).nssocks[ns] == -1) {
 		/* only try IPv6 if IPv6 NS and if not failed before */
 		if ((EXT(statp).nscount6 > 0) && !statp->ipv6_unavail) {
-			if (__have_o_nonblock >= 0) {
+			if (__builtin_expect (__have_o_nonblock >= 0, 1)) {
 				EXT(statp).nssocks[ns] =
 				  socket(PF_INET6, SOCK_DGRAM|SOCK_NONBLOCK,
 					 0);
@@ -939,7 +939,7 @@ send_dg(res_state statp,
 					     && errno == EINVAL ? -1 : 1);
 #endif
 			}
-			if (__have_o_nonblock < 0)
+			if (__builtin_expect (__have_o_nonblock < 0, 0))
 				EXT(statp).nssocks[ns] =
 				  socket(PF_INET6, SOCK_DGRAM, 0);
 			if (EXT(statp).nssocks[ns] < 0)
@@ -950,7 +950,7 @@ send_dg(res_state statp,
 			    convaddr4to6(nsap);
 		}
 		if (EXT(statp).nssocks[ns] < 0) {
-			if (__have_o_nonblock >= 0) {
+			if (__builtin_expect (__have_o_nonblock >= 0, 1)) {
 				EXT(statp).nssocks[ns]
 				  = socket(PF_INET, SOCK_DGRAM|SOCK_NONBLOCK,
 					   0);
@@ -961,7 +961,7 @@ send_dg(res_state statp,
 					     && errno == EINVAL ? -1 : 1);
 #endif
 			}
-			if (__have_o_nonblock < 0)
+			if (__builtin_expect (__have_o_nonblock < 0, 0))
 				EXT(statp).nssocks[ns]
 				  = socket(PF_INET, SOCK_DGRAM, 0);
 		}
@@ -989,7 +989,7 @@ send_dg(res_state statp,
 			__res_iclose(statp, false);
 			return (0);
 		}
-		if (__have_o_nonblock < 0) {
+		if (__builtin_expect (__have_o_nonblock < 0, 0)) {
 			/* Make socket non-blocking.  */
 			int fl = __fcntl (EXT(statp).nssocks[ns], F_GETFL);
 			if  (fl != -1)
@@ -1003,11 +1003,14 @@ send_dg(res_state statp,
 	/*
 	 * Compute time for the total operation.
 	 */
-	seconds = (statp->retrans << ns);
+	int seconds = (statp->retrans << ns);
 	if (ns > 0)
 		seconds /= statp->nscount;
 	if (seconds <= 0)
 		seconds = 1;
+	bool single_request = ((statp->options) & RES_SNGLKUP) != 0;// XXX
+	int save_gotsomewhere = *gotsomewhere;
+ retry:
 	evNowTime(&now);
 	evConsTime(&timeout, seconds, 0);
 	evAddTime(&finish, &now, &timeout);
@@ -1031,6 +1034,7 @@ send_dg(res_state statp,
 			return (0);
 		}
 		evSubTime(&timeout, &finish, &now);
+		need_recompute = 0;
 	}
         /* Convert struct timespec in milliseconds.  */
 	ptimeout = timeout.tv_sec * 1000 + timeout.tv_nsec / 1000000;
@@ -1046,8 +1050,16 @@ send_dg(res_state statp,
 		Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
 		if (resplen > 1 && (recvresp1 || (buf2 != NULL && recvresp2)))
 		  {
-		    *resplen2 = 1;
-		    return resplen;
+		    /* There are quite a few broken name servers out
+		       there which don't handle two outstanding
+		       requests from the same source.  There are also
+		       broken firewall settings.  If we time out after
+		       having received one answer switch to the mode
+		       where we send the second request only once we
+		       have received the first answer.  */
+		    single_request = true;
+		    *gotsomewhere = save_gotsomewhere;
+		    goto retry;
 		  }
 
 		*gotsomewhere = 1;
@@ -1073,7 +1085,7 @@ send_dg(res_state statp,
 			Perror(statp, stderr, "send", errno);
 			goto err_out;
 		}
-		if (nwritten != 0 || buf2 == NULL)
+		if (nwritten != 0 || buf2 == NULL || single_request)
 		  pfd[0].events = POLLIN;
 		else
 		  pfd[0].events = POLLIN | POLLOUT;
@@ -1286,8 +1298,11 @@ send_dg(res_state statp,
 		else
 			recvresp2 = 1;
 		/* Repeat waiting if we have a second answer to arrive.  */
-		if ((recvresp1 & recvresp2) == 0)
+		if ((recvresp1 & recvresp2) == 0) {
+			if (single_request)
+				pfd[0].events = POLLOUT;
 			goto wait;
+		}
 		/*
 		 * All is well, or the error is fatal.  Signal that the
 		 * next nameserver ought not be tried.
diff --git a/resolv/resolv.h b/resolv/resolv.h
index a0de320d0f..c6e695dc72 100644
--- a/resolv/resolv.h
+++ b/resolv/resolv.h
@@ -215,6 +215,7 @@ struct res_sym {
 #define RES_NOIP6DOTINT	0x00080000	/* Do not use .ip6.int in IPv6
 					   reverse lookup */
 #define RES_USE_EDNS0	0x00100000	/* Use EDNS0.  */
+#define RES_SNGLKUP	0x00200000	/* one outstanding request at a time */
 
 #define RES_DEFAULT	(RES_RECURSE|RES_DEFNAMES|RES_DNSRCH|RES_NOIP6DOTINT)