Index: extensions/browser/api/cast_channel/cast_socket.cc |
diff --git a/extensions/browser/api/cast_channel/cast_socket.cc b/extensions/browser/api/cast_channel/cast_socket.cc |
index f446bff88d53957c8a4bad5af185a03b251dea62..0872a2e45780abaad3f5042d4d18e3f38cfb752e 100644 |
--- a/extensions/browser/api/cast_channel/cast_socket.cc |
+++ b/extensions/browser/api/cast_channel/cast_socket.cc |
@@ -99,7 +99,9 @@ CastSocket::CastSocket(const std::string& owner_extension_id, |
current_read_buffer_ = header_read_buffer_; |
} |
-CastSocket::~CastSocket() { } |
+CastSocket::~CastSocket() { |
+ CloseInternal(); |
+} |
ReadyState CastSocket::ready_state() const { |
return ready_state_; |
@@ -176,19 +178,24 @@ void CastSocket::Connect(const net::CompletionCallback& callback) { |
connect_callback_ = callback; |
connect_state_ = CONN_STATE_TCP_CONNECT; |
if (connect_timeout_.InMicroseconds() > 0) { |
- GetTimer()->Start( |
- FROM_HERE, |
- connect_timeout_, |
- base::Bind(&CastSocket::CancelConnect, AsWeakPtr())); |
+ DCHECK(connect_timeout_callback_.IsCancelled()); |
+ connect_timeout_callback_.Reset(base::Bind(&CastSocket::CancelConnect, |
+ base::Unretained(this))); |
+ GetTimer()->Start(FROM_HERE, |
+ connect_timeout_, |
+ connect_timeout_callback_.callback()); |
} |
DoConnectLoop(net::OK); |
} |
void CastSocket::PostTaskToStartConnectLoop(int result) { |
DCHECK(CalledOnValidThread()); |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, |
- base::Bind(&CastSocket::DoConnectLoop, AsWeakPtr(), result)); |
+ DCHECK(connect_loop_callback_.IsCancelled()); |
+ connect_loop_callback_.Reset(base::Bind(&CastSocket::DoConnectLoop, |
+ base::Unretained(this), |
+ result)); |
+ base::MessageLoop::current()->PostTask(FROM_HERE, |
+ connect_loop_callback_.callback()); |
} |
void CastSocket::CancelConnect() { |
@@ -204,6 +211,7 @@ void CastSocket::CancelConnect() { |
// 1. Connect method: this starts the flow |
// 2. Callback from network operations that finish asynchronously |
void CastSocket::DoConnectLoop(int result) { |
+ connect_loop_callback_.Cancel(); |
if (is_canceled_) { |
LOG(ERROR) << "CANCELLED - Aborting DoConnectLoop."; |
return; |
@@ -258,11 +266,12 @@ void CastSocket::DoConnectLoop(int result) { |
} |
int CastSocket::DoTcpConnect() { |
+ DCHECK(connect_loop_callback_.IsCancelled()); |
VLOG_WITH_CONNECTION(1) << "DoTcpConnect"; |
connect_state_ = CONN_STATE_TCP_CONNECT_COMPLETE; |
tcp_socket_ = CreateTcpSocket(); |
return tcp_socket_->Connect( |
- base::Bind(&CastSocket::DoConnectLoop, AsWeakPtr())); |
+ base::Bind(&CastSocket::DoConnectLoop, base::Unretained(this))); |
} |
int CastSocket::DoTcpConnectComplete(int result) { |
@@ -277,11 +286,12 @@ int CastSocket::DoTcpConnectComplete(int result) { |
} |
int CastSocket::DoSslConnect() { |
+ DCHECK(connect_loop_callback_.IsCancelled()); |
VLOG_WITH_CONNECTION(1) << "DoSslConnect"; |
connect_state_ = CONN_STATE_SSL_CONNECT_COMPLETE; |
socket_ = CreateSslSocket(tcp_socket_.PassAs<net::StreamSocket>()); |
return socket_->Connect( |
- base::Bind(&CastSocket::DoConnectLoop, AsWeakPtr())); |
+ base::Bind(&CastSocket::DoConnectLoop, base::Unretained(this))); |
} |
int CastSocket::DoSslConnectComplete(int result) { |
@@ -306,16 +316,28 @@ int CastSocket::DoAuthChallengeSend() { |
// Post a task to send auth challenge so that DoWriteLoop is not nested inside |
// DoConnectLoop. This is not strictly necessary but keeps the write loop |
// code decoupled from connect loop code. |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, |
+ DCHECK(send_auth_challenge_callback_.IsCancelled()); |
+ send_auth_challenge_callback_.Reset( |
base::Bind(&CastSocket::SendCastMessageInternal, |
- AsWeakPtr(), |
+ base::Unretained(this), |
challenge_message, |
- base::Bind(&CastSocket::DoConnectLoop, AsWeakPtr()))); |
+ base::Bind(&CastSocket::DoAuthChallengeSendWriteComplete, |
+ base::Unretained(this)))); |
+ base::MessageLoop::current()->PostTask( |
+ FROM_HERE, |
+ send_auth_challenge_callback_.callback()); |
// Always return IO_PENDING since the result is always asynchronous. |
return net::ERR_IO_PENDING; |
} |
+void CastSocket::DoAuthChallengeSendWriteComplete(int result) { |
+ send_auth_challenge_callback_.Cancel(); |
+ VLOG_WITH_CONNECTION(2) << "DoAuthChallengeSendWriteComplete: " << result; |
+ DCHECK_GT(result, 0); |
+ DCHECK_EQ(write_queue_.size(), 1UL); |
+ PostTaskToStartConnectLoop(result); |
+} |
+ |
int CastSocket::DoAuthChallengeSendComplete(int result) { |
VLOG_WITH_CONNECTION(1) << "DoAuthChallengeSendComplete: " << result; |
if (result < 0) |
@@ -354,15 +376,42 @@ void CastSocket::DoConnectCallback(int result) { |
} |
void CastSocket::Close(const net::CompletionCallback& callback) { |
- DCHECK(CalledOnValidThread()); |
+ CloseInternal(); |
+ callback.Run(net::OK); |
+} |
+ |
+void CastSocket::CloseInternal() { |
+ // TODO(mfoltz): Enforce this when CastChannelAPITest is rewritten to create |
+ // and free sockets on the same thread. crbug.com/398242 |
+ // DCHECK(CalledOnValidThread()); |
+ if (ready_state_ == READY_STATE_CLOSED) { |
+ return; |
+ } |
VLOG_WITH_CONNECTION(1) << "Close ReadyState = " << ready_state_; |
tcp_socket_.reset(); |
socket_.reset(); |
cert_verifier_.reset(); |
transport_security_state_.reset(); |
+ GetTimer()->Stop(); |
+ |
+ // Fire any remaining callbacks passed into us. |
+ if (!connect_callback_.is_null()) { |
+ connect_callback_.Run(net::ERR_CONNECTION_FAILED); |
Wez
2014/07/31 22:57:53
So there is no possibility of this callback deleti
mark a. foltz
2014/08/01 23:21:48
Yes this is possible and that would be bad. The o
|
+ connect_callback_.Reset(); |
+ } |
+ for (; !write_queue_.empty(); write_queue_.pop()) { |
+ net::CompletionCallback& callback = write_queue_.front().callback; |
+ callback.Run(net::ERR_FAILED); |
+ callback.Reset(); |
+ } |
+ |
+ // Cancel callbacks that we queued ourselves to re-enter the connect or read |
+ // loops. |
+ connect_loop_callback_.Cancel(); |
+ send_auth_challenge_callback_.Cancel(); |
+ read_loop_callback_.Cancel(); |
+ connect_timeout_callback_.Cancel(); |
ready_state_ = READY_STATE_CLOSED; |
- callback.Run(net::OK); |
- // |callback| can delete |this| |
} |
void CastSocket::SendMessage(const MessageInfo& message, |
@@ -377,7 +426,6 @@ void CastSocket::SendMessage(const MessageInfo& message, |
callback.Run(net::ERR_FAILED); |
return; |
} |
- |
SendCastMessageInternal(message_proto, callback); |
} |
@@ -454,11 +502,10 @@ int CastSocket::DoWrite() { |
<< request.io_buffer->BytesConsumed(); |
write_state_ = WRITE_STATE_WRITE_COMPLETE; |
- |
return socket_->Write( |
request.io_buffer.get(), |
request.io_buffer->BytesRemaining(), |
- base::Bind(&CastSocket::DoWriteLoop, AsWeakPtr())); |
+ base::Bind(&CastSocket::DoWriteLoop, base::Unretained(this))); |
} |
int CastSocket::DoWriteComplete(int result) { |
@@ -483,21 +530,11 @@ int CastSocket::DoWriteComplete(int result) { |
int CastSocket::DoWriteCallback() { |
DCHECK(!write_queue_.empty()); |
+ write_state_ = WRITE_STATE_WRITE; |
WriteRequest& request = write_queue_.front(); |
int bytes_consumed = request.io_buffer->BytesConsumed(); |
- |
- // If inside connection flow, then there should be exaclty one item in |
- // the write queue. |
- if (ready_state_ == READY_STATE_CONNECTING) { |
- write_queue_.pop(); |
- DCHECK(write_queue_.empty()); |
- PostTaskToStartConnectLoop(bytes_consumed); |
- } else { |
- WriteRequest& request = write_queue_.front(); |
- request.callback.Run(bytes_consumed); |
- write_queue_.pop(); |
- } |
- write_state_ = WRITE_STATE_WRITE; |
+ request.callback.Run(bytes_consumed); |
+ write_queue_.pop(); |
return net::OK; |
} |
@@ -526,12 +563,15 @@ int CastSocket::DoWriteError(int result) { |
void CastSocket::PostTaskToStartReadLoop() { |
DCHECK(CalledOnValidThread()); |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, |
- base::Bind(&CastSocket::StartReadLoop, AsWeakPtr())); |
+ DCHECK(read_loop_callback_.IsCancelled()); |
+ read_loop_callback_.Reset(base::Bind(&CastSocket::StartReadLoop, |
+ base::Unretained(this))); |
+ base::MessageLoop::current()->PostTask(FROM_HERE, |
+ read_loop_callback_.callback()); |
} |
void CastSocket::StartReadLoop() { |
+ read_loop_callback_.Cancel(); |
// Read loop would have already been started if read state is not NONE |
if (read_state_ == READ_STATE_NONE) { |
read_state_ = READ_STATE_READ; |
@@ -603,7 +643,7 @@ int CastSocket::DoRead() { |
return socket_->Read( |
current_read_buffer_.get(), |
num_bytes_to_read, |
- base::Bind(&CastSocket::DoReadLoop, AsWeakPtr())); |
+ base::Bind(&CastSocket::DoReadLoop, base::Unretained(this))); |
} |
int CastSocket::DoReadComplete(int result) { |
@@ -723,8 +763,7 @@ bool CastSocket::Serialize(const CastMessage& message_proto, |
void CastSocket::CloseWithError(ChannelError error) { |
DCHECK(CalledOnValidThread()); |
- socket_.reset(NULL); |
- ready_state_ = READY_STATE_CLOSED; |
+ CloseInternal(); |
error_state_ = error; |
if (delegate_) |
delegate_->OnError(this, error); |
@@ -756,7 +795,7 @@ void CastSocket::MessageHeader::SetMessageSize(size_t size) { |
void CastSocket::MessageHeader::PrependToString(std::string* str) { |
MessageHeader output = *this; |
output.message_size = base::HostToNet32(message_size); |
- size_t header_size = base::checked_cast<size_t,uint32>( |
+ size_t header_size = base::checked_cast<size_t, uint32>( |
MessageHeader::header_size()); |
scoped_ptr<char, base::FreeDeleter> char_array( |
static_cast<char*>(malloc(header_size))); |
@@ -769,7 +808,7 @@ void CastSocket::MessageHeader::PrependToString(std::string* str) { |
void CastSocket::MessageHeader::ReadFromIOBuffer( |
net::GrowableIOBuffer* buffer, MessageHeader* header) { |
uint32 message_size; |
- size_t header_size = base::checked_cast<size_t,uint32>( |
+ size_t header_size = base::checked_cast<size_t, uint32>( |
MessageHeader::header_size()); |
memcpy(&message_size, buffer->StartOfBuffer(), header_size); |
header->message_size = base::NetToHost32(message_size); |