Index: chrome/browser/extensions/api/cast_channel/cast_socket.cc |
diff --git a/chrome/browser/extensions/api/cast_channel/cast_socket.cc b/chrome/browser/extensions/api/cast_channel/cast_socket.cc |
index 6130d92e18755dc825880177b785f7536baf5afc..fda2186193ef6d1aefce1d124d7d41d98dfd6ade 100644 |
--- a/chrome/browser/extensions/api/cast_channel/cast_socket.cc |
+++ b/chrome/browser/extensions/api/cast_channel/cast_socket.cc |
@@ -67,7 +67,8 @@ CastSocket::CastSocket(const std::string& owner_extension_id, |
const net::IPEndPoint& ip_endpoint, |
ChannelAuthType channel_auth, |
CastSocket::Delegate* delegate, |
- net::NetLog* net_log) : |
+ net::NetLog* net_log, |
+ int timeout_ms) : |
ApiResource(owner_extension_id), |
channel_id_(0), |
ip_endpoint_(ip_endpoint), |
@@ -80,7 +81,9 @@ CastSocket::CastSocket(const std::string& owner_extension_id, |
write_state_(WRITE_STATE_NONE), |
read_state_(READ_STATE_NONE), |
error_state_(CHANNEL_ERROR_NONE), |
- ready_state_(READY_STATE_NONE) { |
+ ready_state_(READY_STATE_NONE), |
+ timeout_interval_ms_(timeout_ms), |
+ connect_timeout_timer_(new base::OneShotTimer<CastSocket>) { |
DCHECK(net_log_); |
DCHECK(channel_auth_ == CHANNEL_AUTH_TYPE_SSL || |
channel_auth_ == CHANNEL_AUTH_TYPE_SSL_VERIFIED); |
@@ -171,16 +174,32 @@ void CastSocket::Connect(const net::CompletionCallback& callback) { |
ready_state_ = READY_STATE_CONNECTING; |
connect_callback_ = callback; |
connect_state_ = CONN_STATE_TCP_CONNECT; |
+ if (timeout_interval_ms_ > 0) { |
+ connect_timeout_timer_->Start( |
+ FROM_HERE, |
+ base::TimeDelta::FromMilliseconds(timeout_interval_ms_), |
+ base::Bind(&CastSocket::CancelConnect, AsWeakPtr())); |
+ } |
DoConnectLoop(net::OK); |
} |
void CastSocket::PostTaskToStartConnectLoop(int result) { |
DCHECK(CalledOnValidThread()); |
- base::MessageLoop::current()->PostTask( |
+ task_tracker_.PostTask( |
+ base::MessageLoop::current()->task_runner(), |
FROM_HERE, |
base::Bind(&CastSocket::DoConnectLoop, AsWeakPtr(), result)); |
} |
+void CastSocket::CancelConnect() { |
+ DCHECK(CalledOnValidThread()); |
+ // Stop all pending connection setup tasks and report back to the client. |
+ VLOG(1) << "Timeout while establishing a connection."; |
+ task_tracker_.TryCancelAll(); |
+ CloseWithError(CHANNEL_ERROR_CONNECT_TIMEOUT); |
+ DoConnectCallback(net::ERR_TIMED_OUT); |
+} |
+ |
// This method performs the state machine transitions for connection flow. |
// There are two entry points to this method: |
// 1. Connect method: this starts the flow |
@@ -229,8 +248,10 @@ void CastSocket::DoConnectLoop(int result) { |
// b. The Do* method called did not change state |
// Connect loop is finished: if there is no pending IO invoke the callback. |
- if (rv != net::ERR_IO_PENDING) |
+ if (rv != net::ERR_IO_PENDING) { |
+ connect_timeout_timer_->Stop(); |
DoConnectCallback(rv); |
+ } |
} |
int CastSocket::DoTcpConnect() { |
@@ -282,7 +303,8 @@ 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( |
+ task_tracker_.PostTask( |
+ base::MessageLoop::current()->task_runner(), |
FROM_HERE, |
base::Bind(&CastSocket::SendCastMessageInternal, AsWeakPtr(), |
challenge_message, |
@@ -316,8 +338,13 @@ int CastSocket::DoAuthChallengeReplyComplete(int result) { |
void CastSocket::DoConnectCallback(int result) { |
ready_state_ = (result == net::OK) ? READY_STATE_OPEN : READY_STATE_CLOSED; |
- error_state_ = (result == net::OK) ? |
- CHANNEL_ERROR_NONE : CHANNEL_ERROR_CONNECT_ERROR; |
+ if (result == net::OK) { |
+ error_state_ = CHANNEL_ERROR_NONE; |
+ } else if (result == net::ERR_TIMED_OUT) { |
+ error_state_ = CHANNEL_ERROR_CONNECT_TIMEOUT; |
+ } else { |
+ error_state_ = CHANNEL_ERROR_CONNECT_ERROR; |
+ } |
if (result == net::OK) // Start the read loop |
PostTaskToStartReadLoop(); |
base::ResetAndReturn(&connect_callback_).Run(result); |
@@ -496,7 +523,8 @@ int CastSocket::DoWriteError(int result) { |
void CastSocket::PostTaskToStartReadLoop() { |
DCHECK(CalledOnValidThread()); |
- base::MessageLoop::current()->PostTask( |
+ task_tracker_.PostTask( |
+ base::MessageLoop::current()->task_runner(), |
FROM_HERE, |
base::Bind(&CastSocket::StartReadLoop, AsWeakPtr())); |
} |
@@ -682,7 +710,7 @@ bool CastSocket::Serialize(const CastMessage& message_proto, |
header.SetMessageSize(message_size); |
header.PrependToString(message_data); |
return true; |
-}; |
+} |
void CastSocket::CloseWithError(ChannelError error) { |
DCHECK(CalledOnValidThread()); |
@@ -702,6 +730,10 @@ bool CastSocket::CalledOnValidThread() const { |
return thread_checker_.CalledOnValidThread(); |
} |
+void CastSocket::InjectTimerForTesting(scoped_ptr<base::Timer> injected_timer) { |
+ connect_timeout_timer_ = injected_timer.Pass(); |
+} |
+ |
CastSocket::MessageHeader::MessageHeader() : message_size(0) { } |
void CastSocket::MessageHeader::SetMessageSize(size_t size) { |