| 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 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 293 // Provide the Access Code as shared secret for SSL channel authentication. | 293 // Provide the Access Code as shared secret for SSL channel authentication. |
| 294 session->set_shared_secret(access_code_); | 294 session->set_shared_secret(access_code_); |
| 295 | 295 |
| 296 *response = protocol::SessionManager::ACCEPT; | 296 *response = protocol::SessionManager::ACCEPT; |
| 297 | 297 |
| 298 LOG(INFO) << "Client connected: " << session->jid(); | 298 LOG(INFO) << "Client connected: " << session->jid(); |
| 299 | 299 |
| 300 // We accept the connection, so create a connection object. | 300 // We accept the connection, so create a connection object. |
| 301 ConnectionToClient* connection = new ConnectionToClient( | 301 ConnectionToClient* connection = new ConnectionToClient( |
| 302 context_->network_message_loop(), this); | 302 context_->network_message_loop(), this); |
| 303 connection->Init(session); |
| 303 | 304 |
| 304 // Create a client object. | 305 // Create a client object. |
| 305 ClientSession* client = new ClientSession( | 306 ClientSession* client = new ClientSession( |
| 306 this, | 307 this, |
| 307 UserAuthenticator::Create(), | 308 UserAuthenticator::Create(), |
| 308 connection, | 309 connection, |
| 309 desktop_environment_->event_executor()); | 310 desktop_environment_->event_executor()); |
| 310 connection->set_host_stub(client); | 311 connection->set_host_stub(client); |
| 311 connection->set_input_stub(client); | 312 connection->set_input_stub(client); |
| 312 | 313 |
| 313 connection->Init(session); | |
| 314 | |
| 315 clients_.push_back(client); | 314 clients_.push_back(client); |
| 316 } | 315 } |
| 317 | 316 |
| 318 void ChromotingHost::set_protocol_config( | 317 void ChromotingHost::set_protocol_config( |
| 319 protocol::CandidateSessionConfig* config) { | 318 protocol::CandidateSessionConfig* config) { |
| 320 DCHECK(config_.get()); | 319 DCHECK(config_.get()); |
| 321 DCHECK_EQ(state_, kInitial); | 320 DCHECK_EQ(state_, kInitial); |
| 322 protocol_config_.reset(config); | 321 protocol_config_.reset(config); |
| 323 } | 322 } |
| 324 | 323 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 354 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); | 353 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); |
| 355 DCHECK_EQ(state_, kInitial); | 354 DCHECK_EQ(state_, kInitial); |
| 356 | 355 |
| 357 ui_strings_ = ui_strings; | 356 ui_strings_ = ui_strings; |
| 358 } | 357 } |
| 359 | 358 |
| 360 void ChromotingHost::OnClientDisconnected(ConnectionToClient* connection) { | 359 void ChromotingHost::OnClientDisconnected(ConnectionToClient* connection) { |
| 361 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); | 360 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); |
| 362 | 361 |
| 363 // Find the client session corresponding to the given connection. | 362 // Find the client session corresponding to the given connection. |
| 364 ClientList::iterator client; | 363 ClientList::iterator it; |
| 365 for (client = clients_.begin(); client != clients_.end(); ++client) { | 364 for (it = clients_.begin(); it != clients_.end(); ++it) { |
| 366 if (client->get()->connection() == connection) | 365 if (it->get()->connection() == connection) |
| 367 break; | 366 break; |
| 368 } | 367 } |
| 369 if (client == clients_.end()) | 368 if (it == clients_.end()) |
| 370 return; | 369 return; |
| 371 | 370 |
| 372 // Remove the connection from the session manager and stop the session. | 371 scoped_refptr<ClientSession> client = *it; |
| 373 // TODO(hclam): Stop only if the last connection disconnected. | 372 |
| 373 clients_.erase(it); |
| 374 |
| 374 if (recorder_.get()) { | 375 if (recorder_.get()) { |
| 375 recorder_->RemoveConnection(connection); | 376 recorder_->RemoveConnection(connection); |
| 376 // The recorder only exists to serve the unique authenticated client. | |
| 377 // If that client has disconnected, then we can kill the recorder. | |
| 378 if (client->get()->authenticated()) | |
| 379 StopScreenRecorder(); | |
| 380 } | 377 } |
| 381 | 378 |
| 382 // Close the connection to client just to be safe. | 379 // Close the connection to client just to be safe. |
| 383 connection->Disconnect(); | 380 connection->Disconnect(); |
| 384 | 381 |
| 385 // Also remove reference to ConnectionToClient from this object. | 382 if (client->authenticated()) { |
| 386 int old_authenticated_clients = AuthenticatedClientsCount(); | |
| 387 clients_.erase(client); | |
| 388 | |
| 389 // Notify the observers of the change, if any. | |
| 390 int authenticated_clients = AuthenticatedClientsCount(); | |
| 391 if (old_authenticated_clients != authenticated_clients) { | |
| 392 for (StatusObserverList::iterator it = status_observers_.begin(); | 383 for (StatusObserverList::iterator it = status_observers_.begin(); |
| 393 it != status_observers_.end(); ++it) { | 384 it != status_observers_.end(); ++it) { |
| 394 (*it)->OnClientDisconnected(connection); | 385 (*it)->OnClientDisconnected(client->client_jid()); |
| 395 } | 386 } |
| 396 } | 387 } |
| 397 | 388 |
| 398 // Disable the "curtain" if there are no more active clients. | |
| 399 if (AuthenticatedClientsCount() == 0) { | 389 if (AuthenticatedClientsCount() == 0) { |
| 390 if (recorder_.get()) { |
| 391 // Stop the recorder if there are no more clients. |
| 392 StopScreenRecorder(); |
| 393 } |
| 394 |
| 395 // Disable the "curtain" if there are no more active clients. |
| 400 EnableCurtainMode(false); | 396 EnableCurtainMode(false); |
| 401 if (is_it2me_) { | 397 if (is_it2me_) { |
| 402 desktop_environment_->OnLastDisconnect(); | 398 desktop_environment_->OnLastDisconnect(); |
| 403 } | 399 } |
| 404 } | 400 } |
| 405 } | 401 } |
| 406 | 402 |
| 407 // TODO(sergeyu): Move this to SessionManager? | 403 // TODO(sergeyu): Move this to SessionManager? |
| 408 Encoder* ChromotingHost::CreateEncoder(const protocol::SessionConfig& config) { | 404 Encoder* ChromotingHost::CreateEncoder(const protocol::SessionConfig& config) { |
| 409 const protocol::ChannelConfig& video_config = config.video_config(); | 405 const protocol::ChannelConfig& video_config = config.video_config(); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 440 // about proper crash recovery and daemon mode. | 436 // about proper crash recovery and daemon mode. |
| 441 // TODO(wez): CurtainMode shouldn't be driven directly by ChromotingHost. | 437 // TODO(wez): CurtainMode shouldn't be driven directly by ChromotingHost. |
| 442 if (is_it2me_ || enable == is_curtained_) | 438 if (is_it2me_ || enable == is_curtained_) |
| 443 return; | 439 return; |
| 444 desktop_environment_->curtain()->EnableCurtainMode(enable); | 440 desktop_environment_->curtain()->EnableCurtainMode(enable); |
| 445 is_curtained_ = enable; | 441 is_curtained_ = enable; |
| 446 } | 442 } |
| 447 | 443 |
| 448 void ChromotingHost::LocalLoginSucceeded( | 444 void ChromotingHost::LocalLoginSucceeded( |
| 449 scoped_refptr<ConnectionToClient> connection) { | 445 scoped_refptr<ConnectionToClient> connection) { |
| 450 if (MessageLoop::current() != context_->main_message_loop()) { | 446 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
| 451 context_->main_message_loop()->PostTask( | 447 |
| 452 FROM_HERE, base::Bind(&ChromotingHost::LocalLoginSucceeded, this, | 448 context_->main_message_loop()->PostTask( |
| 453 connection)); | 449 FROM_HERE, base::Bind(&ChromotingHost::AddAuthenticatedClient, |
| 454 return; | 450 this, connection, connection->session()->config(), |
| 455 } | 451 connection->session()->jid())); |
| 452 } |
| 453 |
| 454 void ChromotingHost::AddAuthenticatedClient( |
| 455 scoped_refptr<ConnectionToClient> connection, |
| 456 const protocol::SessionConfig& config, |
| 457 const std::string& jid) { |
| 458 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); |
| 456 | 459 |
| 457 protocol::LocalLoginStatus* status = new protocol::LocalLoginStatus(); | 460 protocol::LocalLoginStatus* status = new protocol::LocalLoginStatus(); |
| 458 status->set_success(true); | 461 status->set_success(true); |
| 459 connection->client_stub()->BeginSessionResponse( | 462 connection->client_stub()->BeginSessionResponse( |
| 460 status, new DeleteTask<protocol::LocalLoginStatus>(status)); | 463 status, new DeleteTask<protocol::LocalLoginStatus>(status)); |
| 461 | 464 |
| 462 // Disconnect all other clients. | 465 // Disconnect all other clients. |
| 463 // Iterate over a copy of the list of clients, to avoid mutating the list | 466 // Iterate over a copy of the list of clients, to avoid mutating the list |
| 464 // while iterating over it. | 467 // while iterating over it. |
| 465 ClientList clients_copy(clients_); | 468 ClientList clients_copy(clients_); |
| 466 for (ClientList::const_iterator client = clients_copy.begin(); | 469 for (ClientList::const_iterator client = clients_copy.begin(); |
| 467 client != clients_copy.end(); client++) { | 470 client != clients_copy.end(); client++) { |
| 468 ConnectionToClient* connection_other = client->get()->connection(); | 471 ConnectionToClient* connection_other = client->get()->connection(); |
| 469 if (connection_other != connection) { | 472 if (connection_other != connection) { |
| 470 OnClientDisconnected(connection_other); | 473 OnClientDisconnected(connection_other); |
| 471 } | 474 } |
| 472 } | 475 } |
| 473 // Those disconnections should have killed the screen recorder. | 476 // Those disconnections should have killed the screen recorder. |
| 474 CHECK(recorder_.get() == NULL); | 477 CHECK(recorder_.get() == NULL); |
| 475 | 478 |
| 476 // Create a new RecordSession if there was none. | 479 // Create a new RecordSession if there was none. |
| 477 if (!recorder_.get()) { | 480 if (!recorder_.get()) { |
| 478 // Then we create a ScreenRecorder passing the message loops that | 481 // Then we create a ScreenRecorder passing the message loops that |
| 479 // it should run on. | 482 // it should run on. |
| 480 Encoder* encoder = CreateEncoder(connection->session()->config()); | 483 Encoder* encoder = CreateEncoder(config); |
| 481 | 484 |
| 482 recorder_ = new ScreenRecorder(context_->main_message_loop(), | 485 recorder_ = new ScreenRecorder(context_->main_message_loop(), |
| 483 context_->encode_message_loop(), | 486 context_->encode_message_loop(), |
| 484 context_->network_message_loop(), | 487 context_->network_message_loop(), |
| 485 desktop_environment_->capturer(), | 488 desktop_environment_->capturer(), |
| 486 encoder); | 489 encoder); |
| 487 } | 490 } |
| 488 | 491 |
| 489 // Immediately add the connection and start the session. | 492 // Immediately add the connection and start the session. |
| 490 recorder_->AddConnection(connection); | 493 recorder_->AddConnection(connection); |
| 491 recorder_->Start(); | 494 recorder_->Start(); |
| 492 // Notify observers that there is at least one authenticated client. | 495 // Notify observers that there is at least one authenticated client. |
| 493 for (StatusObserverList::iterator it = status_observers_.begin(); | 496 for (StatusObserverList::iterator it = status_observers_.begin(); |
| 494 it != status_observers_.end(); ++it) { | 497 it != status_observers_.end(); ++it) { |
| 495 (*it)->OnClientAuthenticated(connection); | 498 (*it)->OnClientAuthenticated(jid); |
| 496 } | 499 } |
| 497 // TODO(jamiewalch): Tidy up actions to be taken on connect/disconnect, | 500 // TODO(jamiewalch): Tidy up actions to be taken on connect/disconnect, |
| 498 // including closing the connection on failure of a critical operation. | 501 // including closing the connection on failure of a critical operation. |
| 499 EnableCurtainMode(true); | 502 EnableCurtainMode(true); |
| 500 if (is_it2me_) { | 503 if (is_it2me_) { |
| 501 std::string username = connection->session()->jid(); | 504 std::string username = jid; |
| 502 size_t pos = username.find('/'); | 505 size_t pos = username.find('/'); |
| 503 if (pos != std::string::npos) | 506 if (pos != std::string::npos) |
| 504 username.replace(pos, std::string::npos, ""); | 507 username.replace(pos, std::string::npos, ""); |
| 505 desktop_environment_->OnConnect(username); | 508 desktop_environment_->OnConnect(username); |
| 506 } | 509 } |
| 507 } | 510 } |
| 508 | 511 |
| 509 void ChromotingHost::LocalLoginFailed( | 512 void ChromotingHost::LocalLoginFailed( |
| 510 scoped_refptr<ConnectionToClient> connection) { | 513 scoped_refptr<ConnectionToClient> connection) { |
| 511 if (MessageLoop::current() != context_->main_message_loop()) { | 514 if (MessageLoop::current() != context_->main_message_loop()) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 524 void ChromotingHost::ProcessPreAuthentication( | 527 void ChromotingHost::ProcessPreAuthentication( |
| 525 const scoped_refptr<ConnectionToClient>& connection) { | 528 const scoped_refptr<ConnectionToClient>& connection) { |
| 526 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); | 529 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); |
| 527 // Find the client session corresponding to the given connection. | 530 // Find the client session corresponding to the given connection. |
| 528 ClientList::iterator client; | 531 ClientList::iterator client; |
| 529 for (client = clients_.begin(); client != clients_.end(); ++client) { | 532 for (client = clients_.begin(); client != clients_.end(); ++client) { |
| 530 if (client->get()->connection() == connection) | 533 if (client->get()->connection() == connection) |
| 531 break; | 534 break; |
| 532 } | 535 } |
| 533 CHECK(client != clients_.end()); | 536 CHECK(client != clients_.end()); |
| 534 client->get()->OnAuthorizationComplete(true); | 537 |
| 538 context_->network_message_loop()->PostTask( |
| 539 FROM_HERE, base::Bind(&ClientSession::OnAuthorizationComplete, |
| 540 client->get(), true)); |
| 535 } | 541 } |
| 536 | 542 |
| 537 void ChromotingHost::StopScreenRecorder() { | 543 void ChromotingHost::StopScreenRecorder() { |
| 538 DCHECK(MessageLoop::current() == context_->main_message_loop()); | 544 DCHECK(MessageLoop::current() == context_->main_message_loop()); |
| 539 DCHECK(recorder_.get()); | 545 DCHECK(recorder_.get()); |
| 540 | 546 |
| 541 ++stopping_recorders_; | 547 ++stopping_recorders_; |
| 542 recorder_->Stop(base::Bind(&ChromotingHost::OnScreenRecorderStopped, this)); | 548 recorder_->Stop(base::Bind(&ChromotingHost::OnScreenRecorderStopped, this)); |
| 543 recorder_ = NULL; | 549 recorder_ = NULL; |
| 544 } | 550 } |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 628 | 634 |
| 629 for (std::vector<Task*>::iterator it = shutdown_tasks_.begin(); | 635 for (std::vector<Task*>::iterator it = shutdown_tasks_.begin(); |
| 630 it != shutdown_tasks_.end(); ++it) { | 636 it != shutdown_tasks_.end(); ++it) { |
| 631 (*it)->Run(); | 637 (*it)->Run(); |
| 632 delete *it; | 638 delete *it; |
| 633 } | 639 } |
| 634 shutdown_tasks_.clear(); | 640 shutdown_tasks_.clear(); |
| 635 } | 641 } |
| 636 | 642 |
| 637 } // namespace remoting | 643 } // namespace remoting |
| OLD | NEW |