Chromium Code Reviews| 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..b4b41d109c3f803a792635c8ef5a6ac211ceaca0 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,33 +50,56 @@ 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() { |
| } |
| +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( |
| const char* host, |
| uint16_t port, |
| scoped_refptr<TrackedCallback> callback) { |
| if (!host) |
| return PP_ERROR_BADARGUMENT; |
| - if (connection_state_ != BEFORE_CONNECT) |
| - return PP_ERROR_FAILED; |
| - if (TrackedCallback::IsPending(connect_callback_)) |
| + if (state_.IsPending(TCPSocketState::CONNECT)) |
| return PP_ERROR_INPROGRESS; // Can only have one pending request. |
|
bbudge
2013/09/19 19:41:47
Comment seems superfluous. Here and below.
yzshen1
2013/09/19 21:12:15
Done.
|
| + if (!state_.IsValidTransition(TCPSocketState::CONNECT)) |
| + return PP_ERROR_FAILED; |
| connect_callback_ = callback; |
| + state_.SetPendingTransition(TCPSocketState::CONNECT); |
| Call<PpapiPluginMsg_TCPSocket_ConnectReply>( |
| BROWSER, |
| @@ -90,12 +114,13 @@ int32_t TCPSocketResourceBase::ConnectWithNetAddressImpl( |
| scoped_refptr<TrackedCallback> callback) { |
| if (!addr) |
| return PP_ERROR_BADARGUMENT; |
| - if (connection_state_ != BEFORE_CONNECT) |
| - return PP_ERROR_FAILED; |
| - if (TrackedCallback::IsPending(connect_callback_)) |
| + if (state_.IsPending(TCPSocketState::CONNECT)) |
| return PP_ERROR_INPROGRESS; // Can only have one pending request. |
| + if (!state_.IsValidTransition(TCPSocketState::CONNECT)) |
| + return PP_ERROR_FAILED; |
| connect_callback_ = callback; |
| + state_.SetPendingTransition(TCPSocketState::CONNECT); |
| Call<PpapiPluginMsg_TCPSocket_ConnectReply>( |
| BROWSER, |
| @@ -107,7 +132,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 +140,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 +153,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 +219,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 +243,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 +262,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()) |
|
bbudge
2013/09/19 19:41:47
Since you have to do all of this checking again on
yzshen1
2013/09/19 21:12:15
It seems nice to fail early. I think this is consi
bbudge
2013/09/19 22:30:57
OK
|
| + 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 +342,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 +377,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 +430,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 +467,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 +523,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 |