summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/base/host_resolver_proc.cc17
-rw-r--r--net/socket/tcp_client_socket_libevent.cc72
2 files changed, 49 insertions, 40 deletions
diff --git a/net/base/host_resolver_proc.cc b/net/base/host_resolver_proc.cc
index 6c9400d..8951646 100644
--- a/net/base/host_resolver_proc.cc
+++ b/net/base/host_resolver_proc.cc
@@ -157,23 +157,6 @@ int SystemHostResolverProc(const std::string& host, AddressList* addrlist) {
// address.
// See http://crbug.com/5234.
hints.ai_flags = 0;
-#elif defined(OS_MACOSX)
- // We don't need to use AI_ADDRCONFIG on Mac OS X. There are two evidences:
- //
- // 1. The getaddrinfo man page on Mac OS X documents only three flags:
- // AI_CANONNAME, AI_NUMERICHOST, and AI_PASSIVE, and shows an example that
- // sets hints.ai_flags to 0.
- // 2. The <netdb.h> header lists only those three flags in the comment after
- // the ai_flags field of struct addrinfo, and defines an AI_MASK macro as
- // the bitwise-OR of those three flags with the comment "valid flags for
- // addrinfo".
- //
- // But is it harmful to use AI_ADDRCONFIG? Unfortunately I can't find a
- // definitive answer by browsing the getaddrinfo source code in Darwin (in
- // the Libinfo project).
- //
- // See http://crbug.com/12711.
- hints.ai_flags = 0;
#else
hints.ai_flags = AI_ADDRCONFIG;
#endif
diff --git a/net/socket/tcp_client_socket_libevent.cc b/net/socket/tcp_client_socket_libevent.cc
index 8ad5ef3..165c4cd 100644
--- a/net/socket/tcp_client_socket_libevent.cc
+++ b/net/socket/tcp_client_socket_libevent.cc
@@ -78,6 +78,26 @@ int MapConnectError(int err) {
}
}
+// Given err, an errno from a connect() attempt, returns true if connect()
+// should be retried with another address.
+bool ShouldTryNextAddress(int err) {
+ switch (err) {
+ case EADDRNOTAVAIL:
+ case EAFNOSUPPORT:
+ case ECONNREFUSED:
+ case ECONNRESET:
+ case EACCES:
+ case EPERM:
+ case ENETUNREACH:
+ case EHOSTUNREACH:
+ case ENETDOWN:
+ case ETIMEDOUT:
+ return true;
+ default:
+ return false;
+ }
+}
+
} // namespace
//-----------------------------------------------------------------------------
@@ -105,30 +125,42 @@ int TCPClientSocketLibevent::Connect(CompletionCallback* callback) {
DCHECK(!waiting_connect_);
TRACE_EVENT_BEGIN("socket.connect", this, "");
- const addrinfo* ai = current_ai_;
- DCHECK(ai);
- int rv = CreateSocket(ai);
- if (rv != OK)
- return rv;
+ while (true) {
+ DCHECK(current_ai_);
- if (!HANDLE_EINTR(connect(socket_, ai->ai_addr,
- static_cast<int>(ai->ai_addrlen)))) {
- TRACE_EVENT_END("socket.connect", this, "");
- // Connected without waiting!
- return OK;
- }
+ int rv = CreateSocket(current_ai_);
+ if (rv != OK)
+ return rv;
- // Synchronous operation not supported
- DCHECK(callback);
+ if (!HANDLE_EINTR(connect(socket_, current_ai_->ai_addr,
+ static_cast<int>(current_ai_->ai_addrlen)))) {
+ TRACE_EVENT_END("socket.connect", this, "");
+ // Connected without waiting!
+ return OK;
+ }
+
+ int error_code = errno;
+ if (error_code == EINPROGRESS)
+ break;
- if (errno != EINPROGRESS) {
- DLOG(INFO) << "connect failed: " << errno;
close(socket_);
socket_ = kInvalidSocket;
- return MapConnectError(errno);
+
+ if (current_ai_->ai_next && ShouldTryNextAddress(error_code)) {
+ // connect() can fail synchronously for an address even on a
+ // non-blocking socket. As an example, this can happen when there is
+ // no route to the host. Retry using the next address in the list.
+ current_ai_ = current_ai_->ai_next;
+ } else {
+ DLOG(INFO) << "connect failed: " << error_code;
+ return MapConnectError(error_code);
+ }
}
+ // Synchronous operation not supported
+ DCHECK(callback);
+
// Initialize write_socket_watcher_ and link it to our MessagePump.
// POLLOUT is set if the connection is established.
// POLLIN is set if the connection fails.
@@ -324,13 +356,7 @@ void TCPClientSocketLibevent::DidCompleteConnect() {
if (error_code == EINPROGRESS || error_code == EALREADY) {
NOTREACHED(); // This indicates a bug in libevent or our code.
result = ERR_IO_PENDING;
- } else if (current_ai_->ai_next && (
- error_code == EADDRNOTAVAIL ||
- error_code == EAFNOSUPPORT ||
- error_code == ECONNREFUSED ||
- error_code == ENETUNREACH ||
- error_code == EHOSTUNREACH ||
- error_code == ETIMEDOUT)) {
+ } else if (current_ai_->ai_next && ShouldTryNextAddress(error_code)) {
// This address failed, try next one in list.
const addrinfo* next = current_ai_->ai_next;
Disconnect();