Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(99)

Side by Side Diff: chrome/browser/extensions/api/cast_channel/cast_socket.cc

Issue 393023003: Added connection timeout functionality to CastSocket. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: JS API plumbing, switch approach from MessageLoop to Timer, better testing. Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/api/cast_channel/cast_socket.h" 5 #include "chrome/browser/extensions/api/cast_channel/cast_socket.h"
6 6
7 #include <stdlib.h> 7 #include <stdlib.h>
8 #include <string.h> 8 #include <string.h>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
60 return g_factory.Pointer(); 60 return g_factory.Pointer();
61 } 61 }
62 62
63 namespace api { 63 namespace api {
64 namespace cast_channel { 64 namespace cast_channel {
65 65
66 CastSocket::CastSocket(const std::string& owner_extension_id, 66 CastSocket::CastSocket(const std::string& owner_extension_id,
67 const net::IPEndPoint& ip_endpoint, 67 const net::IPEndPoint& ip_endpoint,
68 ChannelAuthType channel_auth, 68 ChannelAuthType channel_auth,
69 CastSocket::Delegate* delegate, 69 CastSocket::Delegate* delegate,
70 net::NetLog* net_log) : 70 net::NetLog* net_log,
71 int timeout_ms) :
71 ApiResource(owner_extension_id), 72 ApiResource(owner_extension_id),
72 channel_id_(0), 73 channel_id_(0),
73 ip_endpoint_(ip_endpoint), 74 ip_endpoint_(ip_endpoint),
74 channel_auth_(channel_auth), 75 channel_auth_(channel_auth),
75 delegate_(delegate), 76 delegate_(delegate),
76 current_message_size_(0), 77 current_message_size_(0),
77 current_message_(new CastMessage()), 78 current_message_(new CastMessage()),
78 net_log_(net_log), 79 net_log_(net_log),
79 connect_state_(CONN_STATE_NONE), 80 connect_state_(CONN_STATE_NONE),
80 write_state_(WRITE_STATE_NONE), 81 write_state_(WRITE_STATE_NONE),
81 read_state_(READ_STATE_NONE), 82 read_state_(READ_STATE_NONE),
82 error_state_(CHANNEL_ERROR_NONE), 83 error_state_(CHANNEL_ERROR_NONE),
83 ready_state_(READY_STATE_NONE) { 84 ready_state_(READY_STATE_NONE),
85 timeout_interval_ms_(timeout_ms),
86 connect_timeout_timer_(new base::OneShotTimer<CastSocket>) {
84 DCHECK(net_log_); 87 DCHECK(net_log_);
85 DCHECK(channel_auth_ == CHANNEL_AUTH_TYPE_SSL || 88 DCHECK(channel_auth_ == CHANNEL_AUTH_TYPE_SSL ||
86 channel_auth_ == CHANNEL_AUTH_TYPE_SSL_VERIFIED); 89 channel_auth_ == CHANNEL_AUTH_TYPE_SSL_VERIFIED);
87 net_log_source_.type = net::NetLog::SOURCE_SOCKET; 90 net_log_source_.type = net::NetLog::SOURCE_SOCKET;
88 net_log_source_.id = net_log_->NextID(); 91 net_log_source_.id = net_log_->NextID();
89 92
90 // Reuse these buffers for each message. 93 // Reuse these buffers for each message.
91 header_read_buffer_ = new net::GrowableIOBuffer(); 94 header_read_buffer_ = new net::GrowableIOBuffer();
92 header_read_buffer_->SetCapacity(MessageHeader::header_size()); 95 header_read_buffer_->SetCapacity(MessageHeader::header_size());
93 body_read_buffer_ = new net::GrowableIOBuffer(); 96 body_read_buffer_ = new net::GrowableIOBuffer();
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
164 void CastSocket::Connect(const net::CompletionCallback& callback) { 167 void CastSocket::Connect(const net::CompletionCallback& callback) {
165 DCHECK(CalledOnValidThread()); 168 DCHECK(CalledOnValidThread());
166 VLOG_WITH_CONNECTION(1) << "Connect readyState = " << ready_state_; 169 VLOG_WITH_CONNECTION(1) << "Connect readyState = " << ready_state_;
167 if (ready_state_ != READY_STATE_NONE) { 170 if (ready_state_ != READY_STATE_NONE) {
168 callback.Run(net::ERR_CONNECTION_FAILED); 171 callback.Run(net::ERR_CONNECTION_FAILED);
169 return; 172 return;
170 } 173 }
171 ready_state_ = READY_STATE_CONNECTING; 174 ready_state_ = READY_STATE_CONNECTING;
172 connect_callback_ = callback; 175 connect_callback_ = callback;
173 connect_state_ = CONN_STATE_TCP_CONNECT; 176 connect_state_ = CONN_STATE_TCP_CONNECT;
177 if (timeout_interval_ms_ > 0) {
178 connect_timeout_timer_->Start(
179 FROM_HERE,
180 base::TimeDelta::FromMilliseconds(timeout_interval_ms_),
181 base::Bind(&CastSocket::CancelConnect, AsWeakPtr()));
182 }
174 DoConnectLoop(net::OK); 183 DoConnectLoop(net::OK);
175 } 184 }
176 185
177 void CastSocket::PostTaskToStartConnectLoop(int result) { 186 void CastSocket::PostTaskToStartConnectLoop(int result) {
178 DCHECK(CalledOnValidThread()); 187 DCHECK(CalledOnValidThread());
179 base::MessageLoop::current()->PostTask( 188 task_tracker_.PostTask(
189 base::MessageLoop::current()->task_runner(),
180 FROM_HERE, 190 FROM_HERE,
181 base::Bind(&CastSocket::DoConnectLoop, AsWeakPtr(), result)); 191 base::Bind(&CastSocket::DoConnectLoop, AsWeakPtr(), result));
182 } 192 }
183 193
194 void CastSocket::CancelConnect() {
195 DCHECK(CalledOnValidThread());
196 // Stop all pending connection setup tasks and report back to the client.
197 VLOG(1) << "Timeout while establishing a connection.";
198 task_tracker_.TryCancelAll();
199 CloseWithError(CHANNEL_ERROR_CONNECT_TIMEOUT);
200 DoConnectCallback(net::ERR_TIMED_OUT);
201 }
202
184 // This method performs the state machine transitions for connection flow. 203 // This method performs the state machine transitions for connection flow.
185 // There are two entry points to this method: 204 // There are two entry points to this method:
186 // 1. Connect method: this starts the flow 205 // 1. Connect method: this starts the flow
187 // 2. Callback from network operations that finish asynchronously 206 // 2. Callback from network operations that finish asynchronously
188 void CastSocket::DoConnectLoop(int result) { 207 void CastSocket::DoConnectLoop(int result) {
189 // Network operations can either finish synchronously or asynchronously. 208 // Network operations can either finish synchronously or asynchronously.
190 // This method executes the state machine transitions in a loop so that 209 // This method executes the state machine transitions in a loop so that
191 // correct state transitions happen even when network operations finish 210 // correct state transitions happen even when network operations finish
192 // synchronously. 211 // synchronously.
193 int rv = result; 212 int rv = result;
(...skipping 28 matching lines...) Expand all
222 default: 241 default:
223 NOTREACHED() << "BUG in connect flow. Unknown state: " << state; 242 NOTREACHED() << "BUG in connect flow. Unknown state: " << state;
224 break; 243 break;
225 } 244 }
226 } while (rv != net::ERR_IO_PENDING && connect_state_ != CONN_STATE_NONE); 245 } while (rv != net::ERR_IO_PENDING && connect_state_ != CONN_STATE_NONE);
227 // Get out of the loop either when: 246 // Get out of the loop either when:
228 // a. A network operation is pending, OR 247 // a. A network operation is pending, OR
229 // b. The Do* method called did not change state 248 // b. The Do* method called did not change state
230 249
231 // Connect loop is finished: if there is no pending IO invoke the callback. 250 // Connect loop is finished: if there is no pending IO invoke the callback.
232 if (rv != net::ERR_IO_PENDING) 251 if (rv != net::ERR_IO_PENDING) {
252 connect_timeout_timer_->Stop();
233 DoConnectCallback(rv); 253 DoConnectCallback(rv);
254 }
234 } 255 }
235 256
236 int CastSocket::DoTcpConnect() { 257 int CastSocket::DoTcpConnect() {
237 VLOG_WITH_CONNECTION(1) << "DoTcpConnect"; 258 VLOG_WITH_CONNECTION(1) << "DoTcpConnect";
238 connect_state_ = CONN_STATE_TCP_CONNECT_COMPLETE; 259 connect_state_ = CONN_STATE_TCP_CONNECT_COMPLETE;
239 tcp_socket_ = CreateTcpSocket(); 260 tcp_socket_ = CreateTcpSocket();
240 return tcp_socket_->Connect( 261 return tcp_socket_->Connect(
241 base::Bind(&CastSocket::DoConnectLoop, AsWeakPtr())); 262 base::Bind(&CastSocket::DoConnectLoop, AsWeakPtr()));
242 } 263 }
243 264
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 int CastSocket::DoAuthChallengeSend() { 296 int CastSocket::DoAuthChallengeSend() {
276 VLOG_WITH_CONNECTION(1) << "DoAuthChallengeSend"; 297 VLOG_WITH_CONNECTION(1) << "DoAuthChallengeSend";
277 connect_state_ = CONN_STATE_AUTH_CHALLENGE_SEND_COMPLETE; 298 connect_state_ = CONN_STATE_AUTH_CHALLENGE_SEND_COMPLETE;
278 CastMessage challenge_message; 299 CastMessage challenge_message;
279 CreateAuthChallengeMessage(&challenge_message); 300 CreateAuthChallengeMessage(&challenge_message);
280 VLOG_WITH_CONNECTION(1) << "Sending challenge: " 301 VLOG_WITH_CONNECTION(1) << "Sending challenge: "
281 << CastMessageToString(challenge_message); 302 << CastMessageToString(challenge_message);
282 // Post a task to send auth challenge so that DoWriteLoop is not nested inside 303 // Post a task to send auth challenge so that DoWriteLoop is not nested inside
283 // DoConnectLoop. This is not strictly necessary but keeps the write loop 304 // DoConnectLoop. This is not strictly necessary but keeps the write loop
284 // code decoupled from connect loop code. 305 // code decoupled from connect loop code.
285 base::MessageLoop::current()->PostTask( 306 task_tracker_.PostTask(
307 base::MessageLoop::current()->task_runner(),
286 FROM_HERE, 308 FROM_HERE,
287 base::Bind(&CastSocket::SendCastMessageInternal, AsWeakPtr(), 309 base::Bind(&CastSocket::SendCastMessageInternal, AsWeakPtr(),
288 challenge_message, 310 challenge_message,
289 base::Bind(&CastSocket::DoConnectLoop, AsWeakPtr()))); 311 base::Bind(&CastSocket::DoConnectLoop, AsWeakPtr())));
290 // Always return IO_PENDING since the result is always asynchronous. 312 // Always return IO_PENDING since the result is always asynchronous.
291 return net::ERR_IO_PENDING; 313 return net::ERR_IO_PENDING;
292 } 314 }
293 315
294 int CastSocket::DoAuthChallengeSendComplete(int result) { 316 int CastSocket::DoAuthChallengeSendComplete(int result) {
295 VLOG_WITH_CONNECTION(1) << "DoAuthChallengeSendComplete: " << result; 317 VLOG_WITH_CONNECTION(1) << "DoAuthChallengeSendComplete: " << result;
(...skipping 13 matching lines...) Expand all
309 if (result < 0) 331 if (result < 0)
310 return result; 332 return result;
311 if (!VerifyChallengeReply()) 333 if (!VerifyChallengeReply())
312 return net::ERR_FAILED; 334 return net::ERR_FAILED;
313 VLOG_WITH_CONNECTION(1) << "Auth challenge verification succeeded"; 335 VLOG_WITH_CONNECTION(1) << "Auth challenge verification succeeded";
314 return net::OK; 336 return net::OK;
315 } 337 }
316 338
317 void CastSocket::DoConnectCallback(int result) { 339 void CastSocket::DoConnectCallback(int result) {
318 ready_state_ = (result == net::OK) ? READY_STATE_OPEN : READY_STATE_CLOSED; 340 ready_state_ = (result == net::OK) ? READY_STATE_OPEN : READY_STATE_CLOSED;
319 error_state_ = (result == net::OK) ? 341 if (result == net::OK) {
320 CHANNEL_ERROR_NONE : CHANNEL_ERROR_CONNECT_ERROR; 342 error_state_ = CHANNEL_ERROR_NONE;
343 } else if (result == net::ERR_TIMED_OUT) {
344 error_state_ = CHANNEL_ERROR_CONNECT_TIMEOUT;
345 } else {
346 error_state_ = CHANNEL_ERROR_CONNECT_ERROR;
347 }
321 if (result == net::OK) // Start the read loop 348 if (result == net::OK) // Start the read loop
322 PostTaskToStartReadLoop(); 349 PostTaskToStartReadLoop();
323 base::ResetAndReturn(&connect_callback_).Run(result); 350 base::ResetAndReturn(&connect_callback_).Run(result);
324 } 351 }
325 352
326 void CastSocket::Close(const net::CompletionCallback& callback) { 353 void CastSocket::Close(const net::CompletionCallback& callback) {
327 DCHECK(CalledOnValidThread()); 354 DCHECK(CalledOnValidThread());
328 VLOG_WITH_CONNECTION(1) << "Close ReadyState = " << ready_state_; 355 VLOG_WITH_CONNECTION(1) << "Close ReadyState = " << ready_state_;
329 tcp_socket_.reset(); 356 tcp_socket_.reset();
330 socket_.reset(); 357 socket_.reset();
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
489 while (!write_queue_.empty()) { 516 while (!write_queue_.empty()) {
490 WriteRequest& request = write_queue_.front(); 517 WriteRequest& request = write_queue_.front();
491 request.callback.Run(result); 518 request.callback.Run(result);
492 write_queue_.pop(); 519 write_queue_.pop();
493 } 520 }
494 return net::ERR_FAILED; 521 return net::ERR_FAILED;
495 } 522 }
496 523
497 void CastSocket::PostTaskToStartReadLoop() { 524 void CastSocket::PostTaskToStartReadLoop() {
498 DCHECK(CalledOnValidThread()); 525 DCHECK(CalledOnValidThread());
499 base::MessageLoop::current()->PostTask( 526 task_tracker_.PostTask(
527 base::MessageLoop::current()->task_runner(),
500 FROM_HERE, 528 FROM_HERE,
501 base::Bind(&CastSocket::StartReadLoop, AsWeakPtr())); 529 base::Bind(&CastSocket::StartReadLoop, AsWeakPtr()));
502 } 530 }
503 531
504 void CastSocket::StartReadLoop() { 532 void CastSocket::StartReadLoop() {
505 // Read loop would have already been started if read state is not NONE 533 // Read loop would have already been started if read state is not NONE
506 if (read_state_ == READ_STATE_NONE) { 534 if (read_state_ == READ_STATE_NONE) {
507 read_state_ = READ_STATE_READ; 535 read_state_ = READ_STATE_READ;
508 DoReadLoop(net::OK); 536 DoReadLoop(net::OK);
509 } 537 }
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
675 message_proto.SerializeToString(message_data); 703 message_proto.SerializeToString(message_data);
676 size_t message_size = message_data->size(); 704 size_t message_size = message_data->size();
677 if (message_size > MessageHeader::max_message_size()) { 705 if (message_size > MessageHeader::max_message_size()) {
678 message_data->clear(); 706 message_data->clear();
679 return false; 707 return false;
680 } 708 }
681 CastSocket::MessageHeader header; 709 CastSocket::MessageHeader header;
682 header.SetMessageSize(message_size); 710 header.SetMessageSize(message_size);
683 header.PrependToString(message_data); 711 header.PrependToString(message_data);
684 return true; 712 return true;
685 }; 713 }
686 714
687 void CastSocket::CloseWithError(ChannelError error) { 715 void CastSocket::CloseWithError(ChannelError error) {
688 DCHECK(CalledOnValidThread()); 716 DCHECK(CalledOnValidThread());
689 socket_.reset(NULL); 717 socket_.reset(NULL);
690 ready_state_ = READY_STATE_CLOSED; 718 ready_state_ = READY_STATE_CLOSED;
691 error_state_ = error; 719 error_state_ = error;
692 if (delegate_) 720 if (delegate_)
693 delegate_->OnError(this, error); 721 delegate_->OnError(this, error);
694 } 722 }
695 723
696 std::string CastSocket::CastUrl() const { 724 std::string CastSocket::CastUrl() const {
697 return ((channel_auth_ == CHANNEL_AUTH_TYPE_SSL_VERIFIED) ? 725 return ((channel_auth_ == CHANNEL_AUTH_TYPE_SSL_VERIFIED) ?
698 "casts://" : "cast://") + ip_endpoint_.ToString(); 726 "casts://" : "cast://") + ip_endpoint_.ToString();
699 } 727 }
700 728
701 bool CastSocket::CalledOnValidThread() const { 729 bool CastSocket::CalledOnValidThread() const {
702 return thread_checker_.CalledOnValidThread(); 730 return thread_checker_.CalledOnValidThread();
703 } 731 }
704 732
733 void CastSocket::InjectTimerForTesting(scoped_ptr<base::Timer> injected_timer) {
734 connect_timeout_timer_ = injected_timer.Pass();
735 }
736
705 CastSocket::MessageHeader::MessageHeader() : message_size(0) { } 737 CastSocket::MessageHeader::MessageHeader() : message_size(0) { }
706 738
707 void CastSocket::MessageHeader::SetMessageSize(size_t size) { 739 void CastSocket::MessageHeader::SetMessageSize(size_t size) {
708 DCHECK(size < static_cast<size_t>(kuint32max)); 740 DCHECK(size < static_cast<size_t>(kuint32max));
709 DCHECK(size > 0); 741 DCHECK(size > 0);
710 message_size = static_cast<size_t>(size); 742 message_size = static_cast<size_t>(size);
711 } 743 }
712 744
713 // TODO(mfoltz): Investigate replacing header serialization with base::Pickle, 745 // TODO(mfoltz): Investigate replacing header serialization with base::Pickle,
714 // if bit-for-bit compatible. 746 // if bit-for-bit compatible.
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
751 return true; 783 return true;
752 } 784 }
753 785
754 CastSocket::WriteRequest::~WriteRequest() { } 786 CastSocket::WriteRequest::~WriteRequest() { }
755 787
756 } // namespace cast_channel 788 } // namespace cast_channel
757 } // namespace api 789 } // namespace api
758 } // namespace extensions 790 } // namespace extensions
759 791
760 #undef VLOG_WITH_CONNECTION 792 #undef VLOG_WITH_CONNECTION
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698