diff options
author | yzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-16 19:32:28 +0000 |
---|---|---|
committer | yzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-16 19:32:28 +0000 |
commit | b442da35fcf0bb0069390e819365bc7c9df37978 (patch) | |
tree | 5b66697e84c90964ea25b30fa36a8354f3b6e1f9 | |
parent | 63e627dc079238661c337c71e0061f06f49fbb41 (diff) | |
download | chromium_src-b442da35fcf0bb0069390e819365bc7c9df37978.zip chromium_src-b442da35fcf0bb0069390e819365bc7c9df37978.tar.gz chromium_src-b442da35fcf0bb0069390e819365bc7c9df37978.tar.bz2 |
Implement PPB_Flash_TCPSocket.InitiateSSL.
BUG=None
TEST=None
Review URL: http://codereview.chromium.org/7535007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@97005 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | content/browser/renderer_host/pepper_message_filter.cc | 276 | ||||
-rw-r--r-- | content/ppapi_plugin/ppapi_thread.cc | 2 | ||||
-rw-r--r-- | net/socket/client_socket_factory.h | 3 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_unittest.cc | 37 | ||||
-rw-r--r-- | ppapi/c/private/ppb_flash_tcp_socket.h | 16 | ||||
-rw-r--r-- | ppapi/cpp/private/flash_tcp_socket.cc | 10 | ||||
-rw-r--r-- | ppapi/cpp/private/flash_tcp_socket.h | 5 | ||||
-rw-r--r-- | ppapi/proxy/ppapi_messages.h | 8 | ||||
-rw-r--r-- | ppapi/proxy/ppb_flash_tcp_socket_proxy.cc | 88 | ||||
-rw-r--r-- | ppapi/proxy/ppb_flash_tcp_socket_proxy.h | 3 | ||||
-rw-r--r-- | ppapi/thunk/ppb_flash_tcp_socket_api.h | 5 | ||||
-rw-r--r-- | ppapi/thunk/ppb_flash_tcp_socket_thunk.cc | 12 |
12 files changed, 356 insertions, 109 deletions
diff --git a/content/browser/renderer_host/pepper_message_filter.cc b/content/browser/renderer_host/pepper_message_filter.cc index e38e376..c6bf6b4 100644 --- a/content/browser/renderer_host/pepper_message_filter.cc +++ b/content/browser/renderer_host/pepper_message_filter.cc @@ -12,6 +12,7 @@ #include "base/basictypes.h" #include "base/bind.h" #include "base/compiler_specific.h" +#include "base/logging.h" #include "base/memory/linked_ptr.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" @@ -24,13 +25,18 @@ #include "content/browser/resource_context.h" #include "content/common/pepper_messages.h" #include "net/base/address_list.h" +#include "net/base/cert_verifier.h" #include "net/base/ip_endpoint.h" -#include "net/base/net_errors.h" #include "net/base/host_port_pair.h" #include "net/base/host_resolver.h" #include "net/base/io_buffer.h" +#include "net/base/net_errors.h" #include "net/base/single_request_host_resolver.h" +#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 "net/url_request/url_request_context.h" #include "ppapi/c/private/ppb_flash_net_connector.h" @@ -120,7 +126,7 @@ const PP_Flash_NetAddress kInvalidNetAddress = { 0 }; class PepperMessageFilter::FlashTCPSocket { public: - FlashTCPSocket(PepperMessageFilter* pepper_message_filter, + FlashTCPSocket(FlashTCPSocketManager* manager, int32 routing_id, uint32 plugin_dispatcher_id, uint32 socket_id); @@ -128,32 +134,53 @@ class PepperMessageFilter::FlashTCPSocket { void Connect(const std::string& host, uint16_t port); void ConnectWithNetAddress(const PP_Flash_NetAddress& net_addr); + void SSLHandshake(const std::string& server_name, uint16_t server_port); void Read(int32 bytes_to_read); void Write(const std::string& data); private: + enum ConnectionState { + // Before a connection is successfully established (including a previous + // connect request failed). + BEFORE_CONNECT, + // There is a connect request that is pending. + CONNECT_IN_PROGRESS, + // A connection has been successfully established. + CONNECTED, + // There is an SSL handshake request that is pending. + SSL_HANDSHAKE_IN_PROGRESS, + // An SSL connection has been successfully established. + SSL_CONNECTED, + // An SSL handshake has failed. + SSL_HANDSHAKE_FAILED + }; + void StartConnect(const net::AddressList& addresses); void SendConnectACKError(); void SendReadACKError(); void SendWriteACKError(); + void SendSSLHandshakeACK(bool succeeded); void OnResolveCompleted(int result); void OnConnectCompleted(int result); + void OnSSLHandshakeCompleted(int result); void OnReadCompleted(int result); void OnWriteCompleted(int result); - PepperMessageFilter* pepper_message_filter_; + bool IsConnected() const; + + FlashTCPSocketManager* manager_; int32 routing_id_; uint32 plugin_dispatcher_id_; uint32 socket_id_; - bool connect_in_progress_; - bool connected_; + ConnectionState connection_state_; bool end_of_file_reached_; net::CompletionCallbackImpl<FlashTCPSocket> resolve_callback_; net::CompletionCallbackImpl<FlashTCPSocket> connect_callback_; + net::CompletionCallbackImpl<FlashTCPSocket> ssl_handshake_callback_; net::CompletionCallbackImpl<FlashTCPSocket> read_callback_; net::CompletionCallbackImpl<FlashTCPSocket> write_callback_; @@ -168,27 +195,78 @@ class PepperMessageFilter::FlashTCPSocket { DISALLOW_COPY_AND_ASSIGN(FlashTCPSocket); }; +// FlashTCPSocketManager manages the mapping from socket IDs to FlashTCPSocket +// instances. +class PepperMessageFilter::FlashTCPSocketManager { + public: + explicit FlashTCPSocketManager(PepperMessageFilter* pepper_message_filter); + + void OnMsgCreate(int32 routing_id, + uint32 plugin_dispatcher_id, + uint32* socket_id); + void OnMsgConnect(uint32 socket_id, + const std::string& host, + uint16_t port); + void OnMsgConnectWithNetAddress(uint32 socket_id, + const PP_Flash_NetAddress& net_addr); + void OnMsgSSLHandshake(uint32 socket_id, + const std::string& server_name, + uint16_t server_port); + void OnMsgRead(uint32 socket_id, int32_t bytes_to_read); + void OnMsgWrite(uint32 socket_id, const std::string& data); + void OnMsgDisconnect(uint32 socket_id); + + // Used by FlashTCPSocket. + bool Send(IPC::Message* message) { + return pepper_message_filter_->Send(message); + } + net::HostResolver* GetHostResolver() { + return pepper_message_filter_->GetHostResolver(); + } + const net::SSLConfig& ssl_config() { return ssl_config_; } + // The caller doesn't take ownership of the returned object. + net::CertVerifier* GetCertVerifier(); + + private: + typedef std::map<uint32, linked_ptr<FlashTCPSocket> > SocketMap; + SocketMap sockets_; + + uint32 next_socket_id_; + + PepperMessageFilter* pepper_message_filter_; + + // The default SSL configuration settings are used, as opposed to Chrome's SSL + // settings. + net::SSLConfig ssl_config_; + // This is lazily created. Users should use GetCertVerifier to retrieve it. + scoped_ptr<net::CertVerifier> cert_verifier_; + + DISALLOW_COPY_AND_ASSIGN(FlashTCPSocketManager); +}; + PepperMessageFilter::FlashTCPSocket::FlashTCPSocket( - PepperMessageFilter* pepper_message_filter, + FlashTCPSocketManager* manager, int32 routing_id, uint32 plugin_dispatcher_id, uint32 socket_id) - : pepper_message_filter_(pepper_message_filter), + : manager_(manager), routing_id_(routing_id), plugin_dispatcher_id_(plugin_dispatcher_id), socket_id_(socket_id), - connect_in_progress_(false), - connected_(false), + connection_state_(BEFORE_CONNECT), end_of_file_reached_(false), ALLOW_THIS_IN_INITIALIZER_LIST( resolve_callback_(this, &FlashTCPSocket::OnResolveCompleted)), ALLOW_THIS_IN_INITIALIZER_LIST( connect_callback_(this, &FlashTCPSocket::OnConnectCompleted)), ALLOW_THIS_IN_INITIALIZER_LIST( + ssl_handshake_callback_(this, + &FlashTCPSocket::OnSSLHandshakeCompleted)), + ALLOW_THIS_IN_INITIALIZER_LIST( read_callback_(this, &FlashTCPSocket::OnReadCompleted)), ALLOW_THIS_IN_INITIALIZER_LIST( write_callback_(this, &FlashTCPSocket::OnWriteCompleted)) { - DCHECK(pepper_message_filter); + DCHECK(manager); } PepperMessageFilter::FlashTCPSocket::~FlashTCPSocket() { @@ -201,15 +279,15 @@ void PepperMessageFilter::FlashTCPSocket::Connect(const std::string& host, uint16_t port) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - if (connect_in_progress_ || connected_) { + if (connection_state_ != BEFORE_CONNECT) { SendConnectACKError(); return; } - connect_in_progress_ = true; + connection_state_ = CONNECT_IN_PROGRESS; net::HostResolver::RequestInfo request_info(net::HostPortPair(host, port)); resolver_.reset(new net::SingleRequestHostResolver( - pepper_message_filter_->GetHostResolver())); + manager_->GetHostResolver())); int result = resolver_->Resolve(request_info, &address_list_, &resolve_callback_, net::BoundNetLog()); if (result != net::ERR_IO_PENDING) @@ -220,20 +298,56 @@ void PepperMessageFilter::FlashTCPSocket::ConnectWithNetAddress( const PP_Flash_NetAddress& net_addr) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - if (connect_in_progress_ || connected_ || + if (connection_state_ != BEFORE_CONNECT || !NetAddressToAddressList(net_addr, &address_list_)) { SendConnectACKError(); return; } - connect_in_progress_ = true; + connection_state_ = CONNECT_IN_PROGRESS; StartConnect(address_list_); } +void PepperMessageFilter::FlashTCPSocket::SSLHandshake( + const std::string& server_name, + uint16_t server_port) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + // Allow to do SSL handshake only if currently the socket has been connected + // and there isn't pending read or write. + // IsConnected() includes the state that SSL handshake has been finished and + // therefore isn't suitable here. + if (connection_state_ != CONNECTED || read_buffer_.get() || + write_buffer_.get()) { + SendSSLHandshakeACK(false); + return; + } + + connection_state_ = SSL_HANDSHAKE_IN_PROGRESS; + net::ClientSocketHandle* handle = new net::ClientSocketHandle(); + handle->set_socket(socket_.release()); + net::ClientSocketFactory* factory = + net::ClientSocketFactory::GetDefaultFactory(); + net::HostPortPair host_port_pair(server_name, server_port); + net::SSLClientSocketContext ssl_context; + ssl_context.cert_verifier = manager_->GetCertVerifier(); + socket_.reset(factory->CreateSSLClientSocket( + handle, host_port_pair, manager_->ssl_config(), NULL, ssl_context)); + if (!socket_.get()) { + LOG(WARNING) << "Failed to create an SSL client socket."; + OnSSLHandshakeCompleted(net::ERR_UNEXPECTED); + return; + } + + int result = socket_->Connect(&ssl_handshake_callback_); + if (result != net::ERR_IO_PENDING) + OnSSLHandshakeCompleted(result); +} + void PepperMessageFilter::FlashTCPSocket::Read(int32 bytes_to_read) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - if (!connected_ || end_of_file_reached_ || read_buffer_.get() || + if (!IsConnected() || end_of_file_reached_ || read_buffer_.get() || bytes_to_read <= 0) { SendReadACKError(); return; @@ -253,7 +367,7 @@ void PepperMessageFilter::FlashTCPSocket::Read(int32 bytes_to_read) { void PepperMessageFilter::FlashTCPSocket::Write(const std::string& data) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - if (!connected_ || write_buffer_.get() || data.empty()) { + if (!IsConnected() || write_buffer_.get() || data.empty()) { SendWriteACKError(); return; } @@ -273,7 +387,7 @@ void PepperMessageFilter::FlashTCPSocket::Write(const std::string& data) { void PepperMessageFilter::FlashTCPSocket::StartConnect( const net::AddressList& addresses) { - DCHECK(connect_in_progress_); + DCHECK(connection_state_ == CONNECT_IN_PROGRESS); socket_.reset( new net::TCPClientSocket(addresses, NULL, net::NetLog::Source())); @@ -283,31 +397,32 @@ void PepperMessageFilter::FlashTCPSocket::StartConnect( } void PepperMessageFilter::FlashTCPSocket::SendConnectACKError() { - pepper_message_filter_->Send( - new PpapiMsg_PPBFlashTCPSocket_ConnectACK( - routing_id_, plugin_dispatcher_id_, socket_id_, false, - kInvalidNetAddress, kInvalidNetAddress)); + manager_->Send(new PpapiMsg_PPBFlashTCPSocket_ConnectACK( + routing_id_, plugin_dispatcher_id_, socket_id_, false, + kInvalidNetAddress, kInvalidNetAddress)); } void PepperMessageFilter::FlashTCPSocket::SendReadACKError() { - pepper_message_filter_->Send( - new PpapiMsg_PPBFlashTCPSocket_ReadACK( - routing_id_, plugin_dispatcher_id_, socket_id_, false, - std::string())); + manager_->Send(new PpapiMsg_PPBFlashTCPSocket_ReadACK( + routing_id_, plugin_dispatcher_id_, socket_id_, false, std::string())); } void PepperMessageFilter::FlashTCPSocket::SendWriteACKError() { - pepper_message_filter_->Send( - new PpapiMsg_PPBFlashTCPSocket_WriteACK( - routing_id_, plugin_dispatcher_id_, socket_id_, false, 0)); + manager_->Send(new PpapiMsg_PPBFlashTCPSocket_WriteACK( + routing_id_, plugin_dispatcher_id_, socket_id_, false, 0)); +} + +void PepperMessageFilter::FlashTCPSocket::SendSSLHandshakeACK(bool succeeded) { + manager_->Send(new PpapiMsg_PPBFlashTCPSocket_SSLHandshakeACK( + routing_id_, plugin_dispatcher_id_, socket_id_, succeeded)); } void PepperMessageFilter::FlashTCPSocket::OnResolveCompleted(int result) { - DCHECK(connect_in_progress_); + DCHECK(connection_state_ == CONNECT_IN_PROGRESS); if (result != net::OK) { SendConnectACKError(); - connect_in_progress_ = false; + connection_state_ = BEFORE_CONNECT; return; } @@ -315,10 +430,11 @@ void PepperMessageFilter::FlashTCPSocket::OnResolveCompleted(int result) { } void PepperMessageFilter::FlashTCPSocket::OnConnectCompleted(int result) { - DCHECK(connect_in_progress_ && socket_.get()); + DCHECK(connection_state_ == CONNECT_IN_PROGRESS && socket_.get()); if (result != net::OK) { SendConnectACKError(); + connection_state_ = BEFORE_CONNECT; } else { net::IPEndPoint ip_end_point; net::AddressList address_list; @@ -330,31 +446,35 @@ void PepperMessageFilter::FlashTCPSocket::OnConnectCompleted(int result) { socket_->GetPeerAddress(&address_list) != net::OK || !AddressListToNetAddress(address_list, &remote_addr)) { SendConnectACKError(); + connection_state_ = BEFORE_CONNECT; } else { - pepper_message_filter_->Send( - new PpapiMsg_PPBFlashTCPSocket_ConnectACK( - routing_id_, plugin_dispatcher_id_, socket_id_, true, - local_addr, remote_addr)); - connected_ = true; + manager_->Send(new PpapiMsg_PPBFlashTCPSocket_ConnectACK( + routing_id_, plugin_dispatcher_id_, socket_id_, true, + local_addr, remote_addr)); + connection_state_ = CONNECTED; } } - connect_in_progress_ = false; +} + +void PepperMessageFilter::FlashTCPSocket::OnSSLHandshakeCompleted(int result) { + DCHECK(connection_state_ == SSL_HANDSHAKE_IN_PROGRESS); + + bool succeeded = result == net::OK; + SendSSLHandshakeACK(succeeded); + connection_state_ = succeeded ? SSL_CONNECTED : SSL_HANDSHAKE_FAILED; } void PepperMessageFilter::FlashTCPSocket::OnReadCompleted(int result) { DCHECK(read_buffer_.get()); if (result > 0) { - pepper_message_filter_->Send( - new PpapiMsg_PPBFlashTCPSocket_ReadACK( - routing_id_, plugin_dispatcher_id_, socket_id_, true, - std::string(read_buffer_->data(), result))); + manager_->Send(new PpapiMsg_PPBFlashTCPSocket_ReadACK( + routing_id_, plugin_dispatcher_id_, socket_id_, true, + std::string(read_buffer_->data(), result))); } else if (result == 0) { end_of_file_reached_ = true; - pepper_message_filter_->Send( - new PpapiMsg_PPBFlashTCPSocket_ReadACK( - routing_id_, plugin_dispatcher_id_, socket_id_, true, - std::string())); + manager_->Send(new PpapiMsg_PPBFlashTCPSocket_ReadACK( + routing_id_, plugin_dispatcher_id_, socket_id_, true, std::string())); } else { SendReadACKError(); } @@ -365,42 +485,18 @@ void PepperMessageFilter::FlashTCPSocket::OnWriteCompleted(int result) { DCHECK(write_buffer_.get()); if (result >= 0) { - pepper_message_filter_->Send( - new PpapiMsg_PPBFlashTCPSocket_WriteACK( - routing_id_, plugin_dispatcher_id_, socket_id_, true, result)); + manager_->Send(new PpapiMsg_PPBFlashTCPSocket_WriteACK( + routing_id_, plugin_dispatcher_id_, socket_id_, true, result)); } else { SendWriteACKError(); } write_buffer_ = NULL; } -// FlashTCPSocketManager manages the mapping from socket IDs to FlashTCPSocket -// instances. -class PepperMessageFilter::FlashTCPSocketManager { - public: - explicit FlashTCPSocketManager(PepperMessageFilter* pepper_message_filter); - - void OnMsgCreate(int32 routing_id, - uint32 plugin_dispatcher_id, - uint32* socket_id); - void OnMsgConnect(uint32 socket_id, - const std::string& host, - uint16_t port); - void OnMsgConnectWithNetAddress(uint32 socket_id, - const PP_Flash_NetAddress& net_addr); - void OnMsgRead(uint32 socket_id, int32_t bytes_to_read); - void OnMsgWrite(uint32 socket_id, const std::string& data); - void OnMsgDisconnect(uint32 socket_id); - - private: - typedef std::map<uint32, linked_ptr<FlashTCPSocket> > SocketMap; - SocketMap sockets_; - - uint32 next_socket_id_; - - PepperMessageFilter* pepper_message_filter_; - DISALLOW_COPY_AND_ASSIGN(FlashTCPSocketManager); -}; +bool PepperMessageFilter::FlashTCPSocket::IsConnected() const { + return connection_state_ == CONNECTED || + connection_state_ == SSL_CONNECTED; +} PepperMessageFilter::FlashTCPSocketManager::FlashTCPSocketManager( PepperMessageFilter* pepper_message_filter) @@ -434,8 +530,7 @@ void PepperMessageFilter::FlashTCPSocketManager::OnMsgCreate( } while (*socket_id == 0 || sockets_.find(*socket_id) != sockets_.end()); sockets_[*socket_id] = linked_ptr<FlashTCPSocket>( - new FlashTCPSocket(pepper_message_filter_, routing_id, - plugin_dispatcher_id, *socket_id)); + new FlashTCPSocket(this, routing_id, plugin_dispatcher_id, *socket_id)); } void PepperMessageFilter::FlashTCPSocketManager::OnMsgConnect( @@ -463,6 +558,19 @@ void PepperMessageFilter::FlashTCPSocketManager::OnMsgConnectWithNetAddress( iter->second->ConnectWithNetAddress(net_addr); } +void PepperMessageFilter::FlashTCPSocketManager::OnMsgSSLHandshake( + uint32 socket_id, + const std::string& server_name, + uint16_t server_port) { + SocketMap::iterator iter = sockets_.find(socket_id); + if (iter == sockets_.end()) { + NOTREACHED(); + return; + } + + iter->second->SSLHandshake(server_name, server_port); +} + void PepperMessageFilter::FlashTCPSocketManager::OnMsgRead( uint32 socket_id, int32_t bytes_to_read) { @@ -501,6 +609,14 @@ void PepperMessageFilter::FlashTCPSocketManager::OnMsgDisconnect( sockets_.erase(iter); } +net::CertVerifier* +PepperMessageFilter::FlashTCPSocketManager::GetCertVerifier() { + if (!cert_verifier_.get()) + cert_verifier_.reset(new net::CertVerifier()); + + return cert_verifier_.get(); +} + PepperMessageFilter::PepperMessageFilter( const content::ResourceContext* resource_context) : resource_context_(resource_context), @@ -543,6 +659,10 @@ bool PepperMessageFilter::OnMessageReceived(const IPC::Message& msg, socket_manager_.get(), FlashTCPSocketManager::OnMsgConnectWithNetAddress) IPC_MESSAGE_FORWARD( + PpapiHostMsg_PPBFlashTCPSocket_SSLHandshake, + socket_manager_.get(), + FlashTCPSocketManager::OnMsgSSLHandshake) + IPC_MESSAGE_FORWARD( PpapiHostMsg_PPBFlashTCPSocket_Read, socket_manager_.get(), FlashTCPSocketManager::OnMsgRead) IPC_MESSAGE_FORWARD( diff --git a/content/ppapi_plugin/ppapi_thread.cc b/content/ppapi_plugin/ppapi_thread.cc index 10d95d9..3648f20 100644 --- a/content/ppapi_plugin/ppapi_thread.cc +++ b/content/ppapi_plugin/ppapi_thread.cc @@ -74,6 +74,8 @@ bool PpapiThread::OnMessageReceived(const IPC::Message& msg) { IPC_MESSAGE_HANDLER(PpapiMsg_CreateChannel, OnMsgCreateChannel) IPC_MESSAGE_HANDLER_GENERIC(PpapiMsg_PPBFlashTCPSocket_ConnectACK, OnPluginDispatcherMessageReceived(msg)) + IPC_MESSAGE_HANDLER_GENERIC(PpapiMsg_PPBFlashTCPSocket_SSLHandshakeACK, + OnPluginDispatcherMessageReceived(msg)) IPC_MESSAGE_HANDLER_GENERIC(PpapiMsg_PPBFlashTCPSocket_ReadACK, OnPluginDispatcherMessageReceived(msg)) IPC_MESSAGE_HANDLER_GENERIC(PpapiMsg_PPBFlashTCPSocket_WriteACK, diff --git a/net/socket/client_socket_factory.h b/net/socket/client_socket_factory.h index b8e8d65..0f35194 100644 --- a/net/socket/client_socket_factory.h +++ b/net/socket/client_socket_factory.h @@ -47,6 +47,9 @@ class NET_EXPORT ClientSocketFactory { NetLog* net_log, const NetLog::Source& source) = 0; + // It is allowed to pass in a |transport_socket| that is not obtained from a + // socket pool. The caller could create a ClientSocketHandle directly and call + // set_socket() on it to set a valid StreamSocket instance. virtual SSLClientSocket* CreateSSLClientSocket( ClientSocketHandle* transport_socket, const HostPortPair& host_and_port, diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc index 02dd8f0..b835342 100644 --- a/net/socket/ssl_client_socket_unittest.cc +++ b/net/socket/ssl_client_socket_unittest.cc @@ -14,6 +14,7 @@ #include "net/base/ssl_config_service.h" #include "net/base/test_completion_callback.h" #include "net/socket/client_socket_factory.h" +#include "net/socket/client_socket_handle.h" #include "net/socket/socket_test_util.h" #include "net/socket/tcp_client_socket.h" #include "net/test/test_server.h" @@ -705,3 +706,39 @@ TEST_F(SSLClientSocketTest, CipherSuiteDisables) { EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1) || LogContainsSSLConnectEndEvent(entries, -2)); } + +// When creating an SSLClientSocket, it is allowed to pass in a +// ClientSocketHandle that is not obtained from a client socket pool. +// Here we verify that such a simple ClientSocketHandle, not associated with any +// client socket pool, can be destroyed safely. +TEST_F(SSLClientSocketTest, ClientSocketHandleNotFromPool) { + net::TestServer test_server(net::TestServer::TYPE_HTTPS, FilePath()); + ASSERT_TRUE(test_server.Start()); + + net::AddressList addr; + ASSERT_TRUE(test_server.GetAddressList(&addr)); + + TestCompletionCallback callback; + net::StreamSocket* transport = new net::TCPClientSocket( + addr, NULL, net::NetLog::Source()); + int rv = transport->Connect(&callback); + if (rv == net::ERR_IO_PENDING) + rv = callback.WaitForResult(); + EXPECT_EQ(net::OK, rv); + + net::ClientSocketHandle* socket_handle = new net::ClientSocketHandle(); + socket_handle->set_socket(transport); + + net::SSLClientSocketContext context; + context.cert_verifier = cert_verifier_.get(); + scoped_ptr<net::SSLClientSocket> ssl_socket( + socket_factory_->CreateSSLClientSocket( + socket_handle, test_server.host_port_pair(), kDefaultSSLConfig, + NULL, context)); + + EXPECT_FALSE(ssl_socket->IsConnected()); + rv = ssl_socket->Connect(&callback); + if (rv == net::ERR_IO_PENDING) + rv = callback.WaitForResult(); + EXPECT_EQ(net::OK, rv); +} diff --git a/ppapi/c/private/ppb_flash_tcp_socket.h b/ppapi/c/private/ppb_flash_tcp_socket.h index 6577631..c761300 100644 --- a/ppapi/c/private/ppb_flash_tcp_socket.h +++ b/ppapi/c/private/ppb_flash_tcp_socket.h @@ -17,7 +17,7 @@ struct PP_Flash_NetAddress { char data[128]; }; -#define PPB_FLASH_TCPSOCKET_INTERFACE "PPB_Flash_TCPSocket;0.1" +#define PPB_FLASH_TCPSOCKET_INTERFACE "PPB_Flash_TCPSocket;0.2" struct PPB_Flash_TCPSocket { PP_Resource (*Create)(PP_Instance instance); @@ -25,6 +25,8 @@ struct PPB_Flash_TCPSocket { PP_Bool (*IsFlashTCPSocket)(PP_Resource resource); // Connects to a TCP port given as a host-port pair. + // When a proxy server is used, |host| and |port| refer to the proxy server + // instead of the destination server. int32_t (*Connect)(PP_Resource tcp_socket, const char* host, uint16_t port, @@ -49,10 +51,14 @@ struct PPB_Flash_TCPSocket { // Does SSL handshake and moves to sending and receiving encrypted data. The // socket must have been successfully connected. |server_name| will be // compared with the name(s) in the server's certificate during the SSL - // handshake. - int32_t (*InitiateSSL)(PP_Resource tcp_socket, - const char* server_name, - struct PP_CompletionCallback callback); + // handshake. |server_port| is only used to identify an SSL server in the SSL + // session cache. + // When a proxy server is used, |server_name| and |server_port| refer to the + // destination server. + int32_t (*SSLHandshake)(PP_Resource tcp_socket, + const char* server_name, + uint16_t server_port, + struct PP_CompletionCallback callback); // Reads data from the socket. The size of |buffer| must be at least as large // as |bytes_to_read|. May perform a partial read. Returns the number of bytes diff --git a/ppapi/cpp/private/flash_tcp_socket.cc b/ppapi/cpp/private/flash_tcp_socket.cc index 82e6414..98e9906 100644 --- a/ppapi/cpp/private/flash_tcp_socket.cc +++ b/ppapi/cpp/private/flash_tcp_socket.cc @@ -66,12 +66,14 @@ bool TCPSocket::GetRemoteAddress(PP_Flash_NetAddress* remote_addr) { return PP_ToBool(result); } -int32_t TCPSocket::InitiateSSL(const char* server_name, - const CompletionCallback& callback) { +int32_t TCPSocket::SSLHandshake(const char* server_name, + uint16_t server_port, + const CompletionCallback& callback) { if (!has_interface<PPB_Flash_TCPSocket>()) return callback.MayForce(PP_ERROR_NOINTERFACE); - return get_interface<PPB_Flash_TCPSocket>()->InitiateSSL( - pp_resource(), server_name, callback.pp_completion_callback()); + return get_interface<PPB_Flash_TCPSocket>()->SSLHandshake( + pp_resource(), server_name, server_port, + callback.pp_completion_callback()); } int32_t TCPSocket::Read(char* buffer, diff --git a/ppapi/cpp/private/flash_tcp_socket.h b/ppapi/cpp/private/flash_tcp_socket.h index 8998728..b7ead00 100644 --- a/ppapi/cpp/private/flash_tcp_socket.h +++ b/ppapi/cpp/private/flash_tcp_socket.h @@ -31,8 +31,9 @@ class TCPSocket : public Resource { const CompletionCallback& callback); bool GetLocalAddress(PP_Flash_NetAddress* local_addr); bool GetRemoteAddress(PP_Flash_NetAddress* remote_addr); - int32_t InitiateSSL(const char* server_name, - const CompletionCallback& callback); + int32_t SSLHandshake(const char* server_name, + uint16_t server_port, + const CompletionCallback& callback); int32_t Read(char* buffer, int32_t bytes_to_read, const CompletionCallback& callback); diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h index 5b7c6dd..14799d73 100644 --- a/ppapi/proxy/ppapi_messages.h +++ b/ppapi/proxy/ppapi_messages.h @@ -212,6 +212,10 @@ IPC_MESSAGE_ROUTED5(PpapiMsg_PPBFlashTCPSocket_ConnectACK, bool /* succeeded */, PP_Flash_NetAddress /* local_addr */, PP_Flash_NetAddress /* remote_addr */) +IPC_MESSAGE_ROUTED3(PpapiMsg_PPBFlashTCPSocket_SSLHandshakeACK, + uint32 /* plugin_dispatcher_id */, + uint32 /* socket_id */, + bool /* succeeded */) IPC_MESSAGE_ROUTED4(PpapiMsg_PPBFlashTCPSocket_ReadACK, uint32 /* plugin_dispatcher_id */, uint32 /* socket_id */, @@ -680,6 +684,10 @@ IPC_MESSAGE_CONTROL3(PpapiHostMsg_PPBFlashTCPSocket_Connect, IPC_MESSAGE_CONTROL2(PpapiHostMsg_PPBFlashTCPSocket_ConnectWithNetAddress, uint32 /* socket_id */, PP_Flash_NetAddress /* net_addr */) +IPC_MESSAGE_CONTROL3(PpapiHostMsg_PPBFlashTCPSocket_SSLHandshake, + uint32 /* socket_id */, + std::string /* server_name */, + uint16_t /* server_port */) IPC_MESSAGE_CONTROL2(PpapiHostMsg_PPBFlashTCPSocket_Read, uint32 /* socket_id */, int32_t /* bytes_to_read */) diff --git a/ppapi/proxy/ppb_flash_tcp_socket_proxy.cc b/ppapi/proxy/ppb_flash_tcp_socket_proxy.cc index abe8a2d..5e5a272 100644 --- a/ppapi/proxy/ppb_flash_tcp_socket_proxy.cc +++ b/ppapi/proxy/ppb_flash_tcp_socket_proxy.cc @@ -75,8 +75,9 @@ class FlashTCPSocket : public PPB_Flash_TCPSocket_API, PP_CompletionCallback callback) OVERRIDE; virtual PP_Bool GetLocalAddress(PP_Flash_NetAddress* local_addr) OVERRIDE; virtual PP_Bool GetRemoteAddress(PP_Flash_NetAddress* remote_addr) OVERRIDE; - virtual int32_t InitiateSSL(const char* server_name, - PP_CompletionCallback callback) OVERRIDE; + virtual int32_t SSLHandshake(const char* server_name, + uint16_t server_port, + PP_CompletionCallback callback) OVERRIDE; virtual int32_t Read(char* buffer, int32_t bytes_to_read, PP_CompletionCallback callback) OVERRIDE; @@ -89,6 +90,7 @@ class FlashTCPSocket : public PPB_Flash_TCPSocket_API, void OnConnectCompleted(bool succeeded, const PP_Flash_NetAddress& local_addr, const PP_Flash_NetAddress& remote_addr); + void OnSSLHandshakeCompleted(bool succeeded); void OnReadCompleted(bool succeeded, const std::string& data); void OnWriteCompleted(bool succeeded, int32_t bytes_written); @@ -97,10 +99,17 @@ class FlashTCPSocket : public PPB_Flash_TCPSocket_API, // Before a connection is successfully established (including a connect // request is pending or a previous connect request failed). BEFORE_CONNECT, + // A connection has been successfully established (including a request of + // initiating SSL is pending). CONNECTED, + // An SSL connection has been successfully established. + SSL_CONNECTED, + // The connection has been ended. DISCONNECTED }; + bool IsConnected() const; + // Backend for both Connect() and ConnectWithNetAddress(). To keep things // generic, the message is passed in (on error, it's deleted). int32_t ConnectWithMessage(IPC::Message* msg, @@ -112,6 +121,7 @@ class FlashTCPSocket : public PPB_Flash_TCPSocket_API, ConnectionState connection_state_; PP_CompletionCallback connect_callback_; + PP_CompletionCallback ssl_handshake_callback_; PP_CompletionCallback read_callback_; PP_CompletionCallback write_callback_; @@ -129,6 +139,7 @@ FlashTCPSocket::FlashTCPSocket(const HostResource& resource, uint32 socket_id) socket_id_(socket_id), connection_state_(BEFORE_CONNECT), connect_callback_(PP_BlockUntilComplete()), + ssl_handshake_callback_(PP_BlockUntilComplete()), read_callback_(PP_BlockUntilComplete()), write_callback_(PP_BlockUntilComplete()), read_buffer_(NULL), @@ -178,7 +189,7 @@ int32_t FlashTCPSocket::ConnectWithNetAddress( } PP_Bool FlashTCPSocket::GetLocalAddress(PP_Flash_NetAddress* local_addr) { - if (connection_state_ != CONNECTED || !local_addr) + if (!IsConnected() || !local_addr) return PP_FALSE; *local_addr = local_addr_; @@ -186,17 +197,32 @@ PP_Bool FlashTCPSocket::GetLocalAddress(PP_Flash_NetAddress* local_addr) { } PP_Bool FlashTCPSocket::GetRemoteAddress(PP_Flash_NetAddress* remote_addr) { - if (connection_state_ != CONNECTED || !remote_addr) + if (!IsConnected() || !remote_addr) return PP_FALSE; *remote_addr = remote_addr_; return PP_TRUE; } -int32_t FlashTCPSocket::InitiateSSL(const char* server_name, - PP_CompletionCallback callback) { - // TODO(yzshen): add it. - return PP_ERROR_FAILED; +int32_t FlashTCPSocket::SSLHandshake(const char* server_name, + uint16_t server_port, + PP_CompletionCallback callback) { + if (!server_name || !callback.func) + return PP_ERROR_BADARGUMENT; + + if (connection_state_ != CONNECTED) + return PP_ERROR_FAILED; + if (ssl_handshake_callback_.func || read_callback_.func || + write_callback_.func) + return PP_ERROR_INPROGRESS; + + ssl_handshake_callback_ = callback; + + // Send the request, the browser will call us back via SSLHandshakeACK. + GetDispatcher()->SendToBrowser( + new PpapiHostMsg_PPBFlashTCPSocket_SSLHandshake( + socket_id_, std::string(server_name), server_port)); + return PP_OK_COMPLETIONPENDING; } int32_t FlashTCPSocket::Read(char* buffer, @@ -205,9 +231,9 @@ int32_t FlashTCPSocket::Read(char* buffer, if (!buffer || bytes_to_read <= 0 || !callback.func) return PP_ERROR_BADARGUMENT; - if (connection_state_ != CONNECTED) + if (!IsConnected()) return PP_ERROR_FAILED; - if (read_callback_.func) + if (read_callback_.func || ssl_handshake_callback_.func) return PP_ERROR_INPROGRESS; read_buffer_ = buffer; @@ -226,9 +252,9 @@ int32_t FlashTCPSocket::Write(const char* buffer, if (!buffer || bytes_to_write <= 0 || !callback.func) return PP_ERROR_BADARGUMENT; - if (connection_state_ != CONNECTED) + if (!IsConnected()) return PP_ERROR_FAILED; - if (write_callback_.func) + if (write_callback_.func || ssl_handshake_callback_.func) return PP_ERROR_INPROGRESS; if (bytes_to_write > kFlashTCPSocketMaxWriteSize) @@ -248,7 +274,7 @@ void FlashTCPSocket::Disconnect() { return; connection_state_ = DISCONNECTED; - // After removed from the mapping, this object won't receive any notfications + // After removed from the mapping, this object won't receive any notifications // from the proxy. DCHECK(g_id_to_socket->find(socket_id_) != g_id_to_socket->end()); g_id_to_socket->erase(socket_id_); @@ -258,6 +284,7 @@ void FlashTCPSocket::Disconnect() { socket_id_ = 0; PostAbortAndClearIfNecessary(&connect_callback_); + PostAbortAndClearIfNecessary(&ssl_handshake_callback_); PostAbortAndClearIfNecessary(&read_callback_); PostAbortAndClearIfNecessary(&write_callback_); read_buffer_ = NULL; @@ -282,6 +309,21 @@ void FlashTCPSocket::OnConnectCompleted( succeeded ? PP_OK : PP_ERROR_FAILED); } +void FlashTCPSocket::OnSSLHandshakeCompleted(bool succeeded) { + if (connection_state_ != CONNECTED || !ssl_handshake_callback_.func) { + NOTREACHED(); + return; + } + + if (succeeded) { + connection_state_ = SSL_CONNECTED; + PP_RunAndClearCompletionCallback(&ssl_handshake_callback_, PP_OK); + } else { + PP_RunAndClearCompletionCallback(&ssl_handshake_callback_, PP_ERROR_FAILED); + Disconnect(); + } +} + void FlashTCPSocket::OnReadCompleted(bool succeeded, const std::string& data) { if (!read_callback_.func || !read_buffer_) { NOTREACHED(); @@ -313,6 +355,10 @@ void FlashTCPSocket::OnWriteCompleted(bool succeeded, int32_t bytes_written) { succeeded ? bytes_written : static_cast<int32_t>(PP_ERROR_FAILED)); } +bool FlashTCPSocket::IsConnected() const { + return connection_state_ == CONNECTED || connection_state_ == SSL_CONNECTED; +} + int32_t FlashTCPSocket::ConnectWithMessage(IPC::Message* msg, PP_CompletionCallback callback) { scoped_ptr<IPC::Message> msg_deletor(msg); @@ -383,6 +429,8 @@ bool PPB_Flash_TCPSocket_Proxy::OnMessageReceived(const IPC::Message& msg) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(PPB_Flash_TCPSocket_Proxy, msg) IPC_MESSAGE_HANDLER(PpapiMsg_PPBFlashTCPSocket_ConnectACK, OnMsgConnectACK) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBFlashTCPSocket_SSLHandshakeACK, + OnMsgSSLHandshakeACK) IPC_MESSAGE_HANDLER(PpapiMsg_PPBFlashTCPSocket_ReadACK, OnMsgReadACK) IPC_MESSAGE_HANDLER(PpapiMsg_PPBFlashTCPSocket_WriteACK, OnMsgWriteACK) IPC_MESSAGE_UNHANDLED(handled = false) @@ -406,6 +454,20 @@ void PPB_Flash_TCPSocket_Proxy::OnMsgConnectACK( iter->second->OnConnectCompleted(succeeded, local_addr, remote_addr); } +void PPB_Flash_TCPSocket_Proxy::OnMsgSSLHandshakeACK( + uint32 /* plugin_dispatcher_id */, + uint32 socket_id, + bool succeeded) { + if (!g_id_to_socket) { + NOTREACHED(); + return; + } + IDToSocketMap::iterator iter = g_id_to_socket->find(socket_id); + if (iter == g_id_to_socket->end()) + return; + iter->second->OnSSLHandshakeCompleted(succeeded); +} + void PPB_Flash_TCPSocket_Proxy::OnMsgReadACK(uint32 /* plugin_dispatcher_id */, uint32 socket_id, bool succeeded, diff --git a/ppapi/proxy/ppb_flash_tcp_socket_proxy.h b/ppapi/proxy/ppb_flash_tcp_socket_proxy.h index aac9bbd..2f83ae7 100644 --- a/ppapi/proxy/ppb_flash_tcp_socket_proxy.h +++ b/ppapi/proxy/ppb_flash_tcp_socket_proxy.h @@ -43,6 +43,9 @@ class PPB_Flash_TCPSocket_Proxy : public InterfaceProxy { bool succeeded, const PP_Flash_NetAddress& local_addr, const PP_Flash_NetAddress& remote_addr); + void OnMsgSSLHandshakeACK(uint32 plugin_dispatcher_id, + uint32 socket_id, + bool succeeded); void OnMsgReadACK(uint32 plugin_dispatcher_id, uint32 socket_id, bool succeeded, diff --git a/ppapi/thunk/ppb_flash_tcp_socket_api.h b/ppapi/thunk/ppb_flash_tcp_socket_api.h index d18eb6e..3ded5c1 100644 --- a/ppapi/thunk/ppb_flash_tcp_socket_api.h +++ b/ppapi/thunk/ppb_flash_tcp_socket_api.h @@ -21,8 +21,9 @@ class PPB_Flash_TCPSocket_API { PP_CompletionCallback callback) = 0; virtual PP_Bool GetLocalAddress(PP_Flash_NetAddress* local_addr) = 0; virtual PP_Bool GetRemoteAddress(PP_Flash_NetAddress* remote_addr) = 0; - virtual int32_t InitiateSSL(const char* server_name, - PP_CompletionCallback callback) = 0; + virtual int32_t SSLHandshake(const char* server_name, + uint16_t server_port, + PP_CompletionCallback callback) = 0; virtual int32_t Read(char* buffer, int32_t bytes_to_read, PP_CompletionCallback callback) = 0; diff --git a/ppapi/thunk/ppb_flash_tcp_socket_thunk.cc b/ppapi/thunk/ppb_flash_tcp_socket_thunk.cc index 6154d60..a1ce67e 100644 --- a/ppapi/thunk/ppb_flash_tcp_socket_thunk.cc +++ b/ppapi/thunk/ppb_flash_tcp_socket_thunk.cc @@ -65,13 +65,15 @@ PP_Bool GetRemoteAddress(PP_Resource tcp_socket, return enter.object()->GetRemoteAddress(remote_addr); } -int32_t InitiateSSL(PP_Resource tcp_socket, - const char* server_name, - PP_CompletionCallback callback) { +int32_t SSLHandshake(PP_Resource tcp_socket, + const char* server_name, + uint16_t server_port, + PP_CompletionCallback callback) { EnterResource<PPB_Flash_TCPSocket_API> enter(tcp_socket, true); if (enter.failed()) return MayForceCallback(callback, PP_ERROR_BADRESOURCE); - int32_t result = enter.object()->InitiateSSL(server_name, callback); + int32_t result = enter.object()->SSLHandshake(server_name, server_port, + callback); return MayForceCallback(callback, result); } @@ -110,7 +112,7 @@ const PPB_Flash_TCPSocket g_ppb_flash_tcp_socket_thunk = { &ConnectWithNetAddress, &GetLocalAddress, &GetRemoteAddress, - &InitiateSSL, + &SSLHandshake, &Read, &Write, &Disconnect |