Chromium Code Reviews| Index: content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc |
| diff --git a/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..403de2208ad09f1392311ded327ef51e51759577 |
| --- /dev/null |
| +++ b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc |
| @@ -0,0 +1,612 @@ |
| +// Copyright 2013 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 "content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h" |
| + |
| +#include "base/bind.h" |
| +#include "base/logging.h" |
| +#include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h" |
| +#include "content/browser/renderer_host/pepper/pepper_socket_utils.h" |
| +#include "content/public/browser/browser_context.h" |
| +#include "content/public/browser/browser_thread.h" |
| +#include "content/public/browser/render_process_host.h" |
| +#include "content/public/browser/resource_context.h" |
| +#include "content/public/common/socket_permission_request.h" |
| +#include "net/base/host_port_pair.h" |
| +#include "net/base/io_buffer.h" |
| +#include "net/base/net_errors.h" |
| +#include "net/dns/single_request_host_resolver.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 "ppapi/c/private/ppb_net_address_private.h" |
| +#include "ppapi/host/dispatch_host_message.h" |
| +#include "ppapi/host/error_conversion.h" |
| +#include "ppapi/proxy/ppapi_messages.h" |
| +#include "ppapi/proxy/tcp_socket_resource_base.h" |
| +#include "ppapi/shared_impl/private/net_address_private_impl.h" |
| + |
| +using ppapi::NetAddressPrivateImpl; |
| +using ppapi::host::NetErrorToPepperError; |
| +using ppapi::proxy::TCPSocketResourceBase; |
| + |
| +namespace { |
| + |
| +size_t g_num_instances = 0; |
| + |
| +} // namespace |
| + |
| +namespace content { |
| + |
| +PepperTCPSocketMessageFilter::PepperTCPSocketMessageFilter( |
| + BrowserPpapiHostImpl* host, |
| + PP_Instance instance, |
| + bool private_api, |
| + const scoped_refptr<SSLContextHelper>& ssl_context_helper) |
| + : external_plugin_(host->external_plugin()), |
| + private_api_(private_api), |
| + render_process_id_(0), |
| + render_view_id_(0), |
| + connection_state_(BEFORE_CONNECT), |
| + end_of_file_reached_(false), |
| + ssl_context_helper_(ssl_context_helper) { |
| + ++g_num_instances; |
| + DCHECK(host); |
| + if (!host->GetRenderViewIDsForInstance(instance, |
| + &render_process_id_, |
| + &render_view_id_)) { |
| + NOTREACHED(); |
| + } |
| +} |
| + |
| +PepperTCPSocketMessageFilter::PepperTCPSocketMessageFilter( |
| + BrowserPpapiHostImpl* host, |
| + PP_Instance instance, |
| + bool private_api, |
| + const scoped_refptr<SSLContextHelper>& ssl_context_helper, |
| + net::StreamSocket* socket) |
| + : external_plugin_(host->external_plugin()), |
| + private_api_(private_api), |
| + render_process_id_(0), |
| + render_view_id_(0), |
| + connection_state_(CONNECTED), |
| + end_of_file_reached_(false), |
| + socket_(socket), |
| + ssl_context_helper_(ssl_context_helper) { |
| + ++g_num_instances; |
| + DCHECK(host); |
| + if (!host->GetRenderViewIDsForInstance(instance, |
| + &render_process_id_, |
| + &render_view_id_)) { |
| + NOTREACHED(); |
| + } |
| +} |
| + |
| +PepperTCPSocketMessageFilter::~PepperTCPSocketMessageFilter() { |
| + if (socket_) |
| + socket_->Disconnect(); |
| + --g_num_instances; |
| +} |
| + |
| +// static |
| +size_t PepperTCPSocketMessageFilter::GetNumInstances() { |
| + return g_num_instances; |
| +} |
| + |
| +scoped_refptr<base::TaskRunner> |
| +PepperTCPSocketMessageFilter::OverrideTaskRunnerForMessage( |
| + const IPC::Message& message) { |
| + switch (message.type()) { |
| + case PpapiHostMsg_TCPSocket_Connect::ID: |
| + case PpapiHostMsg_TCPSocket_ConnectWithNetAddress::ID: |
| + return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI); |
| + case PpapiHostMsg_TCPSocket_SSLHandshake::ID: |
| + case PpapiHostMsg_TCPSocket_Read::ID: |
| + case PpapiHostMsg_TCPSocket_Write::ID: |
| + case PpapiHostMsg_TCPSocket_Disconnect::ID: |
| + case PpapiHostMsg_TCPSocket_SetOption::ID: |
| + return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO); |
| + } |
| + return NULL; |
| +} |
| + |
| +int32_t PepperTCPSocketMessageFilter::OnResourceMessageReceived( |
| + const IPC::Message& msg, |
| + ppapi::host::HostMessageContext* context) { |
| + IPC_BEGIN_MESSAGE_MAP(PepperTCPSocketMessageFilter, msg) |
| + PPAPI_DISPATCH_HOST_RESOURCE_CALL( |
| + PpapiHostMsg_TCPSocket_Connect, OnMsgConnect) |
| + PPAPI_DISPATCH_HOST_RESOURCE_CALL( |
| + PpapiHostMsg_TCPSocket_ConnectWithNetAddress, |
| + OnMsgConnectWithNetAddress) |
| + PPAPI_DISPATCH_HOST_RESOURCE_CALL( |
| + PpapiHostMsg_TCPSocket_SSLHandshake, OnMsgSSLHandshake) |
| + PPAPI_DISPATCH_HOST_RESOURCE_CALL( |
| + PpapiHostMsg_TCPSocket_Read, OnMsgRead) |
| + PPAPI_DISPATCH_HOST_RESOURCE_CALL( |
| + PpapiHostMsg_TCPSocket_Write, OnMsgWrite) |
| + PPAPI_DISPATCH_HOST_RESOURCE_CALL_0( |
| + PpapiHostMsg_TCPSocket_Disconnect, OnMsgDisconnect) |
| + PPAPI_DISPATCH_HOST_RESOURCE_CALL( |
| + PpapiHostMsg_TCPSocket_SetOption, OnMsgSetOption) |
| + IPC_END_MESSAGE_MAP() |
| + return PP_ERROR_FAILED; |
| +} |
| + |
| +int32_t PepperTCPSocketMessageFilter::OnMsgConnect( |
| + const ppapi::host::HostMessageContext* context, |
| + const std::string& host, |
| + uint16_t port) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + |
| + // This is only supported by PPB_TCPSocket_Private. |
| + if (!private_api_) { |
| + NOTREACHED(); |
| + return PP_ERROR_FAILED; |
|
yzshen1
2013/08/16 20:40:42
PP_ERROR_NOACCESS.
ygorshenin1
2013/08/19 14:33:35
Done.
|
| + } |
| + |
| + SocketPermissionRequest request(SocketPermissionRequest::TCP_CONNECT, |
| + host, |
| + port); |
| + if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_, private_api_, |
| + request, render_process_id_, |
| + render_view_id_)) { |
| + return PP_ERROR_NOACCESS; |
| + } |
| + |
| + RenderProcessHost* render_process_host = |
| + RenderProcessHost::FromID(render_process_id_); |
| + if (!render_process_host) |
| + return PP_ERROR_FAILED; |
| + BrowserContext* browser_context = render_process_host->GetBrowserContext(); |
| + if (!browser_context || !browser_context->GetResourceContext()) |
| + return PP_ERROR_FAILED; |
| + |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, FROM_HERE, |
| + base::Bind(&PepperTCPSocketMessageFilter::DoConnect, this, |
| + context->MakeReplyMessageContext(), |
| + host, port, browser_context->GetResourceContext())); |
| + return PP_OK_COMPLETIONPENDING; |
| +} |
| + |
| +int32_t PepperTCPSocketMessageFilter::OnMsgConnectWithNetAddress( |
| + const ppapi::host::HostMessageContext* context, |
| + const PP_NetAddress_Private& net_addr) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + |
| + content::SocketPermissionRequest request = |
| + pepper_socket_utils::CreateSocketPermissionRequest( |
| + content::SocketPermissionRequest::TCP_CONNECT, net_addr); |
| + if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_, private_api_, |
| + request, render_process_id_, |
| + render_view_id_)) { |
| + return PP_ERROR_NOACCESS; |
| + } |
| + |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, FROM_HERE, |
| + base::Bind(&PepperTCPSocketMessageFilter::DoConnectWithNetAddress, this, |
| + context->MakeReplyMessageContext(), net_addr)); |
| + return PP_OK_COMPLETIONPENDING; |
| +} |
| + |
| +int32_t PepperTCPSocketMessageFilter::OnMsgSSLHandshake( |
| + const ppapi::host::HostMessageContext* context, |
| + const std::string& server_name, |
| + uint16_t server_port, |
| + const std::vector<std::vector<char> >& trusted_certs, |
| + const std::vector<std::vector<char> >& untrusted_certs) { |
| + if (connection_state_ != CONNECTED || read_buffer_.get() || |
|
yzshen1
2013/08/16 20:40:42
Please keep the comments from PepperTCPSocket.
ygorshenin1
2013/08/19 14:33:35
Done.
|
| + write_buffer_base_.get() || write_buffer_.get()) { |
| + return PP_ERROR_FAILED; |
| + } |
| + |
| + const ppapi::host::ReplyMessageContext reply_context( |
|
yzshen1
2013/08/16 20:40:42
Please move this to be above line 230.
ygorshenin1
2013/08/19 14:33:35
Done.
|
| + context->MakeReplyMessageContext()); |
| + |
| + connection_state_ = SSL_HANDSHAKE_IN_PROGRESS; |
| + // TODO(raymes,rsleevi): Use trusted/untrusted certificates when connecting. |
| + |
| + scoped_ptr<net::ClientSocketHandle> handle(new net::ClientSocketHandle()); |
| + handle->SetSocket(socket_.Pass()); |
| + net::ClientSocketFactory* factory = |
| + net::ClientSocketFactory::GetDefaultFactory(); |
| + net::HostPortPair host_port_pair(server_name, server_port); |
| + net::SSLClientSocketContext ssl_context; |
| + ssl_context.cert_verifier = ssl_context_helper_->GetCertVerifier(); |
| + ssl_context.transport_security_state = |
| + ssl_context_helper_->GetTransportSecurityState(); |
| + socket_ = factory->CreateSSLClientSocket( |
| + handle.Pass(), host_port_pair, ssl_context_helper_->ssl_config(), |
| + ssl_context); |
| + if (!socket_) { |
| + LOG(WARNING) << "Failed to create an SSL client socket."; |
| + return PP_ERROR_FAILED; |
| + } |
| + |
| + int net_result = socket_->Connect( |
| + base::Bind(&PepperTCPSocketMessageFilter::OnSSLHandshakeCompleted, |
| + base::Unretained(this), reply_context)); |
| + if (net_result != net::ERR_IO_PENDING) |
| + OnSSLHandshakeCompleted(reply_context, net_result); |
| + return PP_OK_COMPLETIONPENDING; |
| +} |
| + |
| +int32_t PepperTCPSocketMessageFilter::OnMsgRead( |
| + const ppapi::host::HostMessageContext* context, |
| + int32_t bytes_to_read) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + if (!IsConnected() || end_of_file_reached_) |
| + return PP_ERROR_FAILED; |
| + if (read_buffer_.get()) |
| + return PP_ERROR_INPROGRESS; |
| + if (bytes_to_read <= 0 || |
| + bytes_to_read > TCPSocketResourceBase::kMaxReadSize) { |
| + return PP_ERROR_BADARGUMENT; |
| + } |
| + |
| + ppapi::host::ReplyMessageContext reply_context( |
| + context->MakeReplyMessageContext()); |
| + read_buffer_ = new net::IOBuffer(bytes_to_read); |
| + int net_result = socket_->Read( |
| + read_buffer_.get(), |
| + bytes_to_read, |
| + base::Bind(&PepperTCPSocketMessageFilter::OnReadCompleted, |
| + base::Unretained(this), reply_context)); |
| + if (net_result != net::ERR_IO_PENDING) |
| + OnReadCompleted(reply_context, net_result); |
| + return PP_OK_COMPLETIONPENDING; |
| +} |
| + |
| +int32_t PepperTCPSocketMessageFilter::OnMsgWrite( |
| + const ppapi::host::HostMessageContext* context, |
| + const std::string& data) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + if (!IsConnected()) |
| + return PP_ERROR_FAILED; |
| + if (write_buffer_base_.get() || write_buffer_.get()) |
| + return PP_ERROR_INPROGRESS; |
| + |
| + size_t data_size = data.size(); |
| + if (data_size == 0 || |
| + data_size > static_cast<size_t>(TCPSocketResourceBase::kMaxWriteSize)) { |
| + return PP_ERROR_BADARGUMENT; |
| + } |
| + |
| + write_buffer_base_ = new net::IOBuffer(data_size); |
| + memcpy(write_buffer_base_->data(), data.data(), data_size); |
| + write_buffer_ = |
| + new net::DrainableIOBuffer(write_buffer_base_.get(), data_size); |
| + DoWrite(context->MakeReplyMessageContext()); |
| + return PP_OK_COMPLETIONPENDING; |
| +} |
| + |
| +int32_t PepperTCPSocketMessageFilter::OnMsgDisconnect( |
| + const ppapi::host::HostMessageContext* context) { |
| + // Make sure no further callbacks from socket_. |
|
yzshen1
2013/08/16 20:40:42
In the previous code, when we get a disconnect req
ygorshenin1
2013/08/19 14:33:35
Done.
|
| + if (socket_) |
| + socket_->Disconnect(); |
| + return PP_OK; |
| +} |
| + |
| +int32_t PepperTCPSocketMessageFilter::OnMsgSetOption( |
| + const ppapi::host::HostMessageContext* context, |
| + PP_TCPSocket_Option name, |
| + const ppapi::SocketOptionData& value) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + |
| + if (!IsConnected() || IsSsl()) |
| + return PP_ERROR_FAILED; |
| + |
| + net::TCPClientSocket* tcp_socket = |
| + static_cast<net::TCPClientSocket*>(socket_.get()); |
| + DCHECK(tcp_socket); |
| + |
| + switch (name) { |
| + case PP_TCPSOCKET_OPTION_NO_DELAY: { |
| + bool boolean_value = false; |
| + if (!value.GetBool(&boolean_value)) |
| + return PP_ERROR_BADARGUMENT; |
| + return tcp_socket->SetNoDelay(boolean_value) ? PP_OK : PP_ERROR_FAILED; |
| + } |
| + case PP_TCPSOCKET_OPTION_SEND_BUFFER_SIZE: |
| + case PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE: { |
| + int32_t integer_value = 0; |
| + if (!value.GetInt32(&integer_value) || integer_value <= 0) |
| + return PP_ERROR_BADARGUMENT; |
| + |
| + bool result = false; |
| + if (name == PP_TCPSOCKET_OPTION_SEND_BUFFER_SIZE) { |
| + if (integer_value > TCPSocketResourceBase::kMaxSendBufferSize) |
| + return PP_ERROR_BADARGUMENT; |
| + result = tcp_socket->SetSendBufferSize(integer_value); |
| + } else { |
| + if (integer_value > TCPSocketResourceBase::kMaxReceiveBufferSize) |
| + return PP_ERROR_BADARGUMENT; |
| + result = tcp_socket->SetReceiveBufferSize(integer_value); |
| + } |
| + return result ? PP_OK : PP_ERROR_FAILED; |
| + } |
| + default: { |
| + NOTREACHED(); |
| + return PP_ERROR_BADARGUMENT; |
| + } |
| + } |
| + return PP_ERROR_FAILED; |
| +} |
| + |
| +void PepperTCPSocketMessageFilter::DoConnect( |
| + const ppapi::host::ReplyMessageContext& context, |
| + const std::string& host, |
| + uint16_t port, |
| + ResourceContext* resource_context) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + |
| + if (connection_state_ != BEFORE_CONNECT) { |
| + SendConnectError(context, PP_ERROR_FAILED); |
| + return; |
| + } |
| + |
| + connection_state_ = CONNECT_IN_PROGRESS; |
| + net::HostResolver::RequestInfo request_info(net::HostPortPair(host, port)); |
| + resolver_.reset(new net::SingleRequestHostResolver( |
| + resource_context->GetHostResolver())); |
| + int net_result = resolver_->Resolve( |
| + request_info, &address_list_, |
| + base::Bind(&PepperTCPSocketMessageFilter::OnResolveCompleted, |
| + base::Unretained(this), context), |
| + net::BoundNetLog()); |
| + if (net_result != net::ERR_IO_PENDING) |
| + OnResolveCompleted(context, net_result); |
| +} |
| + |
| +void PepperTCPSocketMessageFilter::DoConnectWithNetAddress( |
| + const ppapi::host::ReplyMessageContext& context, |
| + const PP_NetAddress_Private& net_addr) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + if (connection_state_ != BEFORE_CONNECT) { |
| + SendConnectError(context, PP_ERROR_FAILED); |
| + return; |
| + } |
| + |
| + net::IPAddressNumber address; |
| + int port; |
| + if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(net_addr, &address, |
| + &port)) { |
| + SendConnectError(context, PP_ERROR_ADDRESS_INVALID); |
| + return; |
| + } |
| + |
| + // Copy the single IPEndPoint to address_list_. |
| + address_list_.clear(); |
| + address_list_.push_back(net::IPEndPoint(address, port)); |
| + connection_state_ = CONNECT_IN_PROGRESS; |
| + StartConnect(context); |
| +} |
| + |
| +void PepperTCPSocketMessageFilter::DoWrite( |
| + const ppapi::host::ReplyMessageContext& context) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + DCHECK(write_buffer_base_.get()); |
| + DCHECK(write_buffer_.get()); |
| + DCHECK_GT(write_buffer_->BytesRemaining(), 0); |
| + |
| + int net_result = socket_->Write( |
| + write_buffer_.get(), |
| + write_buffer_->BytesRemaining(), |
| + base::Bind(&PepperTCPSocketMessageFilter::OnWriteCompleted, |
| + base::Unretained(this), context)); |
| + if (net_result != net::ERR_IO_PENDING) |
| + OnWriteCompleted(context, net_result); |
| +} |
| + |
| +void PepperTCPSocketMessageFilter::OnResolveCompleted( |
| + const ppapi::host::ReplyMessageContext& context, |
| + int net_result) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + DCHECK_EQ(CONNECT_IN_PROGRESS, connection_state_); |
| + |
| + if (net_result != net::OK) { |
| + SendConnectError(context, NetErrorToPepperError(net_result)); |
| + connection_state_ = BEFORE_CONNECT; |
| + return; |
| + } |
| + StartConnect(context); |
| +} |
| + |
| +void PepperTCPSocketMessageFilter::StartConnect( |
| + const ppapi::host::ReplyMessageContext& context) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + DCHECK_EQ(CONNECT_IN_PROGRESS, connection_state_); |
| + |
| + socket_.reset(new net::TCPClientSocket(address_list_, NULL, |
| + net::NetLog::Source())); |
| + int net_result = socket_->Connect( |
| + base::Bind(&PepperTCPSocketMessageFilter::OnConnectCompleted, |
| + base::Unretained(this), context)); |
| + if (net_result != net::ERR_IO_PENDING) |
| + OnConnectCompleted(context, net_result); |
| +} |
| + |
| +void PepperTCPSocketMessageFilter::OnConnectCompleted( |
| + const ppapi::host::ReplyMessageContext& context, |
| + int net_result) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + DCHECK_EQ(CONNECT_IN_PROGRESS, connection_state_); |
| + DCHECK(socket_.get()); |
| + |
| + int32_t pp_result = NetErrorToPepperError(net_result); |
| + do { |
| + if (pp_result != PP_OK) |
| + break; |
| + |
| + net::IPEndPoint ip_end_point_local; |
| + net::IPEndPoint ip_end_point_remote; |
| + pp_result = NetErrorToPepperError( |
| + socket_->GetLocalAddress(&ip_end_point_local)); |
| + if (pp_result != PP_OK) |
| + break; |
| + pp_result = NetErrorToPepperError( |
| + socket_->GetPeerAddress(&ip_end_point_remote)); |
| + if (pp_result != PP_OK) |
| + break; |
| + |
| + PP_NetAddress_Private local_addr = |
| + NetAddressPrivateImpl::kInvalidNetAddress; |
| + PP_NetAddress_Private remote_addr = |
| + NetAddressPrivateImpl::kInvalidNetAddress; |
| + if (!NetAddressPrivateImpl::IPEndPointToNetAddress( |
| + ip_end_point_local.address(), |
| + ip_end_point_local.port(), |
| + &local_addr) || |
| + !NetAddressPrivateImpl::IPEndPointToNetAddress( |
| + ip_end_point_remote.address(), |
| + ip_end_point_remote.port(), |
| + &remote_addr)) { |
| + pp_result = PP_ERROR_ADDRESS_INVALID; |
| + break; |
| + } |
| + |
| + SendConnectReply(context, PP_OK, local_addr, remote_addr); |
| + connection_state_ = CONNECTED; |
| + return; |
| + } while (false); |
| + |
| + SendConnectError(context, pp_result); |
| + connection_state_ = BEFORE_CONNECT; |
| +} |
| + |
| +void PepperTCPSocketMessageFilter::OnSSLHandshakeCompleted( |
| + const ppapi::host::ReplyMessageContext& context, |
| + int net_result) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + DCHECK_EQ(SSL_HANDSHAKE_IN_PROGRESS, SSL_HANDSHAKE_IN_PROGRESS); |
| + SendSSLHandshakeReply(context, NetErrorToPepperError(net_result)); |
| + connection_state_ = (net_result == net::OK ? |
| + SSL_CONNECTED : |
| + SSL_HANDSHAKE_FAILED); |
| +} |
| + |
| +void PepperTCPSocketMessageFilter::OnReadCompleted( |
| + const ppapi::host::ReplyMessageContext& context, |
| + int net_result) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + DCHECK(read_buffer_.get()); |
| + |
| + if (net_result > 0) { |
| + SendReadReply(context, |
| + PP_OK, |
| + std::string(read_buffer_->data(), net_result)); |
| + } else if (net_result == 0) { |
| + end_of_file_reached_ = true; |
| + SendReadReply(context, PP_OK, std::string()); |
| + } else { |
| + SendReadError(context, NetErrorToPepperError(net_result)); |
| + } |
| + read_buffer_ = NULL; |
| +} |
| + |
| +void PepperTCPSocketMessageFilter::OnWriteCompleted( |
| + const ppapi::host::ReplyMessageContext& context, |
| + int net_result) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + DCHECK(write_buffer_base_.get()); |
| + DCHECK(write_buffer_.get()); |
| + |
| + // Note: For partial writes of 0 bytes, don't continue writing to avoid a |
| + // likely infinite loop. |
| + if (net_result > 0) { |
| + write_buffer_->DidConsume(net_result); |
| + if (write_buffer_->BytesRemaining() > 0) { |
| + DoWrite(context); |
| + return; |
| + } |
| + } |
| + |
| + if (net_result >= 0) |
| + SendWriteReply(context, write_buffer_->BytesConsumed()); |
| + else |
| + SendWriteReply(context, NetErrorToPepperError(net_result)); |
| + |
| + write_buffer_ = NULL; |
| + write_buffer_base_ = NULL; |
| +} |
| + |
| +void PepperTCPSocketMessageFilter::SendConnectReply( |
| + const ppapi::host::ReplyMessageContext& context, |
| + int32_t pp_result, |
| + const PP_NetAddress_Private& local_addr, |
| + const PP_NetAddress_Private& remote_addr) { |
| + ppapi::host::ReplyMessageContext reply_context(context); |
| + reply_context.params.set_result(pp_result); |
| + SendReply(reply_context, |
| + PpapiPluginMsg_TCPSocket_ConnectReply(local_addr, remote_addr)); |
| +} |
| + |
| +void PepperTCPSocketMessageFilter::SendConnectError( |
| + const ppapi::host::ReplyMessageContext& context, |
| + int32_t pp_error) { |
| + SendConnectReply(context, |
| + pp_error, |
| + NetAddressPrivateImpl::kInvalidNetAddress, |
| + NetAddressPrivateImpl::kInvalidNetAddress); |
| +} |
| + |
| +void PepperTCPSocketMessageFilter::SendSSLHandshakeReply( |
| + const ppapi::host::ReplyMessageContext& context, |
| + int32_t pp_result) { |
| + ppapi::host::ReplyMessageContext reply_context(context); |
| + reply_context.params.set_result(pp_result); |
| + ppapi::PPB_X509Certificate_Fields certificate_fields; |
| + if (pp_result == PP_OK) { |
| + // Our socket is guaranteed to be an SSL socket if we get here. |
| + net::SSLClientSocket* ssl_socket = |
| + static_cast<net::SSLClientSocket*>(socket_.get()); |
| + net::SSLInfo ssl_info; |
| + ssl_socket->GetSSLInfo(&ssl_info); |
| + if (ssl_info.cert.get()) { |
| + pepper_socket_utils::GetCertificateFields(*ssl_info.cert.get(), |
| + &certificate_fields); |
| + } |
| + } |
| + SendReply(reply_context, |
| + PpapiPluginMsg_TCPSocket_SSLHandshakeReply(certificate_fields)); |
| +} |
| + |
| +void PepperTCPSocketMessageFilter::SendReadReply( |
| + const ppapi::host::ReplyMessageContext& context, |
| + int32_t pp_result, |
| + const std::string& data) { |
| + ppapi::host::ReplyMessageContext reply_context(context); |
| + reply_context.params.set_result(pp_result); |
| + SendReply(reply_context, PpapiPluginMsg_TCPSocket_ReadReply(data)); |
| +} |
| + |
| +void PepperTCPSocketMessageFilter::SendReadError( |
| + const ppapi::host::ReplyMessageContext& context, |
| + int32_t pp_error) { |
| + SendReadReply(context, pp_error, std::string()); |
| +} |
| + |
| +void PepperTCPSocketMessageFilter::SendWriteReply( |
| + const ppapi::host::ReplyMessageContext& context, |
| + int32_t pp_result) { |
| + ppapi::host::ReplyMessageContext reply_context(context); |
| + reply_context.params.set_result(pp_result); |
| + SendReply(reply_context, PpapiPluginMsg_TCPSocket_WriteReply()); |
| +} |
| + |
| +bool PepperTCPSocketMessageFilter::IsConnected() const { |
| + return connection_state_ == CONNECTED || connection_state_ == SSL_CONNECTED; |
| +} |
| + |
| +bool PepperTCPSocketMessageFilter::IsSsl() const { |
| + return connection_state_ == SSL_HANDSHAKE_IN_PROGRESS || |
| + connection_state_ == SSL_CONNECTED || |
| + connection_state_ == SSL_HANDSHAKE_FAILED; |
| +} |
| + |
| +} // namespace content |