diff options
author | sanjeevr@chromium.org <sanjeevr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-15 22:34:37 +0000 |
---|---|---|
committer | sanjeevr@chromium.org <sanjeevr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-15 22:34:37 +0000 |
commit | 2e7f6e8287bb2e139da7bba876138e2d0f275714 (patch) | |
tree | ae15c658c20275eeb3b278d226662af46064f8e5 /jingle | |
parent | ae4b68e2c7344f560f12b7e34946188b691a4695 (diff) | |
download | chromium_src-2e7f6e8287bb2e139da7bba876138e2d0f275714.zip chromium_src-2e7f6e8287bb2e139da7bba876138e2d0f275714.tar.gz chromium_src-2e7f6e8287bb2e139da7bba876138e2d0f275714.tar.bz2 |
Changed the jingle network code in ChromeAsyncSocket to use the client socket pool. This also allows the connection to be able to tunnel through proxies.
BUG=77430
TEST=Unit-tests, sync unit-tests, test Cloud Print and Sync behind procy servers.
Review URL: http://codereview.chromium.org/6833031
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@81820 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'jingle')
21 files changed, 799 insertions, 163 deletions
diff --git a/jingle/jingle.gyp b/jingle/jingle.gyp index fece532..aa5a720 100644 --- a/jingle/jingle.gyp +++ b/jingle/jingle.gyp @@ -50,6 +50,9 @@ 'notifier/base/notifier_options.h', 'notifier/base/notifier_options_util.cc', 'notifier/base/notifier_options_util.h', + 'notifier/base/proxy_resolving_client_socket.cc', + 'notifier/base/proxy_resolving_client_socket.h', + 'notifier/base/resolving_client_socket_factory.h', 'notifier/base/server_information.cc', 'notifier/base/server_information.h', 'notifier/base/task_pump.cc', @@ -149,6 +152,7 @@ 'glue/thread_wrapper_unittest.cc', 'notifier/base/chrome_async_socket_unittest.cc', 'notifier/base/fake_ssl_client_socket_unittest.cc', + 'notifier/base/proxy_resolving_client_socket_unittest.cc', 'notifier/base/xmpp_connection_unittest.cc', 'notifier/base/weak_xmpp_client_unittest.cc', 'notifier/communicator/xmpp_connection_generator_unittest.cc', diff --git a/jingle/notifier/base/chrome_async_socket.cc b/jingle/notifier/base/chrome_async_socket.cc index 61adadd..c6d729f 100644 --- a/jingle/notifier/base/chrome_async_socket.cc +++ b/jingle/notifier/base/chrome_async_socket.cc @@ -1,15 +1,9 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "jingle/notifier/base/chrome_async_socket.h" -#if defined(OS_WIN) -#include <winsock2.h> -#elif defined(OS_POSIX) -#include <arpa/inet.h> -#endif - #include <algorithm> #include <cstring> #include <cstdlib> @@ -18,6 +12,7 @@ #include "base/compiler_specific.h" #include "base/logging.h" #include "base/message_loop.h" +#include "jingle/notifier/base/resolving_client_socket_factory.h" #include "net/base/address_list.h" #include "net/base/host_port_pair.h" #include "net/base/io_buffer.h" @@ -25,6 +20,7 @@ #include "net/base/ssl_config_service.h" #include "net/base/sys_addrinfo.h" #include "net/socket/client_socket_factory.h" +#include "net/socket/client_socket_handle.h" #include "net/socket/ssl_client_socket.h" #include "net/socket/tcp_client_socket.h" #include "talk/base/socketaddress.h" @@ -32,9 +28,7 @@ namespace notifier { ChromeAsyncSocket::ChromeAsyncSocket( - net::ClientSocketFactory* client_socket_factory, - const net::SSLConfig& ssl_config, - net::CertVerifier* cert_verifier, + ResolvingClientSocketFactory* client_socket_factory, size_t read_buf_size, size_t write_buf_size, net::NetLog* net_log) @@ -47,8 +41,6 @@ ChromeAsyncSocket::ChromeAsyncSocket( ssl_connect_callback_(ALLOW_THIS_IN_INITIALIZER_LIST(this), &ChromeAsyncSocket::ProcessSSLConnectDone), client_socket_factory_(client_socket_factory), - ssl_config_(ssl_config), - cert_verifier_(cert_verifier), bound_net_log_( net::BoundNetLog::Make(net_log, net::NetLog::SOURCE_SOCKET)), state_(STATE_CLOSED), @@ -103,26 +95,6 @@ void ChromeAsyncSocket::DoNetErrorFromStatus(int status) { DoNetError(static_cast<net::Error>(status)); } -namespace { - -// Takes a 32-bit integer in host byte order and converts it to a -// net::IPAddressNumber. -net::IPAddressNumber Uint32ToIPAddressNumber(uint32 ip) { - uint32 ip_nbo = htonl(ip); - const unsigned char* const ip_start = - reinterpret_cast<const unsigned char*>(&ip_nbo); - return net::IPAddressNumber(ip_start, ip_start + (sizeof ip_nbo)); -} - -net::AddressList SocketAddressToAddressList( - const talk_base::SocketAddress& address) { - DCHECK_NE(address.ip(), 0U); - return net::AddressList(Uint32ToIPAddressNumber(address.ip()), - address.port(), false); -} - -} // namespace - // STATE_CLOSED -> STATE_CONNECTING bool ChromeAsyncSocket::Connect(const talk_base::SocketAddress& address) { @@ -131,7 +103,8 @@ bool ChromeAsyncSocket::Connect(const talk_base::SocketAddress& address) { DoNonNetError(ERROR_WRONGSTATE); return false; } - if (address.ip() == 0) { + // We can't work with an empty hostname and IP address. + if (address.hostname().empty() && (address.ip() == 0)) { DoNonNetError(ERROR_DNS); return false; } @@ -145,10 +118,11 @@ bool ChromeAsyncSocket::Connect(const talk_base::SocketAddress& address) { DCHECK(scoped_runnable_method_factory_.empty()); scoped_runnable_method_factory_.RevokeAll(); - net::AddressList address_list = SocketAddressToAddressList(address); + net::HostPortPair dest_host_port_pair(address.IPAsString(), address.port()); + transport_socket_.reset( client_socket_factory_->CreateTransportClientSocket( - address_list, bound_net_log_.net_log(), net::NetLog::Source())); + dest_host_port_pair, bound_net_log_.net_log())); int status = transport_socket_->Connect(&connect_callback_); if (status != net::ERR_IO_PENDING) { // We defer execution of ProcessConnectDone instead of calling it @@ -436,11 +410,11 @@ bool ChromeAsyncSocket::StartTls(const std::string& domain_name) { scoped_runnable_method_factory_.RevokeAll(); DCHECK(transport_socket_.get()); + net::ClientSocketHandle* socket_handle = new net::ClientSocketHandle(); + socket_handle->set_socket(transport_socket_.release()); transport_socket_.reset( client_socket_factory_->CreateSSLClientSocket( - transport_socket_.release(), net::HostPortPair(domain_name, 443), - ssl_config_, NULL /* ssl_host_info */, - cert_verifier_)); + socket_handle, net::HostPortPair(domain_name, 443))); int status = transport_socket_->Connect(&ssl_connect_callback_); if (status != net::ERR_IO_PENDING) { MessageLoop* message_loop = MessageLoop::current(); diff --git a/jingle/notifier/base/chrome_async_socket.h b/jingle/notifier/base/chrome_async_socket.h index f431dbd..add9f72 100644 --- a/jingle/notifier/base/chrome_async_socket.h +++ b/jingle/notifier/base/chrome_async_socket.h @@ -21,25 +21,22 @@ #include "net/base/completion_callback.h" #include "net/base/net_errors.h" #include "net/base/net_log.h" -#include "net/base/ssl_config_service.h" #include "talk/xmpp/asyncsocket.h" namespace net { -class CertVerifier; class ClientSocket; -class ClientSocketFactory; class IOBufferWithSize; } // namespace net namespace notifier { +class ResolvingClientSocketFactory; + class ChromeAsyncSocket : public buzz::AsyncSocket { public: - // Takes ownership of |client_socket_factory| but not |cert_verifier| nor - // |net_log|. |cert_verifier| may not be NULL. |net_log| may be NULL. - ChromeAsyncSocket(net::ClientSocketFactory* client_socket_factory, - const net::SSLConfig& ssl_config, - net::CertVerifier* cert_verifier, + // Takes ownership of |client_socket_factory| but not |net_log|. + // |net_log| may be NULL. + ChromeAsyncSocket(ResolvingClientSocketFactory* client_socket_factory, size_t read_buf_size, size_t write_buf_size, net::NetLog* net_log); @@ -187,9 +184,7 @@ class ChromeAsyncSocket : public buzz::AsyncSocket { net::CompletionCallbackImpl<ChromeAsyncSocket> write_callback_; net::CompletionCallbackImpl<ChromeAsyncSocket> ssl_connect_callback_; - scoped_ptr<net::ClientSocketFactory> client_socket_factory_; - const net::SSLConfig ssl_config_; - net::CertVerifier* const cert_verifier_; + scoped_ptr<ResolvingClientSocketFactory> client_socket_factory_; net::BoundNetLog bound_net_log_; // buzz::AsyncSocket state. diff --git a/jingle/notifier/base/chrome_async_socket_unittest.cc b/jingle/notifier/base/chrome_async_socket_unittest.cc index 2cc1664..9186d1c 100644 --- a/jingle/notifier/base/chrome_async_socket_unittest.cc +++ b/jingle/notifier/base/chrome_async_socket_unittest.cc @@ -4,6 +4,12 @@ #include "jingle/notifier/base/chrome_async_socket.h" +#if defined(OS_WIN) +#include <winsock2.h> +#elif defined(OS_POSIX) +#include <arpa/inet.h> +#endif + #include <deque> #include <string> @@ -11,11 +17,14 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop.h" +#include "jingle/notifier/base/resolving_client_socket_factory.h" #include "net/base/capturing_net_log.h" #include "net/base/cert_verifier.h" #include "net/base/net_errors.h" +#include "net/base/net_log.h" #include "net/base/ssl_config_service.h" #include "net/socket/socket_test_util.h" +#include "net/url_request/url_request_context_getter.h" #include "talk/base/sigslot.h" #include "talk/base/socketaddress.h" #include "testing/gtest/include/gtest/gtest.h" @@ -95,6 +104,53 @@ class AsyncSocketDataProvider : public net::SocketDataProvider { DISALLOW_COPY_AND_ASSIGN(AsyncSocketDataProvider); }; +// Takes a 32-bit integer in host byte order and converts it to a +// net::IPAddressNumber. +net::IPAddressNumber Uint32ToIPAddressNumber(uint32 ip) { + uint32 ip_nbo = htonl(ip); + const unsigned char* const ip_start = + reinterpret_cast<const unsigned char*>(&ip_nbo); + return net::IPAddressNumber(ip_start, ip_start + (sizeof ip_nbo)); +} + +net::AddressList SocketAddressToAddressList( + const talk_base::SocketAddress& address) { + DCHECK_NE(address.ip(), 0U); + return net::AddressList(Uint32ToIPAddressNumber(address.ip()), + address.port(), false); +} + +class MockXmppClientSocketFactory : public ResolvingClientSocketFactory { + public: + MockXmppClientSocketFactory( + net::ClientSocketFactory* mock_client_socket_factory, + const net::AddressList& address_list) + : mock_client_socket_factory_(mock_client_socket_factory), + address_list_(address_list) { + } + + // ResolvingClientSocketFactory implementation. + virtual net::ClientSocket* CreateTransportClientSocket( + const net::HostPortPair& host_and_port, net::NetLog* net_log) { + return mock_client_socket_factory_->CreateTransportClientSocket( + address_list_, net_log, net::NetLog::Source()); + } + + virtual net::SSLClientSocket* CreateSSLClientSocket( + net::ClientSocketHandle* transport_socket, + const net::HostPortPair& host_and_port) { + return mock_client_socket_factory_->CreateSSLClientSocket( + transport_socket, host_and_port, ssl_config_, NULL, &cert_verifier_, + NULL); + } + + private: + scoped_ptr<net::ClientSocketFactory> mock_client_socket_factory_; + net::AddressList address_list_; + net::SSLConfig ssl_config_; + net::CertVerifier cert_verifier_; +}; + class ChromeAsyncSocketTest : public testing::Test, public sigslot::has_slots<> { @@ -114,9 +170,13 @@ class ChromeAsyncSocketTest mock_client_socket_factory->AddSSLSocketDataProvider( &ssl_socket_data_provider_); + scoped_ptr<MockXmppClientSocketFactory> mock_xmpp_client_socket_factory( + new MockXmppClientSocketFactory( + mock_client_socket_factory.release(), + SocketAddressToAddressList(addr_))); chrome_async_socket_.reset( - new ChromeAsyncSocket(mock_client_socket_factory.release(), - ssl_config_, &cert_verifier_, 14, 20, + new ChromeAsyncSocket(mock_xmpp_client_socket_factory.release(), + 14, 20, &capturing_net_log_)), chrome_async_socket_->SignalConnected.connect( @@ -372,8 +432,6 @@ class ChromeAsyncSocketTest net::SSLSocketDataProvider ssl_socket_data_provider_; net::CapturingNetLog capturing_net_log_; - net::SSLConfig ssl_config_; - net::CertVerifier cert_verifier_; scoped_ptr<ChromeAsyncSocket> chrome_async_socket_; std::deque<SignalSocketState> signal_socket_states_; const talk_base::SocketAddress addr_; diff --git a/jingle/notifier/base/proxy_resolving_client_socket.cc b/jingle/notifier/base/proxy_resolving_client_socket.cc new file mode 100644 index 0000000..82c300e --- /dev/null +++ b/jingle/notifier/base/proxy_resolving_client_socket.cc @@ -0,0 +1,337 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "jingle/notifier/base/proxy_resolving_client_socket.h" + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "googleurl/src/gurl.h" +#include "net/base/io_buffer.h" +#include "net/base/net_errors.h" +#include "net/http/http_network_session.h" +#include "net/socket/client_socket_handle.h" +#include "net/socket/client_socket_pool_manager.h" +#include "net/url_request/url_request_context.h" +#include "net/url_request/url_request_context_getter.h" + +namespace notifier { + +ProxyResolvingClientSocket::ProxyResolvingClientSocket( + const scoped_refptr<net::URLRequestContextGetter>& request_context_getter, + const net::SSLConfig& ssl_config, + const net::HostPortPair& dest_host_port_pair, + net::NetLog* net_log) + : proxy_resolve_callback_(ALLOW_THIS_IN_INITIALIZER_LIST(this), + &ProxyResolvingClientSocket::ProcessProxyResolveDone), + connect_callback_(ALLOW_THIS_IN_INITIALIZER_LIST(this), + &ProxyResolvingClientSocket::ProcessConnectDone), + ssl_config_(ssl_config), + pac_request_(NULL), + dest_host_port_pair_(dest_host_port_pair), + tried_direct_connect_fallback_(false), + bound_net_log_( + net::BoundNetLog::Make(net_log, net::NetLog::SOURCE_SOCKET)), + scoped_runnable_method_factory_( + ALLOW_THIS_IN_INITIALIZER_LIST(this)), + user_connect_callback_(NULL) { + DCHECK(request_context_getter); + net::URLRequestContext* request_context = + request_context_getter->GetURLRequestContext(); + DCHECK(request_context); + net::HttpNetworkSession::Params session_params; + session_params.host_resolver = request_context->host_resolver(); + session_params.cert_verifier = request_context->cert_verifier(); + session_params.dnsrr_resolver = request_context->dnsrr_resolver(); + session_params.proxy_service = request_context->proxy_service(); + session_params.ssl_config_service = request_context->ssl_config_service(); + session_params.http_auth_handler_factory = + request_context->http_auth_handler_factory(); + network_session_ = new net::HttpNetworkSession(session_params); +} + +ProxyResolvingClientSocket::~ProxyResolvingClientSocket() { + Disconnect(); +} + +int ProxyResolvingClientSocket::Read(net::IOBuffer* buf, int buf_len, + net::CompletionCallback* callback) { + if (transport_.get() && transport_->socket()) + return transport_->socket()->Read(buf, buf_len, callback); + NOTREACHED(); + return net::ERR_SOCKET_NOT_CONNECTED; +} + +int ProxyResolvingClientSocket::Write(net::IOBuffer* buf, int buf_len, + net::CompletionCallback* callback) { + if (transport_.get() && transport_->socket()) + return transport_->socket()->Write(buf, buf_len, callback); + NOTREACHED(); + return net::ERR_SOCKET_NOT_CONNECTED; +} + +bool ProxyResolvingClientSocket::SetReceiveBufferSize(int32 size) { + if (transport_.get() && transport_->socket()) + return transport_->socket()->SetReceiveBufferSize(size); + NOTREACHED(); + return false; +} + +bool ProxyResolvingClientSocket::SetSendBufferSize(int32 size) { + if (transport_.get() && transport_->socket()) + return transport_->socket()->SetSendBufferSize(size); + NOTREACHED(); + return false; +} + +int ProxyResolvingClientSocket::Connect(net::CompletionCallback* callback) { + DCHECK(!user_connect_callback_); + + tried_direct_connect_fallback_ = false; + + // First we try and resolve the proxy. + GURL url("http://" + dest_host_port_pair_.ToString()); + int status = network_session_->proxy_service()->ResolveProxy( + url, + &proxy_info_, + &proxy_resolve_callback_, + &pac_request_, + bound_net_log_); + if (status != net::ERR_IO_PENDING) { + // We defer execution of ProcessProxyResolveDone instead of calling it + // directly here for simplicity. From the caller's point of view, + // the connect always happens asynchronously. + MessageLoop* message_loop = MessageLoop::current(); + CHECK(message_loop); + message_loop->PostTask( + FROM_HERE, + scoped_runnable_method_factory_.NewRunnableMethod( + &ProxyResolvingClientSocket::ProcessProxyResolveDone, status)); + } + user_connect_callback_ = callback; + return net::ERR_IO_PENDING; +} + +void ProxyResolvingClientSocket::RunUserConnectCallback(int status) { + DCHECK_LE(status, net::OK); + net::CompletionCallback* user_connect_callback = user_connect_callback_; + user_connect_callback_ = NULL; + user_connect_callback->Run(status); +} + +// Always runs asynchronously. +void ProxyResolvingClientSocket::ProcessProxyResolveDone(int status) { + pac_request_ = NULL; + + DCHECK_NE(status, net::ERR_IO_PENDING); + if (status == net::OK) { + // Remove unsupported proxies from the list. + proxy_info_.RemoveProxiesWithoutScheme( + net::ProxyServer::SCHEME_DIRECT | + net::ProxyServer::SCHEME_HTTP | net::ProxyServer::SCHEME_HTTPS | + net::ProxyServer::SCHEME_SOCKS4 | net::ProxyServer::SCHEME_SOCKS5); + + if (proxy_info_.is_empty()) { + // No proxies/direct to choose from. This happens when we don't support + // any of the proxies in the returned list. + status = net::ERR_NO_SUPPORTED_PROXIES; + } + } + + // Since we are faking the URL, it is possible that no proxies match our URL. + // Try falling back to a direct connection if we have not tried that before. + if (status != net::OK) { + if (!tried_direct_connect_fallback_) { + tried_direct_connect_fallback_ = true; + proxy_info_.UseDirect(); + } else { + CloseTransportSocket(); + RunUserConnectCallback(status); + return; + } + } + + transport_.reset(new net::ClientSocketHandle); + // Now that we have resolved the proxy, we need to connect. + status = net::ClientSocketPoolManager::InitSocketHandleForRawConnect( + dest_host_port_pair_, + network_session_.get(), + proxy_info_, + ssl_config_, + ssl_config_, + bound_net_log_, + transport_.get(), + &connect_callback_); + if (status != net::ERR_IO_PENDING) { + // Since this method is always called asynchronously. it is OK to call + // ProcessConnectDone synchronously. + ProcessConnectDone(status); + } +} + +void ProxyResolvingClientSocket::ProcessConnectDone(int status) { + if (status != net::OK) { + // If the connection fails, try another proxy. + status = ReconsiderProxyAfterError(status); + // ReconsiderProxyAfterError either returns an error (in which case it is + // not reconsidering a proxy) or returns ERR_IO_PENDING if it is considering + // another proxy. + DCHECK_NE(status, net::OK); + if (status == net::ERR_IO_PENDING) + // Proxy reconsideration pending. Return. + return; + CloseTransportSocket(); + } + RunUserConnectCallback(status); +} + +// TODO(sanjeevr): This has largely been copied from +// HttpStreamFactoryImpl::Job::ReconsiderProxyAfterError. This should be +// refactored into some common place. +// This method reconsiders the proxy on certain errors. If it does reconsider +// a proxy it always returns ERR_IO_PENDING and posts a call to +// ProcessProxyResolveDone with the result of the reconsideration. +int ProxyResolvingClientSocket::ReconsiderProxyAfterError(int error) { + DCHECK(!pac_request_); + DCHECK_NE(error, net::OK); + DCHECK_NE(error, net::ERR_IO_PENDING); + // A failure to resolve the hostname or any error related to establishing a + // TCP connection could be grounds for trying a new proxy configuration. + // + // Why do this when a hostname cannot be resolved? Some URLs only make sense + // to proxy servers. The hostname in those URLs might fail to resolve if we + // are still using a non-proxy config. We need to check if a proxy config + // now exists that corresponds to a proxy server that could load the URL. + // + switch (error) { + case net::ERR_PROXY_CONNECTION_FAILED: + case net::ERR_NAME_NOT_RESOLVED: + case net::ERR_INTERNET_DISCONNECTED: + case net::ERR_ADDRESS_UNREACHABLE: + case net::ERR_CONNECTION_CLOSED: + case net::ERR_CONNECTION_RESET: + case net::ERR_CONNECTION_REFUSED: + case net::ERR_CONNECTION_ABORTED: + case net::ERR_TIMED_OUT: + case net::ERR_TUNNEL_CONNECTION_FAILED: + case net::ERR_SOCKS_CONNECTION_FAILED: + break; + case net::ERR_SOCKS_CONNECTION_HOST_UNREACHABLE: + // Remap the SOCKS-specific "host unreachable" error to a more + // generic error code (this way consumers like the link doctor + // know to substitute their error page). + // + // Note that if the host resolving was done by the SOCSK5 proxy, we can't + // differentiate between a proxy-side "host not found" versus a proxy-side + // "address unreachable" error, and will report both of these failures as + // ERR_ADDRESS_UNREACHABLE. + return net::ERR_ADDRESS_UNREACHABLE; + default: + return error; + } + + if (proxy_info_.is_https() && ssl_config_.send_client_cert) { + network_session_->ssl_client_auth_cache()->Remove( + proxy_info_.proxy_server().host_port_pair().ToString()); + } + + GURL url("http://" + dest_host_port_pair_.ToString()); + int rv = network_session_->proxy_service()->ReconsiderProxyAfterError( + url, &proxy_info_, &proxy_resolve_callback_, &pac_request_, + bound_net_log_); + if (rv == net::OK || rv == net::ERR_IO_PENDING) { + CloseTransportSocket(); + } else { + // If ReconsiderProxyAfterError() failed synchronously, it means + // there was nothing left to fall-back to, so fail the transaction + // with the last connection error we got. + rv = error; + } + + // We either have new proxy info or there was an error in falling back. + // In both cases we want to post ProcessProxyResolveDone (in the error case + // we might still want to fall back a direct connection). + if (rv != net::ERR_IO_PENDING) { + MessageLoop* message_loop = MessageLoop::current(); + CHECK(message_loop); + message_loop->PostTask( + FROM_HERE, + scoped_runnable_method_factory_.NewRunnableMethod( + &ProxyResolvingClientSocket::ProcessProxyResolveDone, rv)); + // Since we potentially have another try to go (trying the direct connect) + // set the return code code to ERR_IO_PENDING. + rv = net::ERR_IO_PENDING; + } + return rv; +} + +void ProxyResolvingClientSocket::Disconnect() { + CloseTransportSocket(); + if (pac_request_) + network_session_->proxy_service()->CancelPacRequest(pac_request_); + user_connect_callback_ = NULL; +} + +bool ProxyResolvingClientSocket::IsConnected() const { + if (!transport_.get() || !transport_->socket()) + return false; + return transport_->socket()->IsConnected(); +} + +bool ProxyResolvingClientSocket::IsConnectedAndIdle() const { + if (!transport_.get() || !transport_->socket()) + return false; + return transport_->socket()->IsConnectedAndIdle(); +} + +int ProxyResolvingClientSocket::GetPeerAddress( + net::AddressList* address) const { + if (transport_.get() && transport_->socket()) + return transport_->socket()->GetPeerAddress(address); + NOTREACHED(); + return net::ERR_SOCKET_NOT_CONNECTED; +} + +const net::BoundNetLog& ProxyResolvingClientSocket::NetLog() const { + if (transport_.get() && transport_->socket()) + return transport_->socket()->NetLog(); + NOTREACHED(); + return bound_net_log_; +} + +void ProxyResolvingClientSocket::SetSubresourceSpeculation() { + if (transport_.get() && transport_->socket()) + transport_->socket()->SetSubresourceSpeculation(); + else + NOTREACHED(); +} + +void ProxyResolvingClientSocket::SetOmniboxSpeculation() { + if (transport_.get() && transport_->socket()) + transport_->socket()->SetOmniboxSpeculation(); + else + NOTREACHED(); +} + +bool ProxyResolvingClientSocket::WasEverUsed() const { + if (transport_.get() && transport_->socket()) + return transport_->socket()->WasEverUsed(); + NOTREACHED(); + return false; +} + +bool ProxyResolvingClientSocket::UsingTCPFastOpen() const { + if (transport_.get() && transport_->socket()) + return transport_->socket()->UsingTCPFastOpen(); + NOTREACHED(); + return false; +} + +void ProxyResolvingClientSocket::CloseTransportSocket() { + if (transport_.get() && transport_->socket()) + transport_->socket()->Disconnect(); + transport_.reset(); +} + +} // namespace notifier diff --git a/jingle/notifier/base/proxy_resolving_client_socket.h b/jingle/notifier/base/proxy_resolving_client_socket.h new file mode 100644 index 0000000..3622923 --- /dev/null +++ b/jingle/notifier/base/proxy_resolving_client_socket.h @@ -0,0 +1,94 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// This ClientSocket implementation wraps a ClientSocketHandle that is created +// from the client socket pool after resolving proxies. + +#ifndef JINGLE_NOTIFIER_BASE_PROXY_RESOLVING_CLIENT_SOCKET_H_ +#define JINGLE_NOTIFIER_BASE_PROXY_RESOLVING_CLIENT_SOCKET_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/memory/ref_counted.h" +#include "net/base/completion_callback.h" +#include "net/base/host_port_pair.h" +#include "net/base/net_errors.h" +#include "net/base/net_log.h" +#include "net/base/ssl_config_service.h" +#include "net/proxy/proxy_info.h" +#include "net/proxy/proxy_service.h" +#include "net/socket/client_socket.h" + +namespace net { +class ClientSocketHandle; +class HttpNetworkSession; +class URLRequestContextGetter; +} // namespace net + +// TODO(sanjeevr): Move this to net/ +namespace notifier { + +class ProxyResolvingClientSocket : public net::ClientSocket { + public: + ProxyResolvingClientSocket( + const scoped_refptr<net::URLRequestContextGetter>& + request_context_getter, + const net::SSLConfig& ssl_config, + const net::HostPortPair& dest_host_port_pair, + net::NetLog* net_log); + virtual ~ProxyResolvingClientSocket(); + + // net::ClientSocket implementation. + virtual int Read(net::IOBuffer* buf, int buf_len, + net::CompletionCallback* callback) OVERRIDE; + virtual int Write(net::IOBuffer* buf, int buf_len, + net::CompletionCallback* callback) OVERRIDE; + virtual bool SetReceiveBufferSize(int32 size) OVERRIDE; + virtual bool SetSendBufferSize(int32 size) OVERRIDE; + virtual int Connect(net::CompletionCallback* callback) OVERRIDE; + virtual void Disconnect() OVERRIDE; + virtual bool IsConnected() const OVERRIDE; + virtual bool IsConnectedAndIdle() const OVERRIDE; + virtual int GetPeerAddress(net::AddressList* address) const OVERRIDE; + virtual const net::BoundNetLog& NetLog() const OVERRIDE; + virtual void SetSubresourceSpeculation() OVERRIDE; + virtual void SetOmniboxSpeculation() OVERRIDE; + virtual bool WasEverUsed() const OVERRIDE; + virtual bool UsingTCPFastOpen() const OVERRIDE; + + private: + // Proxy resolution and connection functions. + void ProcessProxyResolveDone(int status); + void ProcessConnectDone(int status); + + void CloseTransportSocket(); + void RunUserConnectCallback(int status); + int ReconsiderProxyAfterError(int error); + + // Callbacks passed to net APIs. + net::CompletionCallbackImpl<ProxyResolvingClientSocket> + proxy_resolve_callback_; + net::CompletionCallbackImpl<ProxyResolvingClientSocket> connect_callback_; + + scoped_refptr<net::HttpNetworkSession> network_session_; + + // The transport socket. + scoped_ptr<net::ClientSocketHandle> transport_; + + const net::SSLConfig ssl_config_; + net::ProxyService::PacRequest* pac_request_; + net::ProxyInfo proxy_info_; + net::HostPortPair dest_host_port_pair_; + bool tried_direct_connect_fallback_; + net::BoundNetLog bound_net_log_; + ScopedRunnableMethodFactory<ProxyResolvingClientSocket> + scoped_runnable_method_factory_; + + // The callback passed to Connect(). + net::CompletionCallback* user_connect_callback_; +}; + +} // namespace notifier + +#endif // JINGLE_NOTIFIER_BASE_PROXY_RESOLVING_CLIENT_SOCKET_H_ diff --git a/jingle/notifier/base/proxy_resolving_client_socket_unittest.cc b/jingle/notifier/base/proxy_resolving_client_socket_unittest.cc new file mode 100644 index 0000000..b8aa4b4 --- /dev/null +++ b/jingle/notifier/base/proxy_resolving_client_socket_unittest.cc @@ -0,0 +1,85 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "jingle/notifier/base/proxy_resolving_client_socket.h" + +#include "base/basictypes.h" +#include "base/message_loop.h" +#include "net/base/capturing_net_log.h" +#include "net/url_request/url_request_context_getter.h" +#include "net/url_request/url_request_test_util.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { +// TODO(sanjeevr): Move this to net_test_support. +// Used to return a dummy context. +class TestURLRequestContextGetter : public net::URLRequestContextGetter { + public: + TestURLRequestContextGetter() + : message_loop_proxy_(base::MessageLoopProxy::CreateForCurrentThread()) { + } + virtual ~TestURLRequestContextGetter() { } + + // net::URLRequestContextGetter: + virtual net::URLRequestContext* GetURLRequestContext() { + if (!context_) + context_ = new TestURLRequestContext(); + return context_.get(); + } + virtual scoped_refptr<base::MessageLoopProxy> GetIOMessageLoopProxy() const { + return message_loop_proxy_; + } + + private: + scoped_refptr<net::URLRequestContext> context_; + scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; +}; +} // namespace + +namespace notifier { + +class ProxyResolvingClientSocketTest : public testing::Test { + protected: + ProxyResolvingClientSocketTest() + : url_request_context_getter_(new TestURLRequestContextGetter()), + capturing_net_log_(net::CapturingNetLog::kUnbounded), + connect_callback_(ALLOW_THIS_IN_INITIALIZER_LIST(this), + &ProxyResolvingClientSocketTest::NetCallback) { } + + virtual ~ProxyResolvingClientSocketTest() {} + + virtual void TearDown() { + // Clear out any messages posted by ProxyResolvingClientSocket's + // destructor. + message_loop_.RunAllPending(); + } + + MOCK_METHOD1(NetCallback, void(int status)); + + // Needed by XmppConnection. + MessageLoop message_loop_; + scoped_refptr<TestURLRequestContextGetter> url_request_context_getter_; + net::CapturingNetLog capturing_net_log_; + net::CompletionCallbackImpl<ProxyResolvingClientSocketTest> connect_callback_; +}; + +TEST_F(ProxyResolvingClientSocketTest, ConnectError) { + net::HostPortPair dest("0.0.0.0", 0); + ProxyResolvingClientSocket proxy_resolving_socket( + url_request_context_getter_, + net::SSLConfig(), + dest, + &capturing_net_log_); + // ProxyResolvingClientSocket::Connect() will always return an error of + // ERR_ADDRESS_INVALID for a 0 IP address. + EXPECT_CALL(*this, NetCallback(net::ERR_ADDRESS_INVALID)).Times(1); + int status = proxy_resolving_socket.Connect(&connect_callback_); + // Connect always returns ERR_IO_PENDING because it is always asynchronous. + EXPECT_EQ(status, net::ERR_IO_PENDING); + message_loop_.RunAllPending(); +} + +// TODO(sanjeevr): Add more unit-tests. +} // namespace notifier diff --git a/jingle/notifier/base/resolving_client_socket_factory.h b/jingle/notifier/base/resolving_client_socket_factory.h new file mode 100644 index 0000000..a60e22f --- /dev/null +++ b/jingle/notifier/base/resolving_client_socket_factory.h @@ -0,0 +1,37 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef JINGLE_NOTIFIER_BASE_RESOLVING_CLIENT_SOCKET_FACTORY_H_ +#define JINGLE_NOTIFIER_BASE_RESOLVING_CLIENT_SOCKET_FACTORY_H_ + + +namespace net { +class ClientSocket; +class ClientSocketHandle; +class HostPortPair; +class NetLog; +class SSLClientSocket; +} + +// TODO(sanjeevr): Move this to net/ + +namespace notifier { + +// Interface for a ClientSocketFactory that creates ClientSockets that can +// resolve host names and tunnel through proxies. +class ResolvingClientSocketFactory { + public: + virtual ~ResolvingClientSocketFactory() { } + // Method to create a transport socket using a HostPortPair. + virtual net::ClientSocket* CreateTransportClientSocket( + const net::HostPortPair& host_and_port, net::NetLog* net_log) = 0; + + virtual net::SSLClientSocket* CreateSSLClientSocket( + net::ClientSocketHandle* transport_socket, + const net::HostPortPair& host_and_port) = 0; +}; + +} // namespace notifier + +#endif // JINGLE_NOTIFIER_BASE_RESOLVING_CLIENT_SOCKET_FACTORY_H_ diff --git a/jingle/notifier/base/xmpp_client_socket_factory.cc b/jingle/notifier/base/xmpp_client_socket_factory.cc index a4c4835..2c73de7 100644 --- a/jingle/notifier/base/xmpp_client_socket_factory.cc +++ b/jingle/notifier/base/xmpp_client_socket_factory.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,13 +6,21 @@ #include "base/logging.h" #include "jingle/notifier/base/fake_ssl_client_socket.h" +#include "jingle/notifier/base/proxy_resolving_client_socket.h" +#include "net/socket/client_socket_factory.h" +#include "net/url_request/url_request_context.h" +#include "net/url_request/url_request_context_getter.h" namespace notifier { XmppClientSocketFactory::XmppClientSocketFactory( net::ClientSocketFactory* client_socket_factory, + const net::SSLConfig& ssl_config, + const scoped_refptr<net::URLRequestContextGetter>& request_context_getter, bool use_fake_ssl_client_socket) : client_socket_factory_(client_socket_factory), + request_context_getter_(request_context_getter), + ssl_config_(ssl_config), use_fake_ssl_client_socket_(use_fake_ssl_client_socket) { CHECK(client_socket_factory_); } @@ -20,30 +28,23 @@ XmppClientSocketFactory::XmppClientSocketFactory( XmppClientSocketFactory::~XmppClientSocketFactory() {} net::ClientSocket* XmppClientSocketFactory::CreateTransportClientSocket( - const net::AddressList& addresses, - net::NetLog* net_log, - const net::NetLog::Source& source) { - net::ClientSocket* transport_socket = - client_socket_factory_->CreateTransportClientSocket( - addresses, net_log, source); + const net::HostPortPair& host_and_port, net::NetLog* net_log) { + net::ClientSocket* transport_socket = new ProxyResolvingClientSocket( + request_context_getter_, + ssl_config_, + host_and_port, + net_log); return (use_fake_ssl_client_socket_ ? new FakeSSLClientSocket(transport_socket) : transport_socket); } net::SSLClientSocket* XmppClientSocketFactory::CreateSSLClientSocket( net::ClientSocketHandle* transport_socket, - const net::HostPortPair& host_and_port, - const net::SSLConfig& ssl_config, - net::SSLHostInfo* ssl_host_info, - net::CertVerifier* cert_verifier, - net::DnsCertProvenanceChecker* dns_cert_checker) { + const net::HostPortPair& host_and_port) { return client_socket_factory_->CreateSSLClientSocket( - transport_socket, host_and_port, ssl_config, ssl_host_info, - cert_verifier, dns_cert_checker); + transport_socket, host_and_port, ssl_config_, NULL, + request_context_getter_->GetURLRequestContext()->cert_verifier(), NULL); } -void XmppClientSocketFactory::ClearSSLSessionCache() { - client_socket_factory_->ClearSSLSessionCache(); -} } // namespace diff --git a/jingle/notifier/base/xmpp_client_socket_factory.h b/jingle/notifier/base/xmpp_client_socket_factory.h index 291cadf..2f9f7eb 100644 --- a/jingle/notifier/base/xmpp_client_socket_factory.h +++ b/jingle/notifier/base/xmpp_client_socket_factory.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,38 +7,46 @@ #include <string> -#include "net/socket/client_socket_factory.h" +#include "base/memory/ref_counted.h" +#include "jingle/notifier/base/resolving_client_socket_factory.h" +#include "net/base/ssl_config_service.h" namespace net { -class DnsCertProvenanceChecker; +class ClientSocket; +class ClientSocketFactory; +class ClientSocketHandle; class HostPortPair; +class NetLog; +class SSLClientSocket; class SSLHostInfo; +class URLRequestContextGetter; } namespace notifier { -class XmppClientSocketFactory : public net::ClientSocketFactory { +class XmppClientSocketFactory : public ResolvingClientSocketFactory { public: // Does not take ownership of |client_socket_factory|. XmppClientSocketFactory( net::ClientSocketFactory* client_socket_factory, + const net::SSLConfig& ssl_config, + const scoped_refptr<net::URLRequestContextGetter>& request_context_getter, bool use_fake_ssl_client_socket); virtual ~XmppClientSocketFactory(); - // net::ClientSocketFactory implementation. + // ResolvingClientSocketFactory implementation. virtual net::ClientSocket* CreateTransportClientSocket( - const net::AddressList& addresses, net::NetLog* net_log, - const net::NetLog::Source& source); + const net::HostPortPair& host_and_port, net::NetLog* net_log); + virtual net::SSLClientSocket* CreateSSLClientSocket( net::ClientSocketHandle* transport_socket, - const net::HostPortPair& host_and_port, const net::SSLConfig& ssl_config, - net::SSLHostInfo* ssl_host_info, net::CertVerifier* cert_verifier, - net::DnsCertProvenanceChecker* dns_cert_checker); - virtual void ClearSSLSessionCache(); + const net::HostPortPair& host_and_port); private: net::ClientSocketFactory* const client_socket_factory_; + scoped_refptr<net::URLRequestContextGetter> request_context_getter_; + const net::SSLConfig ssl_config_; const bool use_fake_ssl_client_socket_; DISALLOW_COPY_AND_ASSIGN(XmppClientSocketFactory); diff --git a/jingle/notifier/base/xmpp_connection.cc b/jingle/notifier/base/xmpp_connection.cc index 98d3070..a347d89 100644 --- a/jingle/notifier/base/xmpp_connection.cc +++ b/jingle/notifier/base/xmpp_connection.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,6 +13,8 @@ #include "jingle/notifier/base/weak_xmpp_client.h" #include "jingle/notifier/base/xmpp_client_socket_factory.h" #include "net/base/ssl_config_service.h" +#include "net/socket/client_socket_factory.h" +#include "net/url_request/url_request_context.h" #include "talk/xmpp/xmppclientsettings.h" namespace notifier { @@ -21,31 +23,32 @@ namespace { buzz::AsyncSocket* CreateSocket( const buzz::XmppClientSettings& xmpp_client_settings, - net::CertVerifier* cert_verifier) { + const scoped_refptr<net::URLRequestContextGetter>& request_context_getter) { bool use_fake_ssl_client_socket = (xmpp_client_settings.protocol() == cricket::PROTO_SSLTCP); - net::ClientSocketFactory* const client_socket_factory = - new XmppClientSocketFactory( - net::ClientSocketFactory::GetDefaultFactory(), - use_fake_ssl_client_socket); // The default SSLConfig is good enough for us for now. const net::SSLConfig ssl_config; // These numbers were taken from similar numbers in // XmppSocketAdapter. const size_t kReadBufSize = 64U * 1024U; const size_t kWriteBufSize = 64U * 1024U; - // TODO(akalin): Use a real NetLog. - net::NetLog* const net_log = NULL; - return new ChromeAsyncSocket( - client_socket_factory, ssl_config, cert_verifier, - kReadBufSize, kWriteBufSize, net_log); + net::NetLog* const net_log = + request_context_getter->GetURLRequestContext()->net_log(); + XmppClientSocketFactory* const client_socket_factory = + new XmppClientSocketFactory( + net::ClientSocketFactory::GetDefaultFactory(), + ssl_config, + request_context_getter, + use_fake_ssl_client_socket); + return new ChromeAsyncSocket(client_socket_factory, + kReadBufSize, kWriteBufSize, net_log); } } // namespace XmppConnection::XmppConnection( const buzz::XmppClientSettings& xmpp_client_settings, - net::CertVerifier* cert_verifier, + const scoped_refptr<net::URLRequestContextGetter>& request_context_getter, Delegate* delegate, buzz::PreXmppAuth* pre_xmpp_auth) : task_pump_(new TaskPump()), on_connect_called_(false), @@ -64,7 +67,7 @@ XmppConnection::XmppConnection( buzz::XmppReturnStatus connect_status = weak_xmpp_client->Connect(xmpp_client_settings, kLanguage, CreateSocket(xmpp_client_settings, - cert_verifier), + request_context_getter), pre_xmpp_auth); // buzz::XmppClient::Connect() should never fail. DCHECK_EQ(connect_status, buzz::XMPP_RETURN_OK); diff --git a/jingle/notifier/base/xmpp_connection.h b/jingle/notifier/base/xmpp_connection.h index 1c03857..8252023 100644 --- a/jingle/notifier/base/xmpp_connection.h +++ b/jingle/notifier/base/xmpp_connection.h @@ -9,9 +9,11 @@ #pragma once #include "base/basictypes.h" +#include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/threading/non_thread_safe.h" +#include "net/url_request/url_request_context_getter.h" #include "talk/base/sigslot.h" #include "talk/xmpp/xmppengine.h" #include "testing/gtest/include/gtest/gtest_prod.h" @@ -22,10 +24,6 @@ class XmlElement; class XmppClientSettings; } // namespace -namespace net { -class CertVerifier; -} // namespace - namespace talk_base { class Task; } // namespace @@ -69,7 +67,8 @@ class XmppConnection : public sigslot::has_slots<> { // // TODO(akalin): Avoid the need for |pre_xmpp_auth|. XmppConnection(const buzz::XmppClientSettings& xmpp_client_settings, - net::CertVerifier* cert_verifier, + const scoped_refptr<net::URLRequestContextGetter>& + request_context_getter, Delegate* delegate, buzz::PreXmppAuth* pre_xmpp_auth); // Invalidates any weak pointers passed to the delegate by diff --git a/jingle/notifier/base/xmpp_connection_unittest.cc b/jingle/notifier/base/xmpp_connection_unittest.cc index 01f2b28..f142750 100644 --- a/jingle/notifier/base/xmpp_connection_unittest.cc +++ b/jingle/notifier/base/xmpp_connection_unittest.cc @@ -12,6 +12,8 @@ #include "base/message_loop.h" #include "jingle/notifier/base/weak_xmpp_client.h" #include "net/base/cert_verifier.h" +#include "net/url_request/url_request_context_getter.h" +#include "net/url_request/url_request_test_util.h" #include "talk/xmpp/prexmppauth.h" #include "talk/xmpp/xmppclientsettings.h" #include "testing/gmock/include/gmock/gmock.h" @@ -28,6 +30,32 @@ class SocketAddress; class Task; } // namespace talk_base +namespace { +// TODO(sanjeevr): Move this to net_test_support. +// Used to return a dummy context. +class TestURLRequestContextGetter : public net::URLRequestContextGetter { + public: + TestURLRequestContextGetter() + : message_loop_proxy_(base::MessageLoopProxy::CreateForCurrentThread()) { + } + virtual ~TestURLRequestContextGetter() { } + + // net::URLRequestContextGetter: + virtual net::URLRequestContext* GetURLRequestContext() { + if (!context_) + context_ = new TestURLRequestContext(); + return context_.get(); + } + virtual scoped_refptr<base::MessageLoopProxy> GetIOMessageLoopProxy() const { + return message_loop_proxy_; + } + + private: + scoped_refptr<net::URLRequestContext> context_; + scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; +}; +} // namespace + namespace notifier { using ::testing::_; @@ -66,7 +94,9 @@ class MockXmppConnectionDelegate : public XmppConnection::Delegate { class XmppConnectionTest : public testing::Test { protected: - XmppConnectionTest() : mock_pre_xmpp_auth_(new MockPreXmppAuth()) {} + XmppConnectionTest() + : mock_pre_xmpp_auth_(new MockPreXmppAuth()), + url_request_context_getter_(new TestURLRequestContextGetter()) {} virtual ~XmppConnectionTest() {} @@ -77,13 +107,14 @@ class XmppConnectionTest : public testing::Test { // Needed by XmppConnection. MessageLoop message_loop_; - net::CertVerifier cert_verifier_; MockXmppConnectionDelegate mock_xmpp_connection_delegate_; scoped_ptr<MockPreXmppAuth> mock_pre_xmpp_auth_; + scoped_refptr<TestURLRequestContextGetter> url_request_context_getter_; }; TEST_F(XmppConnectionTest, CreateDestroy) { - XmppConnection xmpp_connection(buzz::XmppClientSettings(), &cert_verifier_, + XmppConnection xmpp_connection(buzz::XmppClientSettings(), + url_request_context_getter_, &mock_xmpp_connection_delegate_, NULL); } @@ -94,7 +125,8 @@ TEST_F(XmppConnectionTest, ImmediateFailure) { EXPECT_CALL(mock_xmpp_connection_delegate_, OnError(buzz::XmppEngine::ERROR_NONE, 0, NULL)); - XmppConnection xmpp_connection(buzz::XmppClientSettings(), &cert_verifier_, + XmppConnection xmpp_connection(buzz::XmppClientSettings(), + url_request_context_getter_, &mock_xmpp_connection_delegate_, NULL); // We need to do this *before* |xmpp_connection| gets destroyed or @@ -113,7 +145,7 @@ TEST_F(XmppConnectionTest, PreAuthFailure) { OnError(buzz::XmppEngine::ERROR_AUTH, 5, NULL)); XmppConnection xmpp_connection( - buzz::XmppClientSettings(), &cert_verifier_, + buzz::XmppClientSettings(), url_request_context_getter_, &mock_xmpp_connection_delegate_, mock_pre_xmpp_auth_.release()); // We need to do this *before* |xmpp_connection| gets destroyed or @@ -131,7 +163,7 @@ TEST_F(XmppConnectionTest, FailureAfterPreAuth) { OnError(buzz::XmppEngine::ERROR_NONE, 0, NULL)); XmppConnection xmpp_connection( - buzz::XmppClientSettings(), &cert_verifier_, + buzz::XmppClientSettings(), url_request_context_getter_, &mock_xmpp_connection_delegate_, mock_pre_xmpp_auth_.release()); // We need to do this *before* |xmpp_connection| gets destroyed or @@ -143,7 +175,8 @@ TEST_F(XmppConnectionTest, RaisedError) { EXPECT_CALL(mock_xmpp_connection_delegate_, OnError(buzz::XmppEngine::ERROR_NONE, 0, NULL)); - XmppConnection xmpp_connection(buzz::XmppClientSettings(), &cert_verifier_, + XmppConnection xmpp_connection(buzz::XmppClientSettings(), + url_request_context_getter_, &mock_xmpp_connection_delegate_, NULL); xmpp_connection.weak_xmpp_client_-> @@ -156,7 +189,8 @@ TEST_F(XmppConnectionTest, Connect) { WillOnce(SaveArg<0>(&weak_ptr)); { - XmppConnection xmpp_connection(buzz::XmppClientSettings(), &cert_verifier_, + XmppConnection xmpp_connection(buzz::XmppClientSettings(), + url_request_context_getter_, &mock_xmpp_connection_delegate_, NULL); xmpp_connection.weak_xmpp_client_-> @@ -173,7 +207,8 @@ TEST_F(XmppConnectionTest, MultipleConnect) { EXPECT_CALL(mock_xmpp_connection_delegate_, OnConnect(_)). WillOnce(SaveArg<0>(&weak_ptr)); - XmppConnection xmpp_connection(buzz::XmppClientSettings(), &cert_verifier_, + XmppConnection xmpp_connection(buzz::XmppClientSettings(), + url_request_context_getter_, &mock_xmpp_connection_delegate_, NULL); xmpp_connection.weak_xmpp_client_-> @@ -194,7 +229,8 @@ TEST_F(XmppConnectionTest, ConnectThenError) { EXPECT_CALL(mock_xmpp_connection_delegate_, OnError(buzz::XmppEngine::ERROR_NONE, 0, NULL)); - XmppConnection xmpp_connection(buzz::XmppClientSettings(), &cert_verifier_, + XmppConnection xmpp_connection(buzz::XmppClientSettings(), + url_request_context_getter_, &mock_xmpp_connection_delegate_, NULL); xmpp_connection.weak_xmpp_client_-> diff --git a/jingle/notifier/communicator/login.cc b/jingle/notifier/communicator/login.cc index 3e21db7..42fa0fc 100644 --- a/jingle/notifier/communicator/login.cc +++ b/jingle/notifier/communicator/login.cc @@ -33,16 +33,15 @@ static const int kRedirectTimeoutMinutes = 5; Login::Login(Delegate* delegate, const buzz::XmppClientSettings& user_settings, const ConnectionOptions& options, - net::HostResolver* host_resolver, - net::CertVerifier* cert_verifier, + const scoped_refptr<net::URLRequestContextGetter>& + request_context_getter, const ServerList& servers, bool try_ssltcp_first, const std::string& auth_mechanism) : delegate_(delegate), login_settings_(new LoginSettings(user_settings, options, - host_resolver, - cert_verifier, + request_context_getter, servers, try_ssltcp_first, auth_mechanism)), diff --git a/jingle/notifier/communicator/login.h b/jingle/notifier/communicator/login.h index 1240171..8c2530c 100644 --- a/jingle/notifier/communicator/login.h +++ b/jingle/notifier/communicator/login.h @@ -7,6 +7,7 @@ #include <string> +#include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/time.h" @@ -23,8 +24,7 @@ class XmppClientSettings; } // namespace buzz namespace net { -class CertVerifier; -class HostResolver; +class URLRequestContextGetter; } // namespace net namespace talk_base { @@ -60,8 +60,8 @@ class Login : public net::NetworkChangeNotifier::IPAddressObserver, Login(Delegate* delegate, const buzz::XmppClientSettings& user_settings, const ConnectionOptions& options, - net::HostResolver* host_resolver, - net::CertVerifier* cert_verifier, + const scoped_refptr<net::URLRequestContextGetter>& + request_context_getter, const ServerList& servers, bool try_ssltcp_first, const std::string& auth_mechanism); diff --git a/jingle/notifier/communicator/login_settings.cc b/jingle/notifier/communicator/login_settings.cc index 6ed3a8c..f36e739 100644 --- a/jingle/notifier/communicator/login_settings.cc +++ b/jingle/notifier/communicator/login_settings.cc @@ -19,20 +19,17 @@ namespace notifier { LoginSettings::LoginSettings(const buzz::XmppClientSettings& user_settings, const ConnectionOptions& options, - net::HostResolver* host_resolver, - net::CertVerifier* cert_verifier, + const scoped_refptr<net::URLRequestContextGetter>& + request_context_getter, const ServerList& servers, bool try_ssltcp_first, const std::string& auth_mechanism) : try_ssltcp_first_(try_ssltcp_first), - host_resolver_(host_resolver), - cert_verifier_(cert_verifier), + request_context_getter_(request_context_getter), servers_(servers), user_settings_(new buzz::XmppClientSettings(user_settings)), connection_options_(new ConnectionOptions(options)), auth_mechanism_(auth_mechanism) { - DCHECK(host_resolver); - DCHECK(cert_verifier); DCHECK_GT(servers_.size(), 0u); } diff --git a/jingle/notifier/communicator/login_settings.h b/jingle/notifier/communicator/login_settings.h index 5bc8160..dd8a373 100644 --- a/jingle/notifier/communicator/login_settings.h +++ b/jingle/notifier/communicator/login_settings.h @@ -6,19 +6,15 @@ #define JINGLE_NOTIFIER_COMMUNICATOR_LOGIN_SETTINGS_H_ #include <string> +#include "base/memory/ref_counted.h" #include "jingle/notifier/base/server_information.h" #include "jingle/notifier/communicator/xmpp_connection_generator.h" +#include "net/url_request/url_request_context_getter.h" namespace buzz { class XmppClientSettings; } -namespace net { -class CertVerifier; -class HostPortPair; -class HostResolver; -} - namespace talk_base { class SocketAddress; } @@ -30,8 +26,8 @@ class LoginSettings { public: LoginSettings(const buzz::XmppClientSettings& user_settings, const ConnectionOptions& options, - net::HostResolver* host_resolver, - net::CertVerifier* cert_verifier, + const scoped_refptr<net::URLRequestContextGetter>& + request_context_getter, const ServerList& servers, bool try_ssltcp_first, const std::string& auth_mechanism); @@ -42,12 +38,8 @@ class LoginSettings { return try_ssltcp_first_; } - net::HostResolver* host_resolver() { - return host_resolver_; - } - - net::CertVerifier* cert_verifier() { - return cert_verifier_; + scoped_refptr<net::URLRequestContextGetter> request_context_getter() { + return request_context_getter_; } ServerList servers() const { @@ -77,8 +69,7 @@ class LoginSettings { private: bool try_ssltcp_first_; - net::HostResolver* const host_resolver_; - net::CertVerifier* const cert_verifier_; + scoped_refptr<net::URLRequestContextGetter> request_context_getter_; const ServerList servers_; // Used to handle redirects scoped_ptr<ServerInformation> server_override_; diff --git a/jingle/notifier/communicator/single_login_attempt.cc b/jingle/notifier/communicator/single_login_attempt.cc index 2cf99d3..21ab68e 100644 --- a/jingle/notifier/communicator/single_login_attempt.cc +++ b/jingle/notifier/communicator/single_login_attempt.cc @@ -17,6 +17,8 @@ #include "jingle/notifier/communicator/connection_settings.h" #include "jingle/notifier/communicator/login_settings.h" #include "jingle/notifier/listener/xml_element_util.h" +#include "net/url_request/url_request_context.h" +#include "net/url_request/url_request_context_getter.h" #include "talk/xmllite/xmlelement.h" #include "talk/xmpp/xmppclient.h" #include "talk/xmpp/xmppclientsettings.h" @@ -34,10 +36,14 @@ SingleLoginAttempt::SingleLoginAttempt(LoginSettings* login_settings, delegate_(delegate), connection_generator_( ALLOW_THIS_IN_INITIALIZER_LIST(this), - login_settings_->host_resolver(), + login_settings_->request_context_getter()->GetURLRequestContext()-> + host_resolver(), &login_settings_->connection_options(), login_settings_->try_ssltcp_first(), login_settings_->servers()) { + // DNS resolution will happen at a lower layer (we are using the socket + // pools). + connection_generator_.SetShouldResolveDNS(false); connection_generator_.StartGenerating(); } @@ -95,13 +101,6 @@ void SingleLoginAttempt::OnError(buzz::XmppEngine::Error error, int subcode, void SingleLoginAttempt::OnNewSettings( const ConnectionSettings& connection_settings) { - // TODO(akalin): Resolve any unresolved IPs, possibly through a - // proxy, instead of skipping them. - if (connection_settings.server().IsUnresolvedIP()) { - connection_generator_.UseNextConnection(); - return; - } - buzz::XmppClientSettings client_settings = login_settings_->user_settings(); // Fill in the rest of the client settings. @@ -115,7 +114,8 @@ void SingleLoginAttempt::OnNewSettings( client_settings.token_service(), login_settings_->auth_mechanism()); xmpp_connection_.reset( - new XmppConnection(client_settings, login_settings_->cert_verifier(), + new XmppConnection(client_settings, + login_settings_->request_context_getter(), this, pre_xmpp_auth)); } diff --git a/jingle/notifier/communicator/xmpp_connection_generator.cc b/jingle/notifier/communicator/xmpp_connection_generator.cc index 77282e7..5a234e7 100644 --- a/jingle/notifier/communicator/xmpp_connection_generator.cc +++ b/jingle/notifier/communicator/xmpp_connection_generator.cc @@ -56,6 +56,7 @@ XmppConnectionGenerator::XmppConnectionGenerator( try_ssltcp_first_(try_ssltcp_first), successfully_resolved_dns_(false), first_dns_error_(0), + should_resolve_dns_(true), options_(options) { DCHECK(delegate_); DCHECK(host_resolver); @@ -119,18 +120,26 @@ void XmppConnectionGenerator::UseNextConnection() { return; } - // Resolve the server. - const net::HostPortPair& server = current_server_->server; - net::HostResolver::RequestInfo request_info(server); - int status = - host_resolver_.Resolve( - request_info, &address_list_, resolve_callback_.get(), - bound_net_log_); - if (status == net::ERR_IO_PENDING) { - // resolve_callback_ will call us when it's called. - return; + if (should_resolve_dns_) { + // Resolve the server. + const net::HostPortPair& server = current_server_->server; + net::HostResolver::RequestInfo request_info(server); + int status = + host_resolver_.Resolve( + request_info, &address_list_, resolve_callback_.get(), + bound_net_log_); + if (status == net::ERR_IO_PENDING) { + // resolve_callback_ will call us when it's called. + return; + } + HandleServerDNSResolved(status); + } else { + // We are not resolving DNS here (DNS will be resolved by a lower layer). + // Generate settings using an empty IP list (which will just use the + // host name for the current server). + std::vector<uint32> ip_list; + GenerateSettingsForIPList(ip_list); } - HandleServerDNSResolved(status); } } @@ -169,6 +178,11 @@ void XmppConnectionGenerator::HandleServerDNSResolved(int status) { << " : " << talk_base::SocketAddress::IPToString(ip_list[i]); } + GenerateSettingsForIPList(ip_list); +} + +void XmppConnectionGenerator::GenerateSettingsForIPList( + const std::vector<uint32>& ip_list) { // Build the ip list. DCHECK(settings_list_.get()); settings_index_ = -1; diff --git a/jingle/notifier/communicator/xmpp_connection_generator.h b/jingle/notifier/communicator/xmpp_connection_generator.h index 0c955ce..38e964a 100644 --- a/jingle/notifier/communicator/xmpp_connection_generator.h +++ b/jingle/notifier/communicator/xmpp_connection_generator.h @@ -57,9 +57,15 @@ class XmppConnectionGenerator { void UseNextConnection(); + // TODO(sanjeevr): Rip out the DNS resolution code eventually. + void SetShouldResolveDNS(bool should_resolve_dns) { + should_resolve_dns_ = should_resolve_dns; + } + private: void OnServerDNSResolved(int status); void HandleServerDNSResolved(int status); + void GenerateSettingsForIPList(const std::vector<uint32>& ip_list); Delegate* delegate_; net::SingleRequestHostResolver host_resolver_; @@ -73,6 +79,7 @@ class XmppConnectionGenerator { bool try_ssltcp_first_; // Used when sync tests are run on chromium builders. bool successfully_resolved_dns_; int first_dns_error_; + bool should_resolve_dns_; const ConnectionOptions* options_; DISALLOW_COPY_AND_ASSIGN(XmppConnectionGenerator); diff --git a/jingle/notifier/listener/mediator_thread_impl.cc b/jingle/notifier/listener/mediator_thread_impl.cc index 9ef6ea9..38520e4 100644 --- a/jingle/notifier/listener/mediator_thread_impl.cc +++ b/jingle/notifier/listener/mediator_thread_impl.cc @@ -99,10 +99,7 @@ void MediatorThreadImpl::Core::Login(const buzz::XmppClientSettings& settings) { login_.reset(new notifier::Login(this, settings, notifier::ConnectionOptions(), - notifier_options_.request_context_getter-> - GetURLRequestContext()->host_resolver(), - notifier_options_.request_context_getter-> - GetURLRequestContext()->cert_verifier(), + notifier_options_.request_context_getter, GetServerList(notifier_options_), notifier_options_.try_ssltcp_first, notifier_options_.auth_mechanism)); |