OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "remoting/host/chromoting_host.h" | 5 #include "remoting/host/chromoting_host.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback.h" | 8 #include "base/callback.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/message_loop_proxy.h" | 10 #include "base/message_loop_proxy.h" |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
123 } | 123 } |
124 if (!shutdown_task.is_null()) | 124 if (!shutdown_task.is_null()) |
125 shutdown_tasks_.push_back(shutdown_task); | 125 shutdown_tasks_.push_back(shutdown_task); |
126 if (state_ == kStopping) | 126 if (state_ == kStopping) |
127 return; | 127 return; |
128 state_ = kStopping; | 128 state_ = kStopping; |
129 } | 129 } |
130 | 130 |
131 // Disconnect all of the clients, implicitly stopping the ScreenRecorder. | 131 // Disconnect all of the clients, implicitly stopping the ScreenRecorder. |
132 while (!clients_.empty()) { | 132 while (!clients_.empty()) { |
133 OnClientDisconnected(clients_.front()->connection()); | 133 scoped_refptr<ClientSession> client = clients_.front(); |
| 134 client->Disconnect(); |
| 135 OnClientDisconnected(client); |
134 } | 136 } |
135 | 137 |
136 ShutdownNetwork(); | 138 ShutdownNetwork(); |
137 } | 139 } |
138 | 140 |
139 void ChromotingHost::AddStatusObserver(HostStatusObserver* observer) { | 141 void ChromotingHost::AddStatusObserver(HostStatusObserver* observer) { |
140 DCHECK_EQ(state_, kInitial); | 142 DCHECK_EQ(state_, kInitial); |
141 status_observers_.push_back(observer); | 143 status_observers_.push_back(observer); |
142 } | 144 } |
143 | 145 |
144 //////////////////////////////////////////////////////////////////////////// | 146 //////////////////////////////////////////////////////////////////////////// |
145 // protocol::ConnectionToClient::EventHandler implementations | 147 // protocol::ClientSession::EventHandler implementation. |
146 void ChromotingHost::OnConnectionOpened(ConnectionToClient* connection) { | 148 void ChromotingHost::OnSessionAuthenticated(ClientSession* client) { |
147 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); | 149 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
148 VLOG(1) << "Connection to client established."; | 150 protocol::Session* session = client->connection()->session(); |
149 context_->main_message_loop()->PostTask( | 151 context_->main_message_loop()->PostTask( |
150 FROM_HERE, base::Bind(&ChromotingHost::ProcessPreAuthentication, this, | 152 FROM_HERE, base::Bind(&ChromotingHost::AddAuthenticatedClient, |
151 make_scoped_refptr(connection))); | 153 this, make_scoped_refptr(client), |
| 154 session->config(), session->jid())); |
152 } | 155 } |
153 | 156 |
154 void ChromotingHost::OnConnectionClosed(ConnectionToClient* connection) { | 157 void ChromotingHost::OnSessionClosed(ClientSession* client) { |
155 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); | 158 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
156 | 159 |
157 VLOG(1) << "Connection to client closed."; | 160 VLOG(1) << "Connection to client closed."; |
158 context_->main_message_loop()->PostTask( | 161 context_->main_message_loop()->PostTask( |
159 FROM_HERE, base::Bind(&ChromotingHost::OnClientDisconnected, this, | 162 FROM_HERE, base::Bind(&ChromotingHost::OnClientDisconnected, this, |
160 make_scoped_refptr(connection))); | 163 make_scoped_refptr(client))); |
161 } | 164 } |
162 | 165 |
163 void ChromotingHost::OnConnectionFailed(ConnectionToClient* connection) { | 166 void ChromotingHost::OnSessionSequenceNumber(ClientSession* session, |
164 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); | |
165 | |
166 LOG(ERROR) << "Connection failed unexpectedly."; | |
167 context_->main_message_loop()->PostTask( | |
168 FROM_HERE, base::Bind(&ChromotingHost::OnClientDisconnected, this, | |
169 make_scoped_refptr(connection))); | |
170 } | |
171 | |
172 void ChromotingHost::OnSequenceNumberUpdated(ConnectionToClient* connection, | |
173 int64 sequence_number) { | 167 int64 sequence_number) { |
174 // Update the sequence number in ScreenRecorder. | 168 // Update the sequence number in ScreenRecorder. |
175 if (MessageLoop::current() != context_->main_message_loop()) { | 169 if (MessageLoop::current() != context_->main_message_loop()) { |
176 context_->main_message_loop()->PostTask( | 170 context_->main_message_loop()->PostTask( |
177 FROM_HERE, base::Bind(&ChromotingHost::OnSequenceNumberUpdated, this, | 171 FROM_HERE, base::Bind(&ChromotingHost::OnSessionSequenceNumber, this, |
178 make_scoped_refptr(connection), sequence_number)); | 172 make_scoped_refptr(session), sequence_number)); |
179 return; | 173 return; |
180 } | 174 } |
181 | 175 |
182 if (recorder_.get()) | 176 if (recorder_.get()) |
183 recorder_->UpdateSequenceNumber(sequence_number); | 177 recorder_->UpdateSequenceNumber(sequence_number); |
184 } | 178 } |
185 | 179 |
186 //////////////////////////////////////////////////////////////////////////// | 180 //////////////////////////////////////////////////////////////////////////// |
187 // SignalStrategy::StatusObserver implementations | 181 // SignalStrategy::StatusObserver implementations |
188 void ChromotingHost::OnStateChange( | 182 void ChromotingHost::OnStateChange( |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
285 session->set_receiver_token( | 279 session->set_receiver_token( |
286 GenerateHostAuthToken(session->initiator_token())); | 280 GenerateHostAuthToken(session->initiator_token())); |
287 | 281 |
288 // Provide the Access Code as shared secret for SSL channel authentication. | 282 // Provide the Access Code as shared secret for SSL channel authentication. |
289 session->set_shared_secret(access_code_); | 283 session->set_shared_secret(access_code_); |
290 | 284 |
291 *response = protocol::SessionManager::ACCEPT; | 285 *response = protocol::SessionManager::ACCEPT; |
292 | 286 |
293 LOG(INFO) << "Client connected: " << session->jid(); | 287 LOG(INFO) << "Client connected: " << session->jid(); |
294 | 288 |
295 // We accept the connection, so create a connection object. | |
296 ConnectionToClient* connection = new ConnectionToClient( | |
297 context_->network_message_loop(), this); | |
298 connection->Init(session); | |
299 | |
300 // Create a client object. | 289 // Create a client object. |
| 290 scoped_refptr<protocol::ConnectionToClient> connection = |
| 291 new protocol::ConnectionToClient(context_->network_message_loop(), |
| 292 session); |
301 ClientSession* client = new ClientSession( | 293 ClientSession* client = new ClientSession( |
302 this, | 294 this, connection, |
303 connection, | |
304 desktop_environment_->event_executor(), | 295 desktop_environment_->event_executor(), |
305 desktop_environment_->capturer()); | 296 desktop_environment_->capturer()); |
306 connection->set_host_stub(client); | |
307 connection->set_input_stub(client); | |
308 | 297 |
309 clients_.push_back(client); | 298 clients_.push_back(client); |
310 } | 299 } |
311 | 300 |
312 void ChromotingHost::set_protocol_config( | 301 void ChromotingHost::set_protocol_config( |
313 protocol::CandidateSessionConfig* config) { | 302 protocol::CandidateSessionConfig* config) { |
314 DCHECK(config_.get()); | 303 DCHECK(config_.get()); |
315 DCHECK_EQ(state_, kInitial); | 304 DCHECK_EQ(state_, kInitial); |
316 protocol_config_.reset(config); | 305 protocol_config_.reset(config); |
317 } | 306 } |
(...skipping 23 matching lines...) Expand all Loading... |
341 desktop_environment_->OnPause(pause); | 330 desktop_environment_->OnPause(pause); |
342 } | 331 } |
343 | 332 |
344 void ChromotingHost::SetUiStrings(const UiStrings& ui_strings) { | 333 void ChromotingHost::SetUiStrings(const UiStrings& ui_strings) { |
345 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); | 334 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); |
346 DCHECK_EQ(state_, kInitial); | 335 DCHECK_EQ(state_, kInitial); |
347 | 336 |
348 ui_strings_ = ui_strings; | 337 ui_strings_ = ui_strings; |
349 } | 338 } |
350 | 339 |
351 void ChromotingHost::OnClientDisconnected(ConnectionToClient* connection) { | 340 void ChromotingHost::OnClientDisconnected(ClientSession* client) { |
352 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); | 341 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); |
353 | 342 |
354 // Find the client session corresponding to the given connection. | 343 scoped_refptr<ClientSession> client_ref = client; |
| 344 |
355 ClientList::iterator it; | 345 ClientList::iterator it; |
356 for (it = clients_.begin(); it != clients_.end(); ++it) { | 346 for (it = clients_.begin(); it != clients_.end(); ++it) { |
357 if (it->get()->connection() == connection) | 347 if (it->get() == client) |
358 break; | 348 break; |
359 } | 349 } |
360 if (it == clients_.end()) | |
361 return; | |
362 | |
363 scoped_refptr<ClientSession> client = *it; | |
364 | |
365 clients_.erase(it); | 350 clients_.erase(it); |
366 | 351 |
367 if (recorder_.get()) { | 352 if (recorder_.get()) { |
368 recorder_->RemoveConnection(connection); | 353 recorder_->RemoveConnection(client->connection()); |
369 } | 354 } |
370 | 355 |
371 // Close the connection to client just to be safe. | |
372 // TODO(garykac): This should be removed when we revisit our shutdown and | |
373 // disconnect code. This should only need to be done in | |
374 // ClientSession::Disconnect(). | |
375 connection->Disconnect(); | |
376 | |
377 for (StatusObserverList::iterator it = status_observers_.begin(); | 356 for (StatusObserverList::iterator it = status_observers_.begin(); |
378 it != status_observers_.end(); ++it) { | 357 it != status_observers_.end(); ++it) { |
379 (*it)->OnClientDisconnected(client->client_jid()); | 358 (*it)->OnClientDisconnected(client->client_jid()); |
380 } | 359 } |
381 | 360 |
382 if (AuthenticatedClientsCount() == 0) { | 361 if (AuthenticatedClientsCount() == 0) { |
383 if (recorder_.get()) { | 362 if (recorder_.get()) { |
384 // Stop the recorder if there are no more clients. | 363 // Stop the recorder if there are no more clients. |
385 StopScreenRecorder(); | 364 StopScreenRecorder(); |
386 } | 365 } |
387 | 366 |
388 // Disable the "curtain" if there are no more active clients. | 367 // Disable the "curtain" if there are no more active clients. |
389 EnableCurtainMode(false); | 368 EnableCurtainMode(false); |
390 if (is_it2me_) { | 369 desktop_environment_->OnLastDisconnect(); |
391 desktop_environment_->OnLastDisconnect(); | |
392 } | |
393 } | 370 } |
394 | |
395 client->OnDisconnected(); | |
396 } | 371 } |
397 | 372 |
398 // TODO(sergeyu): Move this to SessionManager? | 373 // TODO(sergeyu): Move this to SessionManager? |
399 Encoder* ChromotingHost::CreateEncoder(const protocol::SessionConfig& config) { | 374 Encoder* ChromotingHost::CreateEncoder(const protocol::SessionConfig& config) { |
400 const protocol::ChannelConfig& video_config = config.video_config(); | 375 const protocol::ChannelConfig& video_config = config.video_config(); |
401 | 376 |
402 if (video_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) { | 377 if (video_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) { |
403 return EncoderRowBased::CreateVerbatimEncoder(); | 378 return EncoderRowBased::CreateVerbatimEncoder(); |
404 } else if (video_config.codec == protocol::ChannelConfig::CODEC_ZIP) { | 379 } else if (video_config.codec == protocol::ChannelConfig::CODEC_ZIP) { |
405 return EncoderRowBased::CreateZlibEncoder(); | 380 return EncoderRowBased::CreateZlibEncoder(); |
(...skipping 23 matching lines...) Expand all Loading... |
429 void ChromotingHost::EnableCurtainMode(bool enable) { | 404 void ChromotingHost::EnableCurtainMode(bool enable) { |
430 // TODO(jamiewalch): This will need to be more sophisticated when we think | 405 // TODO(jamiewalch): This will need to be more sophisticated when we think |
431 // about proper crash recovery and daemon mode. | 406 // about proper crash recovery and daemon mode. |
432 // TODO(wez): CurtainMode shouldn't be driven directly by ChromotingHost. | 407 // TODO(wez): CurtainMode shouldn't be driven directly by ChromotingHost. |
433 if (is_it2me_ || enable == is_curtained_) | 408 if (is_it2me_ || enable == is_curtained_) |
434 return; | 409 return; |
435 desktop_environment_->curtain()->EnableCurtainMode(enable); | 410 desktop_environment_->curtain()->EnableCurtainMode(enable); |
436 is_curtained_ = enable; | 411 is_curtained_ = enable; |
437 } | 412 } |
438 | 413 |
439 void ChromotingHost::OnAuthenticationComplete( | |
440 scoped_refptr<ConnectionToClient> connection) { | |
441 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); | |
442 | |
443 context_->main_message_loop()->PostTask( | |
444 FROM_HERE, base::Bind(&ChromotingHost::AddAuthenticatedClient, | |
445 this, connection, connection->session()->config(), | |
446 connection->session()->jid())); | |
447 } | |
448 | |
449 void ChromotingHost::AddAuthenticatedClient( | 414 void ChromotingHost::AddAuthenticatedClient( |
450 scoped_refptr<ConnectionToClient> connection, | 415 ClientSession* client, |
451 const protocol::SessionConfig& config, | 416 const protocol::SessionConfig& config, |
452 const std::string& jid) { | 417 const std::string& jid) { |
453 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); | 418 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); |
454 | 419 |
455 // Disconnect all other clients. | 420 // Disconnect all other clients. |
456 // Iterate over a copy of the list of clients, to avoid mutating the list | 421 // Iterate over a copy of the list of clients, to avoid mutating the list |
457 // while iterating over it. | 422 // while iterating over it. |
458 ClientList clients_copy(clients_); | 423 ClientList clients_copy(clients_); |
459 for (ClientList::const_iterator client = clients_copy.begin(); | 424 for (ClientList::const_iterator other_client = clients_copy.begin(); |
460 client != clients_copy.end(); client++) { | 425 other_client != clients_copy.end(); ++other_client) { |
461 ConnectionToClient* connection_other = client->get()->connection(); | 426 if ((*other_client) != client) { |
462 if (connection_other != connection) { | 427 (*other_client)->Disconnect(); |
463 OnClientDisconnected(connection_other); | 428 OnClientDisconnected(*other_client); |
464 } | 429 } |
465 } | 430 } |
| 431 |
466 // Those disconnections should have killed the screen recorder. | 432 // Those disconnections should have killed the screen recorder. |
467 CHECK(recorder_.get() == NULL); | 433 CHECK(recorder_.get() == NULL); |
468 | 434 |
469 // Create a new RecordSession if there was none. | 435 // Create a new RecordSession if there was none. |
470 if (!recorder_.get()) { | 436 if (!recorder_.get()) { |
471 // Then we create a ScreenRecorder passing the message loops that | 437 // Then we create a ScreenRecorder passing the message loops that |
472 // it should run on. | 438 // it should run on. |
473 Encoder* encoder = CreateEncoder(config); | 439 Encoder* encoder = CreateEncoder(config); |
474 | 440 |
475 recorder_ = new ScreenRecorder(context_->main_message_loop(), | 441 recorder_ = new ScreenRecorder(context_->main_message_loop(), |
476 context_->encode_message_loop(), | 442 context_->encode_message_loop(), |
477 context_->network_message_loop(), | 443 context_->network_message_loop(), |
478 desktop_environment_->capturer(), | 444 desktop_environment_->capturer(), |
479 encoder); | 445 encoder); |
480 } | 446 } |
481 | 447 |
482 // Immediately add the connection and start the session. | 448 // Immediately add the connection and start the session. |
483 recorder_->AddConnection(connection); | 449 recorder_->AddConnection(client->connection()); |
484 recorder_->Start(); | 450 recorder_->Start(); |
485 // Notify observers that there is at least one authenticated client. | 451 // Notify observers that there is at least one authenticated client. |
486 for (StatusObserverList::iterator it = status_observers_.begin(); | 452 for (StatusObserverList::iterator it = status_observers_.begin(); |
487 it != status_observers_.end(); ++it) { | 453 it != status_observers_.end(); ++it) { |
488 (*it)->OnClientAuthenticated(jid); | 454 (*it)->OnClientAuthenticated(jid); |
489 } | 455 } |
490 // TODO(jamiewalch): Tidy up actions to be taken on connect/disconnect, | 456 // TODO(jamiewalch): Tidy up actions to be taken on connect/disconnect, |
491 // including closing the connection on failure of a critical operation. | 457 // including closing the connection on failure of a critical operation. |
492 EnableCurtainMode(true); | 458 EnableCurtainMode(true); |
493 if (is_it2me_) { | 459 if (is_it2me_) { |
494 std::string username = jid; | 460 std::string username = jid; |
495 size_t pos = username.find('/'); | 461 size_t pos = username.find('/'); |
496 if (pos != std::string::npos) | 462 if (pos != std::string::npos) |
497 username.replace(pos, std::string::npos, ""); | 463 username.replace(pos, std::string::npos, ""); |
498 desktop_environment_->OnConnect(username); | 464 desktop_environment_->OnConnect(username); |
499 } | 465 } |
500 } | 466 } |
501 | 467 |
502 void ChromotingHost::ProcessPreAuthentication( | |
503 const scoped_refptr<ConnectionToClient>& connection) { | |
504 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); | |
505 // Find the client session corresponding to the given connection. | |
506 ClientList::iterator client; | |
507 for (client = clients_.begin(); client != clients_.end(); ++client) { | |
508 if (client->get()->connection() == connection) | |
509 break; | |
510 } | |
511 CHECK(client != clients_.end()); | |
512 | |
513 context_->network_message_loop()->PostTask( | |
514 FROM_HERE, base::Bind(&ClientSession::OnAuthenticationComplete, | |
515 client->get())); | |
516 } | |
517 | |
518 void ChromotingHost::StopScreenRecorder() { | 468 void ChromotingHost::StopScreenRecorder() { |
519 DCHECK(MessageLoop::current() == context_->main_message_loop()); | 469 DCHECK(MessageLoop::current() == context_->main_message_loop()); |
520 DCHECK(recorder_.get()); | 470 DCHECK(recorder_.get()); |
521 | 471 |
522 ++stopping_recorders_; | 472 ++stopping_recorders_; |
523 recorder_->Stop(base::Bind(&ChromotingHost::OnScreenRecorderStopped, this)); | 473 recorder_->Stop(base::Bind(&ChromotingHost::OnScreenRecorderStopped, this)); |
524 recorder_ = NULL; | 474 recorder_ = NULL; |
525 } | 475 } |
526 | 476 |
527 void ChromotingHost::OnScreenRecorderStopped() { | 477 void ChromotingHost::OnScreenRecorderStopped() { |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
608 } | 558 } |
609 | 559 |
610 for (std::vector<base::Closure>::iterator it = shutdown_tasks_.begin(); | 560 for (std::vector<base::Closure>::iterator it = shutdown_tasks_.begin(); |
611 it != shutdown_tasks_.end(); ++it) { | 561 it != shutdown_tasks_.end(); ++it) { |
612 it->Run(); | 562 it->Run(); |
613 } | 563 } |
614 shutdown_tasks_.clear(); | 564 shutdown_tasks_.clear(); |
615 } | 565 } |
616 | 566 |
617 } // namespace remoting | 567 } // namespace remoting |
OLD | NEW |