aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--resolv/res_init.c3
-rw-r--r--resolv/res_send.c37
-rw-r--r--resolv/resolv.h1
4 files changed, 38 insertions, 11 deletions
diff --git a/ChangeLog b/ChangeLog
index 44f1ebcb72..0646e39c04 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2009-04-06 Ulrich Drepper <drepper@redhat.com>
+
+ * resolv/resolv.h (RES_SNGLKUP): Define.
+ * 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.
+
2009-04-05 Ulrich Drepper <drepper@redhat.com>
* sysdeps/x86_64/strlen.S: Optimize by using SSE2 instructions.
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)