Chromium Code Reviews| 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) | 124 if (shutdown_task) |
| 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); | |
|
Wez
2011/11/09 01:35:07
It seems strange that client->Disconnect() doesn't
Sergey Ulanov
2011/11/09 19:26:13
That is intentional. I think the code is simpler w
Wez
2011/11/09 23:34:50
I think it's different in this case. ChromotingHo
Sergey Ulanov
2011/11/10 00:55:57
I agree that it may not be a problem in this parti
Wez
2011/11/10 01:25:12
The caller can't touch the session object after Di
| |
| 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 26 matching lines...) Expand all Loading... | |
| 344 desktop_environment_->OnPause(pause); | 333 desktop_environment_->OnPause(pause); |
| 345 } | 334 } |
| 346 | 335 |
| 347 void ChromotingHost::SetUiStrings(const UiStrings& ui_strings) { | 336 void ChromotingHost::SetUiStrings(const UiStrings& ui_strings) { |
| 348 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); | 337 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); |
| 349 DCHECK_EQ(state_, kInitial); | 338 DCHECK_EQ(state_, kInitial); |
| 350 | 339 |
| 351 ui_strings_ = ui_strings; | 340 ui_strings_ = ui_strings; |
| 352 } | 341 } |
| 353 | 342 |
| 354 void ChromotingHost::OnClientDisconnected(ConnectionToClient* connection) { | 343 void ChromotingHost::OnClientDisconnected(ClientSession* client) { |
| 355 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); | 344 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); |
| 356 | 345 |
| 357 // Find the client session corresponding to the given connection. | 346 scoped_refptr<ClientSession> client_ref = client; |
| 347 | |
| 358 ClientList::iterator it; | 348 ClientList::iterator it; |
| 359 for (it = clients_.begin(); it != clients_.end(); ++it) { | 349 for (it = clients_.begin(); it != clients_.end(); ++it) { |
| 360 if (it->get()->connection() == connection) | 350 if (it->get() == client) |
| 361 break; | 351 break; |
| 362 } | 352 } |
| 363 if (it == clients_.end()) | |
| 364 return; | |
| 365 | |
| 366 scoped_refptr<ClientSession> client = *it; | |
| 367 | |
| 368 clients_.erase(it); | 353 clients_.erase(it); |
| 369 | 354 |
| 370 if (recorder_.get()) { | 355 if (recorder_.get()) { |
| 371 recorder_->RemoveConnection(connection); | 356 recorder_->RemoveConnection(client->connection()); |
| 372 } | 357 } |
| 373 | 358 |
| 374 // Close the connection to client just to be safe. | |
| 375 // TODO(garykac): This should be removed when we revisit our shutdown and | |
| 376 // disconnect code. This should only need to be done in | |
| 377 // ClientSession::Disconnect(). | |
| 378 connection->Disconnect(); | |
| 379 | |
| 380 for (StatusObserverList::iterator it = status_observers_.begin(); | 359 for (StatusObserverList::iterator it = status_observers_.begin(); |
| 381 it != status_observers_.end(); ++it) { | 360 it != status_observers_.end(); ++it) { |
| 382 (*it)->OnClientDisconnected(client->client_jid()); | 361 (*it)->OnClientDisconnected(client->client_jid()); |
| 383 } | 362 } |
| 384 | 363 |
| 385 if (AuthenticatedClientsCount() == 0) { | 364 if (AuthenticatedClientsCount() == 0) { |
| 386 if (recorder_.get()) { | 365 if (recorder_.get()) { |
| 387 // Stop the recorder if there are no more clients. | 366 // Stop the recorder if there are no more clients. |
| 388 StopScreenRecorder(); | 367 StopScreenRecorder(); |
| 389 } | 368 } |
| 390 | 369 |
| 391 // Disable the "curtain" if there are no more active clients. | 370 // Disable the "curtain" if there are no more active clients. |
| 392 EnableCurtainMode(false); | 371 EnableCurtainMode(false); |
| 393 if (is_it2me_) { | 372 desktop_environment_->OnLastDisconnect(); |
| 394 desktop_environment_->OnLastDisconnect(); | |
| 395 } | |
| 396 } | 373 } |
| 397 | |
| 398 client->OnDisconnected(); | |
| 399 } | 374 } |
| 400 | 375 |
| 401 // TODO(sergeyu): Move this to SessionManager? | 376 // TODO(sergeyu): Move this to SessionManager? |
| 402 Encoder* ChromotingHost::CreateEncoder(const protocol::SessionConfig& config) { | 377 Encoder* ChromotingHost::CreateEncoder(const protocol::SessionConfig& config) { |
| 403 const protocol::ChannelConfig& video_config = config.video_config(); | 378 const protocol::ChannelConfig& video_config = config.video_config(); |
| 404 | 379 |
| 405 if (video_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) { | 380 if (video_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) { |
| 406 return EncoderRowBased::CreateVerbatimEncoder(); | 381 return EncoderRowBased::CreateVerbatimEncoder(); |
| 407 } else if (video_config.codec == protocol::ChannelConfig::CODEC_ZIP) { | 382 } else if (video_config.codec == protocol::ChannelConfig::CODEC_ZIP) { |
| 408 return EncoderRowBased::CreateZlibEncoder(); | 383 return EncoderRowBased::CreateZlibEncoder(); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 432 void ChromotingHost::EnableCurtainMode(bool enable) { | 407 void ChromotingHost::EnableCurtainMode(bool enable) { |
| 433 // TODO(jamiewalch): This will need to be more sophisticated when we think | 408 // TODO(jamiewalch): This will need to be more sophisticated when we think |
| 434 // about proper crash recovery and daemon mode. | 409 // about proper crash recovery and daemon mode. |
| 435 // TODO(wez): CurtainMode shouldn't be driven directly by ChromotingHost. | 410 // TODO(wez): CurtainMode shouldn't be driven directly by ChromotingHost. |
| 436 if (is_it2me_ || enable == is_curtained_) | 411 if (is_it2me_ || enable == is_curtained_) |
| 437 return; | 412 return; |
| 438 desktop_environment_->curtain()->EnableCurtainMode(enable); | 413 desktop_environment_->curtain()->EnableCurtainMode(enable); |
| 439 is_curtained_ = enable; | 414 is_curtained_ = enable; |
| 440 } | 415 } |
| 441 | 416 |
| 442 void ChromotingHost::OnAuthenticationComplete( | |
| 443 scoped_refptr<ConnectionToClient> connection) { | |
| 444 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); | |
| 445 | |
| 446 context_->main_message_loop()->PostTask( | |
| 447 FROM_HERE, base::Bind(&ChromotingHost::AddAuthenticatedClient, | |
| 448 this, connection, connection->session()->config(), | |
| 449 connection->session()->jid())); | |
| 450 } | |
| 451 | |
| 452 void ChromotingHost::AddAuthenticatedClient( | 417 void ChromotingHost::AddAuthenticatedClient( |
| 453 scoped_refptr<ConnectionToClient> connection, | 418 ClientSession* client, |
| 454 const protocol::SessionConfig& config, | 419 const protocol::SessionConfig& config, |
| 455 const std::string& jid) { | 420 const std::string& jid) { |
| 456 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); | 421 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); |
| 457 | 422 |
| 458 // Disconnect all other clients. | 423 // Disconnect all other clients. |
| 459 // Iterate over a copy of the list of clients, to avoid mutating the list | 424 // Iterate over a copy of the list of clients, to avoid mutating the list |
| 460 // while iterating over it. | 425 // while iterating over it. |
| 461 ClientList clients_copy(clients_); | 426 ClientList clients_copy(clients_); |
| 462 for (ClientList::const_iterator client = clients_copy.begin(); | 427 for (ClientList::const_iterator other_client = clients_copy.begin(); |
| 463 client != clients_copy.end(); client++) { | 428 other_client != clients_copy.end(); ++other_client) { |
| 464 ConnectionToClient* connection_other = client->get()->connection(); | 429 if ((*other_client) != client) { |
| 465 if (connection_other != connection) { | 430 (*other_client)->Disconnect(); |
| 466 OnClientDisconnected(connection_other); | 431 OnClientDisconnected(*other_client); |
| 467 } | 432 } |
| 468 } | 433 } |
| 434 | |
| 469 // Those disconnections should have killed the screen recorder. | 435 // Those disconnections should have killed the screen recorder. |
| 470 CHECK(recorder_.get() == NULL); | 436 CHECK(recorder_.get() == NULL); |
| 471 | 437 |
| 472 // Create a new RecordSession if there was none. | 438 // Create a new RecordSession if there was none. |
| 473 if (!recorder_.get()) { | 439 if (!recorder_.get()) { |
| 474 // Then we create a ScreenRecorder passing the message loops that | 440 // Then we create a ScreenRecorder passing the message loops that |
| 475 // it should run on. | 441 // it should run on. |
| 476 Encoder* encoder = CreateEncoder(config); | 442 Encoder* encoder = CreateEncoder(config); |
| 477 | 443 |
| 478 recorder_ = new ScreenRecorder(context_->main_message_loop(), | 444 recorder_ = new ScreenRecorder(context_->main_message_loop(), |
| 479 context_->encode_message_loop(), | 445 context_->encode_message_loop(), |
| 480 context_->network_message_loop(), | 446 context_->network_message_loop(), |
| 481 desktop_environment_->capturer(), | 447 desktop_environment_->capturer(), |
| 482 encoder); | 448 encoder); |
| 483 } | 449 } |
| 484 | 450 |
| 485 // Immediately add the connection and start the session. | 451 // Immediately add the connection and start the session. |
| 486 recorder_->AddConnection(connection); | 452 recorder_->AddConnection(client->connection()); |
| 487 recorder_->Start(); | 453 recorder_->Start(); |
| 488 // Notify observers that there is at least one authenticated client. | 454 // Notify observers that there is at least one authenticated client. |
| 489 for (StatusObserverList::iterator it = status_observers_.begin(); | 455 for (StatusObserverList::iterator it = status_observers_.begin(); |
| 490 it != status_observers_.end(); ++it) { | 456 it != status_observers_.end(); ++it) { |
| 491 (*it)->OnClientAuthenticated(jid); | 457 (*it)->OnClientAuthenticated(jid); |
| 492 } | 458 } |
| 493 // TODO(jamiewalch): Tidy up actions to be taken on connect/disconnect, | 459 // TODO(jamiewalch): Tidy up actions to be taken on connect/disconnect, |
| 494 // including closing the connection on failure of a critical operation. | 460 // including closing the connection on failure of a critical operation. |
| 495 EnableCurtainMode(true); | 461 EnableCurtainMode(true); |
| 496 if (is_it2me_) { | 462 if (is_it2me_) { |
| 497 std::string username = jid; | 463 std::string username = jid; |
| 498 size_t pos = username.find('/'); | 464 size_t pos = username.find('/'); |
| 499 if (pos != std::string::npos) | 465 if (pos != std::string::npos) |
| 500 username.replace(pos, std::string::npos, ""); | 466 username.replace(pos, std::string::npos, ""); |
| 501 desktop_environment_->OnConnect(username); | 467 desktop_environment_->OnConnect(username); |
| 502 } | 468 } |
| 503 } | 469 } |
| 504 | 470 |
| 505 void ChromotingHost::ProcessPreAuthentication( | |
| 506 const scoped_refptr<ConnectionToClient>& connection) { | |
| 507 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); | |
| 508 // Find the client session corresponding to the given connection. | |
| 509 ClientList::iterator client; | |
| 510 for (client = clients_.begin(); client != clients_.end(); ++client) { | |
| 511 if (client->get()->connection() == connection) | |
| 512 break; | |
| 513 } | |
| 514 CHECK(client != clients_.end()); | |
| 515 | |
| 516 context_->network_message_loop()->PostTask( | |
| 517 FROM_HERE, base::Bind(&ClientSession::OnAuthenticationComplete, | |
| 518 client->get())); | |
| 519 } | |
| 520 | |
| 521 void ChromotingHost::StopScreenRecorder() { | 471 void ChromotingHost::StopScreenRecorder() { |
| 522 DCHECK(MessageLoop::current() == context_->main_message_loop()); | 472 DCHECK(MessageLoop::current() == context_->main_message_loop()); |
| 523 DCHECK(recorder_.get()); | 473 DCHECK(recorder_.get()); |
| 524 | 474 |
| 525 ++stopping_recorders_; | 475 ++stopping_recorders_; |
| 526 recorder_->Stop(base::Bind(&ChromotingHost::OnScreenRecorderStopped, this)); | 476 recorder_->Stop(base::Bind(&ChromotingHost::OnScreenRecorderStopped, this)); |
| 527 recorder_ = NULL; | 477 recorder_ = NULL; |
| 528 } | 478 } |
| 529 | 479 |
| 530 void ChromotingHost::OnScreenRecorderStopped() { | 480 void ChromotingHost::OnScreenRecorderStopped() { |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 612 | 562 |
| 613 for (std::vector<Task*>::iterator it = shutdown_tasks_.begin(); | 563 for (std::vector<Task*>::iterator it = shutdown_tasks_.begin(); |
| 614 it != shutdown_tasks_.end(); ++it) { | 564 it != shutdown_tasks_.end(); ++it) { |
| 615 (*it)->Run(); | 565 (*it)->Run(); |
| 616 delete *it; | 566 delete *it; |
| 617 } | 567 } |
| 618 shutdown_tasks_.clear(); | 568 shutdown_tasks_.clear(); |
| 619 } | 569 } |
| 620 | 570 |
| 621 } // namespace remoting | 571 } // namespace remoting |
| OLD | NEW |