Index: ppapi/proxy/tcp_socket_resource_base.cc |
diff --git a/ppapi/proxy/tcp_socket_resource_base.cc b/ppapi/proxy/tcp_socket_resource_base.cc |
index f02895b64c05d65db987932df6e31d4dae3560c0..2590c417841fefb6dafb5f9cab1681a15208696a 100644 |
--- a/ppapi/proxy/tcp_socket_resource_base.cc |
+++ b/ppapi/proxy/tcp_socket_resource_base.cc |
@@ -32,12 +32,13 @@ const int32_t TCPSocketResourceBase::kMaxReceiveBufferSize = |
TCPSocketResourceBase::TCPSocketResourceBase(Connection connection, |
PP_Instance instance, |
- bool private_api) |
+ TCPSocketVersion version) |
: PluginResource(connection, instance), |
- connection_state_(BEFORE_CONNECT), |
+ state_(TCPSocketState::INITIAL), |
read_buffer_(NULL), |
bytes_to_read_(-1), |
- private_api_(private_api) { |
+ accepted_tcp_socket_(NULL), |
+ version_(version) { |
local_addr_.size = 0; |
memset(local_addr_.data, 0, |
arraysize(local_addr_.data) * sizeof(*local_addr_.data)); |
@@ -49,19 +50,42 @@ TCPSocketResourceBase::TCPSocketResourceBase(Connection connection, |
TCPSocketResourceBase::TCPSocketResourceBase( |
Connection connection, |
PP_Instance instance, |
- bool private_api, |
+ TCPSocketVersion version, |
const PP_NetAddress_Private& local_addr, |
const PP_NetAddress_Private& remote_addr) |
: PluginResource(connection, instance), |
- connection_state_(CONNECTED), |
+ state_(TCPSocketState::CONNECTED), |
read_buffer_(NULL), |
bytes_to_read_(-1), |
local_addr_(local_addr), |
remote_addr_(remote_addr), |
- private_api_(private_api) { |
+ accepted_tcp_socket_(NULL), |
+ version_(version) { |
} |
TCPSocketResourceBase::~TCPSocketResourceBase() { |
+ CloseImpl(); |
+} |
+ |
+int32_t TCPSocketResourceBase::BindImpl( |
+ const PP_NetAddress_Private* addr, |
+ scoped_refptr<TrackedCallback> callback) { |
+ if (!addr) |
+ return PP_ERROR_BADARGUMENT; |
+ if (state_.IsPending(TCPSocketState::BIND)) |
+ return PP_ERROR_INPROGRESS; |
+ if (!state_.IsValidTransition(TCPSocketState::BIND)) |
+ return PP_ERROR_FAILED; |
+ |
+ bind_callback_ = callback; |
+ state_.SetPendingTransition(TCPSocketState::BIND); |
+ |
+ Call<PpapiPluginMsg_TCPSocket_BindReply>( |
+ BROWSER, |
+ PpapiHostMsg_TCPSocket_Bind(*addr), |
+ base::Bind(&TCPSocketResourceBase::OnPluginMsgBindReply, |
+ base::Unretained(this))); |
+ return PP_OK_COMPLETIONPENDING; |
} |
int32_t TCPSocketResourceBase::ConnectImpl( |
@@ -70,12 +94,13 @@ int32_t TCPSocketResourceBase::ConnectImpl( |
scoped_refptr<TrackedCallback> callback) { |
if (!host) |
return PP_ERROR_BADARGUMENT; |
- if (connection_state_ != BEFORE_CONNECT) |
+ if (state_.IsPending(TCPSocketState::CONNECT)) |
+ return PP_ERROR_INPROGRESS; |
+ if (!state_.IsValidTransition(TCPSocketState::CONNECT)) |
return PP_ERROR_FAILED; |
- if (TrackedCallback::IsPending(connect_callback_)) |
- return PP_ERROR_INPROGRESS; // Can only have one pending request. |
connect_callback_ = callback; |
+ state_.SetPendingTransition(TCPSocketState::CONNECT); |
Call<PpapiPluginMsg_TCPSocket_ConnectReply>( |
BROWSER, |
@@ -90,12 +115,13 @@ int32_t TCPSocketResourceBase::ConnectWithNetAddressImpl( |
scoped_refptr<TrackedCallback> callback) { |
if (!addr) |
return PP_ERROR_BADARGUMENT; |
- if (connection_state_ != BEFORE_CONNECT) |
+ if (state_.IsPending(TCPSocketState::CONNECT)) |
+ return PP_ERROR_INPROGRESS; |
+ if (!state_.IsValidTransition(TCPSocketState::CONNECT)) |
return PP_ERROR_FAILED; |
- if (TrackedCallback::IsPending(connect_callback_)) |
- return PP_ERROR_INPROGRESS; // Can only have one pending request. |
connect_callback_ = callback; |
+ state_.SetPendingTransition(TCPSocketState::CONNECT); |
Call<PpapiPluginMsg_TCPSocket_ConnectReply>( |
BROWSER, |
@@ -107,7 +133,7 @@ int32_t TCPSocketResourceBase::ConnectWithNetAddressImpl( |
PP_Bool TCPSocketResourceBase::GetLocalAddressImpl( |
PP_NetAddress_Private* local_addr) { |
- if (!IsConnected() || !local_addr) |
+ if (!state_.IsBound() || !local_addr) |
return PP_FALSE; |
*local_addr = local_addr_; |
return PP_TRUE; |
@@ -115,7 +141,7 @@ PP_Bool TCPSocketResourceBase::GetLocalAddressImpl( |
PP_Bool TCPSocketResourceBase::GetRemoteAddressImpl( |
PP_NetAddress_Private* remote_addr) { |
- if (!IsConnected() || !remote_addr) |
+ if (!state_.IsConnected() || !remote_addr) |
return PP_FALSE; |
*remote_addr = remote_addr_; |
return PP_TRUE; |
@@ -128,15 +154,16 @@ int32_t TCPSocketResourceBase::SSLHandshakeImpl( |
if (!server_name) |
return PP_ERROR_BADARGUMENT; |
- if (connection_state_ != CONNECTED) |
- return PP_ERROR_FAILED; |
- if (TrackedCallback::IsPending(ssl_handshake_callback_) || |
+ if (state_.IsPending(TCPSocketState::SSL_CONNECT) || |
TrackedCallback::IsPending(read_callback_) || |
TrackedCallback::IsPending(write_callback_)) { |
return PP_ERROR_INPROGRESS; |
} |
+ if (!state_.IsValidTransition(TCPSocketState::SSL_CONNECT)) |
+ return PP_ERROR_FAILED; |
ssl_handshake_callback_ = callback; |
+ state_.SetPendingTransition(TCPSocketState::SSL_CONNECT); |
Call<PpapiPluginMsg_TCPSocket_SSLHandshakeReply>( |
BROWSER, |
@@ -193,10 +220,10 @@ int32_t TCPSocketResourceBase::ReadImpl( |
if (!buffer || bytes_to_read <= 0) |
return PP_ERROR_BADARGUMENT; |
- if (!IsConnected()) |
+ if (!state_.IsConnected()) |
return PP_ERROR_FAILED; |
if (TrackedCallback::IsPending(read_callback_) || |
- TrackedCallback::IsPending(ssl_handshake_callback_)) |
+ state_.IsPending(TCPSocketState::SSL_CONNECT)) |
return PP_ERROR_INPROGRESS; |
read_buffer_ = buffer; |
bytes_to_read_ = std::min(bytes_to_read, kMaxReadSize); |
@@ -217,10 +244,10 @@ int32_t TCPSocketResourceBase::WriteImpl( |
if (!buffer || bytes_to_write <= 0) |
return PP_ERROR_BADARGUMENT; |
- if (!IsConnected()) |
+ if (!state_.IsConnected()) |
return PP_ERROR_FAILED; |
if (TrackedCallback::IsPending(write_callback_) || |
- TrackedCallback::IsPending(ssl_handshake_callback_)) |
+ state_.IsPending(TCPSocketState::SSL_CONNECT)) |
return PP_ERROR_INPROGRESS; |
if (bytes_to_write > kMaxWriteSize) |
@@ -236,33 +263,79 @@ int32_t TCPSocketResourceBase::WriteImpl( |
return PP_OK_COMPLETIONPENDING; |
} |
-void TCPSocketResourceBase::DisconnectImpl() { |
- if (connection_state_ == DISCONNECTED) |
+int32_t TCPSocketResourceBase::ListenImpl( |
+ int32_t backlog, |
+ scoped_refptr<TrackedCallback> callback) { |
+ if (backlog <= 0) |
+ return PP_ERROR_BADARGUMENT; |
+ if (state_.IsPending(TCPSocketState::LISTEN)) |
+ return PP_ERROR_INPROGRESS; |
+ if (!state_.IsValidTransition(TCPSocketState::LISTEN)) |
+ return PP_ERROR_FAILED; |
+ |
+ listen_callback_ = callback; |
+ state_.SetPendingTransition(TCPSocketState::LISTEN); |
+ |
+ Call<PpapiPluginMsg_TCPSocket_ListenReply>( |
+ BROWSER, |
+ PpapiHostMsg_TCPSocket_Listen(backlog), |
+ base::Bind(&TCPSocketResourceBase::OnPluginMsgListenReply, |
+ base::Unretained(this))); |
+ return PP_OK_COMPLETIONPENDING; |
+} |
+ |
+int32_t TCPSocketResourceBase::AcceptImpl( |
+ PP_Resource* accepted_tcp_socket, |
+ scoped_refptr<TrackedCallback> callback) { |
+ if (!accepted_tcp_socket) |
+ return PP_ERROR_BADARGUMENT; |
+ if (TrackedCallback::IsPending(accept_callback_)) |
+ return PP_ERROR_INPROGRESS; |
+ if (state_.state() != TCPSocketState::LISTENING) |
+ return PP_ERROR_FAILED; |
+ |
+ accept_callback_ = callback; |
+ accepted_tcp_socket_ = accepted_tcp_socket; |
+ |
+ Call<PpapiPluginMsg_TCPSocket_AcceptReply>( |
+ BROWSER, |
+ PpapiHostMsg_TCPSocket_Accept(), |
+ base::Bind(&TCPSocketResourceBase::OnPluginMsgAcceptReply, |
+ base::Unretained(this))); |
+ return PP_OK_COMPLETIONPENDING; |
+} |
+ |
+void TCPSocketResourceBase::CloseImpl() { |
+ if (state_.state() == TCPSocketState::CLOSED) |
return; |
- connection_state_ = DISCONNECTED; |
+ state_.DoTransition(TCPSocketState::CLOSE, true); |
- Post(BROWSER, PpapiHostMsg_TCPSocket_Disconnect()); |
+ Post(BROWSER, PpapiHostMsg_TCPSocket_Close()); |
+ PostAbortIfNecessary(&bind_callback_); |
PostAbortIfNecessary(&connect_callback_); |
PostAbortIfNecessary(&ssl_handshake_callback_); |
PostAbortIfNecessary(&read_callback_); |
PostAbortIfNecessary(&write_callback_); |
+ PostAbortIfNecessary(&listen_callback_); |
+ PostAbortIfNecessary(&accept_callback_); |
read_buffer_ = NULL; |
bytes_to_read_ = -1; |
server_certificate_ = NULL; |
+ accepted_tcp_socket_ = NULL; |
} |
int32_t TCPSocketResourceBase::SetOptionImpl( |
PP_TCPSocket_Option name, |
const PP_Var& value, |
scoped_refptr<TrackedCallback> callback) { |
- if (!IsConnected()) |
- return PP_ERROR_FAILED; |
- |
SocketOptionData option_data; |
switch (name) { |
case PP_TCPSOCKET_OPTION_NO_DELAY: { |
+ if (!state_.IsConnected()) |
+ return PP_ERROR_FAILED; |
+ |
if (value.type != PP_VARTYPE_BOOL) |
return PP_ERROR_BADARGUMENT; |
option_data.SetBool(PP_ToBool(value.value.as_bool)); |
@@ -270,11 +343,25 @@ int32_t TCPSocketResourceBase::SetOptionImpl( |
} |
case PP_TCPSOCKET_OPTION_SEND_BUFFER_SIZE: |
case PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE: { |
+ if (!state_.IsConnected()) |
+ return PP_ERROR_FAILED; |
+ |
if (value.type != PP_VARTYPE_INT32) |
return PP_ERROR_BADARGUMENT; |
option_data.SetInt32(value.value.as_int); |
break; |
} |
+ case PP_TCPSOCKET_OPTION_ADDRESS_REUSE: { |
+ if (version_ != TCP_SOCKET_VERSION_1_1_OR_ABOVE) |
+ return PP_ERROR_NOTSUPPORTED; |
+ if (state_.state() != TCPSocketState::INITIAL) |
+ return PP_ERROR_FAILED; |
+ |
+ if (value.type != PP_VARTYPE_BOOL) |
+ return PP_ERROR_BADARGUMENT; |
+ option_data.SetBool(PP_ToBool(value.value.as_bool)); |
+ break; |
+ } |
default: { |
NOTREACHED(); |
return PP_ERROR_BADARGUMENT; |
@@ -291,34 +378,52 @@ int32_t TCPSocketResourceBase::SetOptionImpl( |
return PP_OK_COMPLETIONPENDING; |
} |
-bool TCPSocketResourceBase::IsConnected() const { |
- return connection_state_ == CONNECTED || connection_state_ == SSL_CONNECTED; |
-} |
- |
void TCPSocketResourceBase::PostAbortIfNecessary( |
scoped_refptr<TrackedCallback>* callback) { |
if (TrackedCallback::IsPending(*callback)) |
(*callback)->PostAbort(); |
} |
+void TCPSocketResourceBase::OnPluginMsgBindReply( |
+ const ResourceMessageReplyParams& params, |
+ const PP_NetAddress_Private& local_addr) { |
+ // It is possible that CloseImpl() has been called. We don't want to update |
+ // class members in this case. |
+ if (!state_.IsPending(TCPSocketState::BIND)) |
+ return; |
+ |
+ DCHECK(TrackedCallback::IsPending(bind_callback_)); |
+ if (params.result() == PP_OK) { |
+ local_addr_ = local_addr; |
+ state_.CompletePendingTransition(true); |
+ } else { |
+ state_.CompletePendingTransition(false); |
+ } |
+ RunCallback(bind_callback_, params.result()); |
+} |
+ |
void TCPSocketResourceBase::OnPluginMsgConnectReply( |
const ResourceMessageReplyParams& params, |
const PP_NetAddress_Private& local_addr, |
const PP_NetAddress_Private& remote_addr) { |
- // It is possible that |connect_callback_| is pending while |
- // |connection_state_| is not BEFORE_CONNECT: DisconnectImpl() has been |
- // called, but a ConnectCompleted notification came earlier than the task to |
- // abort |connect_callback_|. We don't want to update |connection_state_| or |
- // other members in that case. |
- if (connection_state_ != BEFORE_CONNECT || |
- !TrackedCallback::IsPending(connect_callback_)) { |
+ // It is possible that CloseImpl() has been called. We don't want to update |
+ // class members in this case. |
+ if (!state_.IsPending(TCPSocketState::CONNECT)) |
return; |
- } |
+ DCHECK(TrackedCallback::IsPending(connect_callback_)); |
if (params.result() == PP_OK) { |
local_addr_ = local_addr; |
remote_addr_ = remote_addr; |
- connection_state_ = CONNECTED; |
+ state_.CompletePendingTransition(true); |
+ } else { |
+ if (version_ == TCP_SOCKET_VERSION_1_1_OR_ABOVE) { |
+ state_.CompletePendingTransition(false); |
+ } else { |
+ // In order to maintain backward compatibility, allow to connect the |
+ // socket again. |
+ state_ = TCPSocketState(TCPSocketState::INITIAL); |
+ } |
} |
RunCallback(connect_callback_, params.result()); |
} |
@@ -326,42 +431,33 @@ void TCPSocketResourceBase::OnPluginMsgConnectReply( |
void TCPSocketResourceBase::OnPluginMsgSSLHandshakeReply( |
const ResourceMessageReplyParams& params, |
const PPB_X509Certificate_Fields& certificate_fields) { |
- // It is possible that |ssl_handshake_callback_| is pending while |
- // |connection_state_| is not CONNECT: DisconnectImpl() has been |
- // called, but a SSLHandshakeCompleted notification came earlier than the task |
- // to abort |ssl_handshake_callback_|. We don't want to update |
- // |connection_state_| or other members in that case. |
- if (connection_state_ != CONNECTED || |
- !TrackedCallback::IsPending(ssl_handshake_callback_)) { |
+ // It is possible that CloseImpl() has been called. We don't want to |
+ // update class members in this case. |
+ if (!state_.IsPending(TCPSocketState::SSL_CONNECT)) |
return; |
- } |
+ DCHECK(TrackedCallback::IsPending(ssl_handshake_callback_)); |
if (params.result() == PP_OK) { |
- connection_state_ = SSL_CONNECTED; |
+ state_.CompletePendingTransition(true); |
server_certificate_ = new PPB_X509Certificate_Private_Shared( |
OBJECT_IS_PROXY, |
pp_instance(), |
certificate_fields); |
- RunCallback(ssl_handshake_callback_, params.result()); |
} else { |
- // The resource might be released in the callback so we need to hold |
- // a reference so we can Disconnect() first. |
- AddRef(); |
- RunCallback(ssl_handshake_callback_, params.result()); |
- DisconnectImpl(); |
- Release(); |
+ state_.CompletePendingTransition(false); |
} |
+ RunCallback(ssl_handshake_callback_, params.result()); |
} |
void TCPSocketResourceBase::OnPluginMsgReadReply( |
const ResourceMessageReplyParams& params, |
const std::string& data) { |
- // It is possible that |read_callback_| is pending while |read_buffer_| is |
- // NULL: DisconnectImpl() has been called, but a ReadCompleted notification |
- // came earlier than the task to abort |read_callback_|. We shouldn't access |
- // the buffer in that case. The user may have released it. |
- if (!TrackedCallback::IsPending(read_callback_) || !read_buffer_) |
+ // It is possible that CloseImpl() has been called. We shouldn't access the |
+ // buffer in that case. The user may have released it. |
+ if (!state_.IsConnected() || !TrackedCallback::IsPending(read_callback_) || |
+ !read_buffer_) { |
return; |
+ } |
const bool succeeded = params.result() == PP_OK; |
if (succeeded) { |
@@ -372,19 +468,48 @@ void TCPSocketResourceBase::OnPluginMsgReadReply( |
read_buffer_ = NULL; |
bytes_to_read_ = -1; |
- read_callback_->Run(succeeded ? |
- static_cast<int32_t>(data.size()) : |
- ConvertNetworkAPIErrorForCompatibility(params.result(), |
- private_api_)); |
+ RunCallback(read_callback_, |
+ succeeded ? static_cast<int32_t>(data.size()) : params.result()); |
} |
void TCPSocketResourceBase::OnPluginMsgWriteReply( |
const ResourceMessageReplyParams& params) { |
- if (!TrackedCallback::IsPending(write_callback_)) |
+ if (!state_.IsConnected() || !TrackedCallback::IsPending(write_callback_)) |
return; |
RunCallback(write_callback_, params.result()); |
} |
+void TCPSocketResourceBase::OnPluginMsgListenReply( |
+ const ResourceMessageReplyParams& params) { |
+ if (!state_.IsPending(TCPSocketState::LISTEN)) |
+ return; |
+ |
+ DCHECK(TrackedCallback::IsPending(listen_callback_)); |
+ state_.CompletePendingTransition(params.result() == PP_OK); |
+ |
+ RunCallback(listen_callback_, params.result()); |
+} |
+ |
+void TCPSocketResourceBase::OnPluginMsgAcceptReply( |
+ const ResourceMessageReplyParams& params, |
+ int pending_host_id, |
+ const PP_NetAddress_Private& local_addr, |
+ const PP_NetAddress_Private& remote_addr) { |
+ // It is possible that CloseImpl() has been called. We shouldn't access the |
+ // output parameter in that case. The user may have released it. |
+ if (state_.state() != TCPSocketState::LISTENING || |
+ !TrackedCallback::IsPending(accept_callback_) || !accepted_tcp_socket_) { |
+ return; |
+ } |
+ |
+ if (params.result() == PP_OK) { |
+ *accepted_tcp_socket_ = CreateAcceptedSocket(pending_host_id, local_addr, |
+ remote_addr); |
+ } |
+ accepted_tcp_socket_ = NULL; |
+ RunCallback(accept_callback_, params.result()); |
+} |
+ |
void TCPSocketResourceBase::OnPluginMsgSetOptionReply( |
const ResourceMessageReplyParams& params) { |
if (set_option_callbacks_.empty()) { |
@@ -399,8 +524,8 @@ void TCPSocketResourceBase::OnPluginMsgSetOptionReply( |
void TCPSocketResourceBase::RunCallback(scoped_refptr<TrackedCallback> callback, |
int32_t pp_result) { |
- callback->Run(ConvertNetworkAPIErrorForCompatibility(pp_result, |
- private_api_)); |
+ callback->Run(ConvertNetworkAPIErrorForCompatibility( |
+ pp_result, version_ == TCP_SOCKET_VERSION_PRIVATE)); |
} |
} // namespace ppapi |