From owner-freebsd-bugs@FreeBSD.ORG Tue Jun 21 14:20:10 2011 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 5667D1065672 for ; Tue, 21 Jun 2011 14:20:10 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 271478FC0C for ; Tue, 21 Jun 2011 14:20:10 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.4/8.14.4) with ESMTP id p5LEKACt052616 for ; Tue, 21 Jun 2011 14:20:10 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.4/8.14.4/Submit) id p5LEKATO052615; Tue, 21 Jun 2011 14:20:10 GMT (envelope-from gnats) Resent-Date: Tue, 21 Jun 2011 14:20:10 GMT Resent-Message-Id: <201106211420.p5LEKATO052615@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Mark Andrews Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 52DE11065675 for ; Tue, 21 Jun 2011 14:19:12 +0000 (UTC) (envelope-from marka@isc.org) Received: from mx.pao1.isc.org (mx.pao1.isc.org [IPv6:2001:4f8:0:2::2b]) by mx1.freebsd.org (Postfix) with ESMTP id 32C038FC16 for ; Tue, 21 Jun 2011 14:19:12 +0000 (UTC) Received: from bikeshed.isc.org (bikeshed.isc.org [IPv6:2001:4f8:3:d::19]) (using TLSv1 with cipher DHE-RSA-CAMELLIA256-SHA (256/256 bits)) (Client CN "bikeshed.isc.org", Issuer "ISC CA" (verified OK)) by mx.pao1.isc.org (Postfix) with ESMTPS id D569EC94D9 for ; Tue, 21 Jun 2011 14:19:01 +0000 (UTC) (envelope-from marka@isc.org) Received: from sex.dv.isc.org (sex.dv.isc.org [IPv6:2001:470:1f00:820:218:f3ff:feba:9a37]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by bikeshed.isc.org (Postfix) with ESMTPSA id 33EE1216C7B for ; Tue, 21 Jun 2011 14:19:01 +0000 (UTC) (envelope-from marka@isc.org) Received: from sex.dv.isc.org (localhost [127.0.0.1]) by sex.dv.isc.org (8.14.4/8.14.4) with ESMTP id p5LEGOmb081372 for ; Wed, 22 Jun 2011 00:16:24 +1000 (EST) (envelope-from marka@sex.dv.isc.org) Received: (from marka@localhost) by sex.dv.isc.org (8.14.4/8.14.4/Submit) id p5LEGNV1081371; Wed, 22 Jun 2011 00:16:23 +1000 (EST) (envelope-from marka) Message-Id: <201106211416.p5LEGNV1081371@sex.dv.isc.org> Date: Wed, 22 Jun 2011 00:16:23 +1000 (EST) From: Mark Andrews To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 Cc: Subject: bin/158125: whois takes too long to move to next address. [patch] X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Mark Andrews List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 21 Jun 2011 14:20:10 -0000 >Number: 158125 >Category: bin >Synopsis: whois takes too long to move to next address. [patch] >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Tue Jun 21 14:20:09 UTC 2011 >Closed-Date: >Last-Modified: >Originator: Mark Andrews >Release: FreeBSD 8.2-STABLE i386 >Organization: ISC >Environment: System: FreeBSD sex.dv.isc.org 8.2-STABLE FreeBSD 8.2-STABLE #10: Sat Feb 26 18:02:12 EST 2011 marka@sex.dv.isc.org:/usr/obj/usr/src/sys/DEBUG i386 >Description: whois has a simple connect loop which has doesn't fallback to alternate address on connect failures in a timely manner. >How-To-Repeat: block connections to whois.ripe.net over IPv6 then try to lookup information in ripe's whois database from a dual stack server. >Fix: Attempt to connect to alternate addresses if the connect doesn't succeed in 100ms. Take the first connection to succeed and close the others. Reduce the wait between connection attempts by 2 on each connection attempt. --- /usr/src/usr.bin/whois/whois.c 2010-01-21 21:16:21.000000000 +1100 +++ whois.c 2011-06-22 00:01:47.000000000 +1000 @@ -48,6 +48,7 @@ #include #include +#include #include #include #include @@ -59,6 +60,8 @@ #include #include #include +#include +#include #define ABUSEHOST "whois.abuse.net" #define NICHOST "whois.crsnic.net" @@ -282,21 +285,96 @@ FILE *sfi, *sfo; struct addrinfo *hostres, *res; char *buf, *host, *nhost, *p; - int i, s; + int i, j, n, s, count; size_t c, len; + struct pollfd *fds; + int timeout = 100; s = -1; hostres = gethostinfo(hostname, 1); - for (res = hostres; res; res = res->ai_next) { + for (res = hostres, count = 0; res; res = res->ai_next) + count++; + + fds = calloc(count, sizeof(*fds)); + if (fds == NULL) + err(EX_OSERR, "calloc()"); + + for (res = hostres, i = 0, count = 0; res; res = res->ai_next) { s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (s < 0) + if (s < 0) { + if (res->ai_next != NULL) + continue; + } else if ((flags = fcntl(s, F_GETFL)) == -1) { + close(s); + } else if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) { + close(s); + } else if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { + if (errno != EINPROGRESS) { + close(s); + } else { + fds[i].fd = s; + fds[i].events = POLLERR | POLLHUP | + POLLIN | POLLOUT; + count++; + i++; + } + } else + goto done; + + if (count == 0) continue; - if (connect(s, res->ai_addr, res->ai_addrlen) == 0) - break; - close(s); + + do { + if (res->ai_next == NULL) + timeout = -1; + n = poll(fds, i, timeout); + if (n == 0) { + timeout >> 1; + break; + } + if (n < 0 ) { + if (errno == EAGAIN || errno == EINTR) + continue; + s = -1; + goto done; + } + for (j = 0; j < i; j++) { + if (fds[j].fd == -1 || fds[j].events == 0 || + fds[j].revents == 0) + continue; + s = fds[j].fd; + if (fds[j].revents & POLLHUP) { + close(s); + fds[j].fd = -1; + fds[j].events = 0; + count--; + continue; + } + /* Connect succeeded. */ + goto done; + } + } while (timeout == -1 && count != 0); } + s = -1; + + done: + for (j = 0; j < i; j++) + if (fds[j].fd != s && fds[j].fd != -1) + close(fds[j].fd); + + if (s != -1) { + /* Restore default blocking behaviour. */ + if ((flags = fcntl(s, F_GETFL)) != -1) { + flags &= ~O_NONBLOCK; + if (fcntl(s, F_SETFL, flags) == -1) + err(EX_OSERR, "fcntl()"); + } else + err(EX_OSERR, "fcntl()"); + } + + free(fds); freeaddrinfo(hostres); - if (res == NULL) + if (s == -1) err(EX_OSERR, "connect()"); sfi = fdopen(s, "r"); >Release-Note: >Audit-Trail: >Unformatted: