OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |