From owner-svn-src-all@FreeBSD.ORG Mon May 18 21:27:47 2015 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id AC1A4BC6; Mon, 18 May 2015 21:27:47 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 8DDCC17B4; Mon, 18 May 2015 21:27:47 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t4ILRlNc047743; Mon, 18 May 2015 21:27:47 GMT (envelope-from delphij@FreeBSD.org) Received: (from delphij@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t4ILRlmI047742; Mon, 18 May 2015 21:27:47 GMT (envelope-from delphij@FreeBSD.org) Message-Id: <201505182127.t4ILRlmI047742@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: delphij set sender to delphij@FreeBSD.org using -f From: Xin LI Date: Mon, 18 May 2015 21:27:47 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r283083 - stable/10/usr.bin/whois X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 18 May 2015 21:27:47 -0000 Author: delphij Date: Mon May 18 21:27:46 2015 New Revision: 283083 URL: https://svnweb.freebsd.org/changeset/base/283083 Log: MFC r281959,282885 (fanf, partial),282888 (fanf): Try alternate addresses more agressively. PR: 158125 Submitted by: Mark Andrews (with changes from me) whois: code cleanup Use pedantically correct types. whois: do not clobber command-line flags when tweaking O_NONBLOCK This can make whois fail to follow referrals when it should. The bug was introduced in r281959. Modified: stable/10/usr.bin/whois/whois.c Directory Properties: stable/10/ (props changed) Modified: stable/10/usr.bin/whois/whois.c ============================================================================== --- stable/10/usr.bin/whois/whois.c Mon May 18 21:18:44 2015 (r283082) +++ stable/10/usr.bin/whois/whois.c Mon May 18 21:27:46 2015 (r283083) @@ -1,4 +1,4 @@ -/* +/*- * Copyright (c) 1980, 1993 * The Regents of the University of California. All rights reserved. * @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -55,6 +56,8 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include #define ABUSEHOST "whois.abuse.net" #define NICHOST "whois.crsnic.net" @@ -280,21 +283,137 @@ whois(const char *query, const char *hos FILE *sfi, *sfo; struct addrinfo *hostres, *res; char *buf, *host, *nhost, *p; - int i, s; - size_t c, len; + int s = -1, f; + nfds_t i, j; + size_t c, len, count; + struct pollfd *fds; + int timeout = 180; - s = -1; hostres = gethostinfo(hostname, 1); - for (res = hostres; res; res = res->ai_next) { - s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + for (res = hostres, count = 0; res; res = res->ai_next) + count++; + + fds = calloc(count, sizeof(*fds)); + if (fds == NULL) + err(EX_OSERR, "calloc()"); + + /* + * Traverse the result list elements and make non-block + * connection attempts. + */ + count = i = 0; + for (res = hostres; res != NULL; res = res->ai_next) { + s = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK, + res->ai_protocol); if (s < 0) continue; - if (connect(s, res->ai_addr, res->ai_addrlen) == 0) - break; - close(s); + if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { + if (errno == EINPROGRESS) { + /* Add the socket to poll list */ + fds[i].fd = s; + fds[i].events = POLLERR | POLLHUP | + POLLIN | POLLOUT; + count++; + i++; + } else { + close(s); + s = -1; + + /* + * Poll only if we have something to poll, + * otherwise just go ahead and try next + * address + */ + if (count == 0) + continue; + } + } else + goto done; + + /* + * If we are at the last address, poll until a connection is + * established or we failed all connection attempts. + */ + if (res->ai_next == NULL) + timeout = INFTIM; + + /* + * Poll the watched descriptors for successful connections: + * if we still have more untried resolved addresses, poll only + * once; otherwise, poll until all descriptors have errors, + * which will be considered as ETIMEDOUT later. + */ + do { + int n; + + n = poll(fds, i, timeout); + if (n == 0) { + /* + * No event reported in time. Try with a + * smaller timeout (but cap at 2-3ms) + * after a new host have been added. + */ + if (timeout >= 3) + timeout <<= 1; + + break; + } else if (n < 0) { + /* + * errno here can only be EINTR which we would want + * to clean up and bail out. + */ + s = -1; + goto done; + } + + /* + * Check for the event(s) we have seen. + */ + for (j = 0; j < i; j++) { + if (fds[j].fd == -1 || fds[j].events == 0 || + fds[j].revents == 0) + continue; + if (fds[j].revents & ~(POLLIN | POLLOUT)) { + close(s); + fds[j].fd = -1; + fds[j].events = 0; + count--; + continue; + } else if (fds[j].revents & (POLLIN | POLLOUT)) { + /* Connect succeeded. */ + s = fds[j].fd; + + goto done; + } + + } + } while (timeout == INFTIM && count != 0); } + + /* All attempts were failed */ + s = -1; + if (count == 0) + errno = ETIMEDOUT; + +done: + /* Close all watched fds except the succeeded one */ + 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 behavior. */ + if ((f = fcntl(s, F_GETFL)) != -1) { + f &= ~O_NONBLOCK; + if (fcntl(s, F_SETFL, f) == -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");