| 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.
|
| + 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())
|
| + 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
|
|
|