summaryrefslogtreecommitdiffstats
path: root/jingle
diff options
context:
space:
mode:
authorsanjeevr@chromium.org <sanjeevr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-15 22:34:37 +0000
committersanjeevr@chromium.org <sanjeevr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-15 22:34:37 +0000
commit2e7f6e8287bb2e139da7bba876138e2d0f275714 (patch)
treeae15c658c20275eeb3b278d226662af46064f8e5 /jingle
parentae4b68e2c7344f560f12b7e34946188b691a4695 (diff)
downloadchromium_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')
-rw-r--r--jingle/jingle.gyp4
-rw-r--r--jingle/notifier/base/chrome_async_socket.cc50
-rw-r--r--jingle/notifier/base/chrome_async_socket.h17
-rw-r--r--jingle/notifier/base/chrome_async_socket_unittest.cc66
-rw-r--r--jingle/notifier/base/proxy_resolving_client_socket.cc337
-rw-r--r--jingle/notifier/base/proxy_resolving_client_socket.h94
-rw-r--r--jingle/notifier/base/proxy_resolving_client_socket_unittest.cc85
-rw-r--r--jingle/notifier/base/resolving_client_socket_factory.h37
-rw-r--r--jingle/notifier/base/xmpp_client_socket_factory.cc35
-rw-r--r--jingle/notifier/base/xmpp_client_socket_factory.h30
-rw-r--r--jingle/notifier/base/xmpp_connection.cc29
-rw-r--r--jingle/notifier/base/xmpp_connection.h9
-rw-r--r--jingle/notifier/base/xmpp_connection_unittest.cc56
-rw-r--r--jingle/notifier/communicator/login.cc7
-rw-r--r--jingle/notifier/communicator/login.h8
-rw-r--r--jingle/notifier/communicator/login_settings.cc9
-rw-r--r--jingle/notifier/communicator/login_settings.h23
-rw-r--r--jingle/notifier/communicator/single_login_attempt.cc18
-rw-r--r--jingle/notifier/communicator/xmpp_connection_generator.cc36
-rw-r--r--jingle/notifier/communicator/xmpp_connection_generator.h7
-rw-r--r--jingle/notifier/listener/mediator_thread_impl.cc5
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));