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 const base::TimeDelta& timeout) : |
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), |
| 80 connect_timeout_(timeout), |
| 81 connect_timeout_timer_(new base::OneShotTimer<CastSocket>), |
| 82 is_canceled_(false), |
79 connect_state_(CONN_STATE_NONE), | 83 connect_state_(CONN_STATE_NONE), |
80 write_state_(WRITE_STATE_NONE), | 84 write_state_(WRITE_STATE_NONE), |
81 read_state_(READ_STATE_NONE), | 85 read_state_(READ_STATE_NONE), |
82 error_state_(CHANNEL_ERROR_NONE), | 86 error_state_(CHANNEL_ERROR_NONE), |
83 ready_state_(READY_STATE_NONE) { | 87 ready_state_(READY_STATE_NONE) { |
84 DCHECK(net_log_); | 88 DCHECK(net_log_); |
85 DCHECK(channel_auth_ == CHANNEL_AUTH_TYPE_SSL || | 89 DCHECK(channel_auth_ == CHANNEL_AUTH_TYPE_SSL || |
86 channel_auth_ == CHANNEL_AUTH_TYPE_SSL_VERIFIED); | 90 channel_auth_ == CHANNEL_AUTH_TYPE_SSL_VERIFIED); |
87 net_log_source_.type = net::NetLog::SOURCE_SOCKET; | 91 net_log_source_.type = net::NetLog::SOURCE_SOCKET; |
88 net_log_source_.id = net_log_->NextID(); | 92 net_log_source_.id = net_log_->NextID(); |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
164 void CastSocket::Connect(const net::CompletionCallback& callback) { | 168 void CastSocket::Connect(const net::CompletionCallback& callback) { |
165 DCHECK(CalledOnValidThread()); | 169 DCHECK(CalledOnValidThread()); |
166 VLOG_WITH_CONNECTION(1) << "Connect readyState = " << ready_state_; | 170 VLOG_WITH_CONNECTION(1) << "Connect readyState = " << ready_state_; |
167 if (ready_state_ != READY_STATE_NONE) { | 171 if (ready_state_ != READY_STATE_NONE) { |
168 callback.Run(net::ERR_CONNECTION_FAILED); | 172 callback.Run(net::ERR_CONNECTION_FAILED); |
169 return; | 173 return; |
170 } | 174 } |
171 ready_state_ = READY_STATE_CONNECTING; | 175 ready_state_ = READY_STATE_CONNECTING; |
172 connect_callback_ = callback; | 176 connect_callback_ = callback; |
173 connect_state_ = CONN_STATE_TCP_CONNECT; | 177 connect_state_ = CONN_STATE_TCP_CONNECT; |
| 178 if (connect_timeout_.InMicroseconds() > 0) { |
| 179 GetTimer()->Start( |
| 180 FROM_HERE, |
| 181 connect_timeout_, |
| 182 base::Bind(&CastSocket::CancelConnect, AsWeakPtr())); |
| 183 } |
174 DoConnectLoop(net::OK); | 184 DoConnectLoop(net::OK); |
175 } | 185 } |
176 | 186 |
177 void CastSocket::PostTaskToStartConnectLoop(int result) { | 187 void CastSocket::PostTaskToStartConnectLoop(int result) { |
178 DCHECK(CalledOnValidThread()); | 188 DCHECK(CalledOnValidThread()); |
179 base::MessageLoop::current()->PostTask( | 189 base::MessageLoop::current()->PostTask( |
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 is_canceled_ = true; |
| 198 VLOG_WITH_CONNECTION(1) << "Timeout while establishing a connection."; |
| 199 DoConnectCallback(net::ERR_TIMED_OUT); |
| 200 } |
| 201 |
184 // This method performs the state machine transitions for connection flow. | 202 // This method performs the state machine transitions for connection flow. |
185 // There are two entry points to this method: | 203 // There are two entry points to this method: |
186 // 1. Connect method: this starts the flow | 204 // 1. Connect method: this starts the flow |
187 // 2. Callback from network operations that finish asynchronously | 205 // 2. Callback from network operations that finish asynchronously |
188 void CastSocket::DoConnectLoop(int result) { | 206 void CastSocket::DoConnectLoop(int result) { |
| 207 if (is_canceled_) { |
| 208 LOG(ERROR) << "CANCELLED - Aborting DoConnectLoop."; |
| 209 return; |
| 210 } |
189 // Network operations can either finish synchronously or asynchronously. | 211 // Network operations can either finish synchronously or asynchronously. |
190 // This method executes the state machine transitions in a loop so that | 212 // This method executes the state machine transitions in a loop so that |
191 // correct state transitions happen even when network operations finish | 213 // correct state transitions happen even when network operations finish |
192 // synchronously. | 214 // synchronously. |
193 int rv = result; | 215 int rv = result; |
194 do { | 216 do { |
195 ConnectionState state = connect_state_; | 217 ConnectionState state = connect_state_; |
196 // Default to CONN_STATE_NONE, which breaks the processing loop if any | 218 // Default to CONN_STATE_NONE, which breaks the processing loop if any |
197 // handler fails to transition to another state to continue processing. | 219 // handler fails to transition to another state to continue processing. |
198 connect_state_ = CONN_STATE_NONE; | 220 connect_state_ = CONN_STATE_NONE; |
(...skipping 23 matching lines...) Expand all Loading... |
222 default: | 244 default: |
223 NOTREACHED() << "BUG in connect flow. Unknown state: " << state; | 245 NOTREACHED() << "BUG in connect flow. Unknown state: " << state; |
224 break; | 246 break; |
225 } | 247 } |
226 } while (rv != net::ERR_IO_PENDING && connect_state_ != CONN_STATE_NONE); | 248 } while (rv != net::ERR_IO_PENDING && connect_state_ != CONN_STATE_NONE); |
227 // Get out of the loop either when: | 249 // Get out of the loop either when: |
228 // a. A network operation is pending, OR | 250 // a. A network operation is pending, OR |
229 // b. The Do* method called did not change state | 251 // b. The Do* method called did not change state |
230 | 252 |
231 // Connect loop is finished: if there is no pending IO invoke the callback. | 253 // Connect loop is finished: if there is no pending IO invoke the callback. |
232 if (rv != net::ERR_IO_PENDING) | 254 if (rv != net::ERR_IO_PENDING) { |
| 255 GetTimer()->Stop(); |
233 DoConnectCallback(rv); | 256 DoConnectCallback(rv); |
| 257 } |
234 } | 258 } |
235 | 259 |
236 int CastSocket::DoTcpConnect() { | 260 int CastSocket::DoTcpConnect() { |
237 VLOG_WITH_CONNECTION(1) << "DoTcpConnect"; | 261 VLOG_WITH_CONNECTION(1) << "DoTcpConnect"; |
238 connect_state_ = CONN_STATE_TCP_CONNECT_COMPLETE; | 262 connect_state_ = CONN_STATE_TCP_CONNECT_COMPLETE; |
239 tcp_socket_ = CreateTcpSocket(); | 263 tcp_socket_ = CreateTcpSocket(); |
240 return tcp_socket_->Connect( | 264 return tcp_socket_->Connect( |
241 base::Bind(&CastSocket::DoConnectLoop, AsWeakPtr())); | 265 base::Bind(&CastSocket::DoConnectLoop, AsWeakPtr())); |
242 } | 266 } |
243 | 267 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
277 connect_state_ = CONN_STATE_AUTH_CHALLENGE_SEND_COMPLETE; | 301 connect_state_ = CONN_STATE_AUTH_CHALLENGE_SEND_COMPLETE; |
278 CastMessage challenge_message; | 302 CastMessage challenge_message; |
279 CreateAuthChallengeMessage(&challenge_message); | 303 CreateAuthChallengeMessage(&challenge_message); |
280 VLOG_WITH_CONNECTION(1) << "Sending challenge: " | 304 VLOG_WITH_CONNECTION(1) << "Sending challenge: " |
281 << CastMessageToString(challenge_message); | 305 << CastMessageToString(challenge_message); |
282 // Post a task to send auth challenge so that DoWriteLoop is not nested inside | 306 // 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 | 307 // DoConnectLoop. This is not strictly necessary but keeps the write loop |
284 // code decoupled from connect loop code. | 308 // code decoupled from connect loop code. |
285 base::MessageLoop::current()->PostTask( | 309 base::MessageLoop::current()->PostTask( |
286 FROM_HERE, | 310 FROM_HERE, |
287 base::Bind(&CastSocket::SendCastMessageInternal, AsWeakPtr(), | 311 base::Bind(&CastSocket::SendCastMessageInternal, |
| 312 AsWeakPtr(), |
288 challenge_message, | 313 challenge_message, |
289 base::Bind(&CastSocket::DoConnectLoop, AsWeakPtr()))); | 314 base::Bind(&CastSocket::DoConnectLoop, AsWeakPtr()))); |
290 // Always return IO_PENDING since the result is always asynchronous. | 315 // Always return IO_PENDING since the result is always asynchronous. |
291 return net::ERR_IO_PENDING; | 316 return net::ERR_IO_PENDING; |
292 } | 317 } |
293 | 318 |
294 int CastSocket::DoAuthChallengeSendComplete(int result) { | 319 int CastSocket::DoAuthChallengeSendComplete(int result) { |
295 VLOG_WITH_CONNECTION(1) << "DoAuthChallengeSendComplete: " << result; | 320 VLOG_WITH_CONNECTION(1) << "DoAuthChallengeSendComplete: " << result; |
296 if (result < 0) | 321 if (result < 0) |
297 return result; | 322 return result; |
(...skipping 11 matching lines...) Expand all Loading... |
309 if (result < 0) | 334 if (result < 0) |
310 return result; | 335 return result; |
311 if (!VerifyChallengeReply()) | 336 if (!VerifyChallengeReply()) |
312 return net::ERR_FAILED; | 337 return net::ERR_FAILED; |
313 VLOG_WITH_CONNECTION(1) << "Auth challenge verification succeeded"; | 338 VLOG_WITH_CONNECTION(1) << "Auth challenge verification succeeded"; |
314 return net::OK; | 339 return net::OK; |
315 } | 340 } |
316 | 341 |
317 void CastSocket::DoConnectCallback(int result) { | 342 void CastSocket::DoConnectCallback(int result) { |
318 ready_state_ = (result == net::OK) ? READY_STATE_OPEN : READY_STATE_CLOSED; | 343 ready_state_ = (result == net::OK) ? READY_STATE_OPEN : READY_STATE_CLOSED; |
319 error_state_ = (result == net::OK) ? | 344 if (result == net::OK) { |
320 CHANNEL_ERROR_NONE : CHANNEL_ERROR_CONNECT_ERROR; | 345 error_state_ = CHANNEL_ERROR_NONE; |
321 if (result == net::OK) // Start the read loop | |
322 PostTaskToStartReadLoop(); | 346 PostTaskToStartReadLoop(); |
| 347 } else if (result == net::ERR_TIMED_OUT) { |
| 348 error_state_ = CHANNEL_ERROR_CONNECT_TIMEOUT; |
| 349 } else { |
| 350 error_state_ = CHANNEL_ERROR_CONNECT_ERROR; |
| 351 } |
| 352 VLOG_WITH_CONNECTION(1) << "Calling Connect_Callback"; |
323 base::ResetAndReturn(&connect_callback_).Run(result); | 353 base::ResetAndReturn(&connect_callback_).Run(result); |
324 } | 354 } |
325 | 355 |
326 void CastSocket::Close(const net::CompletionCallback& callback) { | 356 void CastSocket::Close(const net::CompletionCallback& callback) { |
327 DCHECK(CalledOnValidThread()); | 357 DCHECK(CalledOnValidThread()); |
328 VLOG_WITH_CONNECTION(1) << "Close ReadyState = " << ready_state_; | 358 VLOG_WITH_CONNECTION(1) << "Close ReadyState = " << ready_state_; |
329 tcp_socket_.reset(); | 359 tcp_socket_.reset(); |
330 socket_.reset(); | 360 socket_.reset(); |
331 cert_verifier_.reset(); | 361 cert_verifier_.reset(); |
332 transport_security_state_.reset(); | 362 transport_security_state_.reset(); |
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
675 message_proto.SerializeToString(message_data); | 705 message_proto.SerializeToString(message_data); |
676 size_t message_size = message_data->size(); | 706 size_t message_size = message_data->size(); |
677 if (message_size > MessageHeader::max_message_size()) { | 707 if (message_size > MessageHeader::max_message_size()) { |
678 message_data->clear(); | 708 message_data->clear(); |
679 return false; | 709 return false; |
680 } | 710 } |
681 CastSocket::MessageHeader header; | 711 CastSocket::MessageHeader header; |
682 header.SetMessageSize(message_size); | 712 header.SetMessageSize(message_size); |
683 header.PrependToString(message_data); | 713 header.PrependToString(message_data); |
684 return true; | 714 return true; |
685 }; | 715 } |
686 | 716 |
687 void CastSocket::CloseWithError(ChannelError error) { | 717 void CastSocket::CloseWithError(ChannelError error) { |
688 DCHECK(CalledOnValidThread()); | 718 DCHECK(CalledOnValidThread()); |
689 socket_.reset(NULL); | 719 socket_.reset(NULL); |
690 ready_state_ = READY_STATE_CLOSED; | 720 ready_state_ = READY_STATE_CLOSED; |
691 error_state_ = error; | 721 error_state_ = error; |
692 if (delegate_) | 722 if (delegate_) |
693 delegate_->OnError(this, error); | 723 delegate_->OnError(this, error); |
694 } | 724 } |
695 | 725 |
696 std::string CastSocket::CastUrl() const { | 726 std::string CastSocket::CastUrl() const { |
697 return ((channel_auth_ == CHANNEL_AUTH_TYPE_SSL_VERIFIED) ? | 727 return ((channel_auth_ == CHANNEL_AUTH_TYPE_SSL_VERIFIED) ? |
698 "casts://" : "cast://") + ip_endpoint_.ToString(); | 728 "casts://" : "cast://") + ip_endpoint_.ToString(); |
699 } | 729 } |
700 | 730 |
701 bool CastSocket::CalledOnValidThread() const { | 731 bool CastSocket::CalledOnValidThread() const { |
702 return thread_checker_.CalledOnValidThread(); | 732 return thread_checker_.CalledOnValidThread(); |
703 } | 733 } |
704 | 734 |
| 735 base::Timer* CastSocket::GetTimer() { |
| 736 return connect_timeout_timer_.get(); |
| 737 } |
| 738 |
705 CastSocket::MessageHeader::MessageHeader() : message_size(0) { } | 739 CastSocket::MessageHeader::MessageHeader() : message_size(0) { } |
706 | 740 |
707 void CastSocket::MessageHeader::SetMessageSize(size_t size) { | 741 void CastSocket::MessageHeader::SetMessageSize(size_t size) { |
708 DCHECK(size < static_cast<size_t>(kuint32max)); | 742 DCHECK(size < static_cast<size_t>(kuint32max)); |
709 DCHECK(size > 0); | 743 DCHECK(size > 0); |
710 message_size = static_cast<size_t>(size); | 744 message_size = static_cast<size_t>(size); |
711 } | 745 } |
712 | 746 |
713 // TODO(mfoltz): Investigate replacing header serialization with base::Pickle, | 747 // TODO(mfoltz): Investigate replacing header serialization with base::Pickle, |
714 // if bit-for-bit compatible. | 748 // if bit-for-bit compatible. |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
751 return true; | 785 return true; |
752 } | 786 } |
753 | 787 |
754 CastSocket::WriteRequest::~WriteRequest() { } | 788 CastSocket::WriteRequest::~WriteRequest() { } |
755 | 789 |
756 } // namespace cast_channel | 790 } // namespace cast_channel |
757 } // namespace api | 791 } // namespace api |
758 } // namespace extensions | 792 } // namespace extensions |
759 | 793 |
760 #undef VLOG_WITH_CONNECTION | 794 #undef VLOG_WITH_CONNECTION |
OLD | NEW |