diff options
-rw-r--r-- | net/base/host_resolver_proc.cc | 17 | ||||
-rw-r--r-- | net/socket/tcp_client_socket_libevent.cc | 72 |
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(); |