svn commit: r283083 - stable/10/usr.bin/whois
Xin LI
delphij at FreeBSD.org
Mon May 18 21:27:47 UTC 2015
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 <marka isc org> (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 <sys/types.h>
#include <sys/socket.h>
+#include <sys/poll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
@@ -55,6 +56,8 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
#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");
More information about the svn-src-all
mailing list