From ae06191038e8757bc9ba637c7c94f2e02817b43b Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Tue, 7 Apr 2009 02:00:27 +0000 Subject: * 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. --- resolv/res_init.c | 3 +++ resolv/res_send.c | 37 ++++++++++++++++++++++++++----------- resolv/resolv.h | 1 + 3 files changed, 30 insertions(+), 11 deletions(-) (limited to 'resolv') 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) -- cgit 1.4.1