Chromium Code Reviews| Index: remoting/host/chromoting_host.cc |
| diff --git a/remoting/host/chromoting_host.cc b/remoting/host/chromoting_host.cc |
| index a8f4640c65f7a0c51a19a6b4dfef4fa983e4c18a..d751e0bc919e07955102f79be658268114cd441a 100644 |
| --- a/remoting/host/chromoting_host.cc |
| +++ b/remoting/host/chromoting_host.cc |
| @@ -54,8 +54,8 @@ ChromotingHost::ChromotingHost(ChromotingHostContext* context, |
| config_(config), |
| access_verifier_(access_verifier), |
| allow_nat_traversal_(allow_nat_traversal), |
| - state_(kInitial), |
| stopping_recorders_(0), |
| + state_(kInitial), |
| protocol_config_(protocol::CandidateSessionConfig::CreateDefault()), |
| is_curtained_(false), |
| is_it2me_(false) { |
| @@ -78,12 +78,9 @@ void ChromotingHost::Start() { |
| DCHECK(access_verifier_.get()); |
| // Make sure this object is not started. |
| - { |
| - base::AutoLock auto_lock(lock_); |
| - if (state_ != kInitial) |
| - return; |
| - state_ = kStarted; |
| - } |
| + if (state_ != kInitial) |
| + return; |
| + state_ = kStarted; |
| // Use an XMPP connection to the Talk network for session signalling. |
| std::string xmpp_login; |
| @@ -105,37 +102,59 @@ void ChromotingHost::Start() { |
| // This method is called when we need to destroy the host process. |
| void ChromotingHost::Shutdown(Task* shutdown_task) { |
| - if (MessageLoop::current() != context_->main_message_loop()) { |
| - context_->main_message_loop()->PostTask( |
| - FROM_HERE, |
| - base::Bind(&ChromotingHost::Shutdown, this, shutdown_task)); |
| + if (!context_->network_message_loop()->BelongsToCurrentThread()) { |
| + context_->network_message_loop()->PostTask( |
| + FROM_HERE, base::Bind(&ChromotingHost::Shutdown, this, shutdown_task)); |
| return; |
| } |
| // No-op if this object is not started yet. |
| - { |
| - base::AutoLock auto_lock(lock_); |
| - if (state_ == kInitial || state_ == kStopped) { |
| + if (state_ == kInitial || state_ == kStopped) { |
| // Nothing to do if we are not started. |
| - state_ = kStopped; |
| - context_->main_message_loop()->PostTask(FROM_HERE, shutdown_task); |
| - return; |
| - } |
| - if (shutdown_task) |
| - shutdown_tasks_.push_back(shutdown_task); |
| - if (state_ == kStopping) |
| - return; |
| - state_ = kStopping; |
| + state_ = kStopped; |
| + context_->network_message_loop()->PostTask(FROM_HERE, shutdown_task); |
| + return; |
| } |
| + if (shutdown_task) |
| + shutdown_tasks_.push_back(shutdown_task); |
| + if (state_ == kStopping) |
| + return; |
| + state_ = kStopping; |
| // Disconnect all of the clients, implicitly stopping the ScreenRecorder. |
| while (!clients_.empty()) { |
| scoped_refptr<ClientSession> client = clients_.front(); |
| client->Disconnect(); |
| - OnClientDisconnected(client); |
| + OnSessionClosed(client); |
| } |
| - ShutdownNetwork(); |
| + // Stop session manager. |
| + if (session_manager_.get()) { |
| + session_manager_->Close(); |
| + // It may not be safe to delete |session_manager_| here becase |
| + // this method may be invoked in resonse to a libjingle event and |
|
Wez
2011/11/09 23:18:45
typo: resonse
Sergey Ulanov
2011/11/10 21:06:14
Done.
|
| + // libjingle's sigslot doesn't handle it properly, so postpone |
| + // the deletion. |
| + context_->network_message_loop()->DeleteSoon( |
| + FROM_HERE, session_manager_.release()); |
| + } |
| + |
| + // Stop XMPP connection synchronously. |
| + if (signal_strategy_.get()) { |
| + signal_strategy_->Close(); |
| + signal_strategy_.reset(); |
| + |
| + for (StatusObserverList::iterator it = status_observers_.begin(); |
| + it != status_observers_.end(); ++it) { |
| + (*it)->OnSignallingDisconnected(); |
| + } |
| + } |
| + |
| + if (recorder_.get()) { |
| + StopScreenRecorder(); |
| + } else { |
| + ShutdownFinish(); |
| + } |
| } |
| void ChromotingHost::AddStatusObserver(HostStatusObserver* observer) { |
| @@ -147,32 +166,86 @@ void ChromotingHost::AddStatusObserver(HostStatusObserver* observer) { |
| // protocol::ClientSession::EventHandler implementation. |
| void ChromotingHost::OnSessionAuthenticated(ClientSession* client) { |
| DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
| - protocol::Session* session = client->connection()->session(); |
| - context_->main_message_loop()->PostTask( |
| - FROM_HERE, base::Bind(&ChromotingHost::AddAuthenticatedClient, |
| - this, make_scoped_refptr(client), |
| - session->config(), session->jid())); |
| + |
| + // Disconnect all other clients. |
| + // Iterate over a copy of the list of clients, to avoid mutating the list |
| + // while iterating over it. |
| + ClientList clients_copy(clients_); |
| + for (ClientList::const_iterator other_client = clients_copy.begin(); |
| + other_client != clients_copy.end(); ++other_client) { |
| + if ((*other_client) != client) { |
| + (*other_client)->Disconnect(); |
| + OnSessionClosed(*other_client); |
| + } |
| + } |
| + |
| + // Those disconnections should have killed the screen recorder. |
| + CHECK(recorder_.get() == NULL); |
| + |
| + // Create a new RecordSession if there was none. |
| + if (!recorder_.get()) { |
| + // Then we create a ScreenRecorder passing the message loops that |
| + // it should run on. |
| + Encoder* encoder = CreateEncoder(client->connection()->session()->config()); |
| + |
| + recorder_ = new ScreenRecorder(context_->main_message_loop(), |
| + context_->encode_message_loop(), |
| + context_->network_message_loop(), |
| + desktop_environment_->capturer(), |
| + encoder); |
| + } |
| + |
| + // Immediately add the connection and start the session. |
| + recorder_->AddConnection(client->connection()); |
| + recorder_->Start(); |
| + |
| + // Notify observers that there is at least one authenticated client. |
| + const std::string& jid = client->connection()->session()->jid(); |
| + for (StatusObserverList::iterator it = status_observers_.begin(); |
| + it != status_observers_.end(); ++it) { |
| + (*it)->OnClientAuthenticated(jid); |
| + } |
| + // TODO(jamiewalch): Tidy up actions to be taken on connect/disconnect, |
| + // including closing the connection on failure of a critical operation. |
| + EnableCurtainMode(true); |
| + |
| + std::string username = jid.substr(0, jid.find('/')); |
| + desktop_environment_->OnConnect(username); |
| } |
| void ChromotingHost::OnSessionClosed(ClientSession* client) { |
| DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
| - VLOG(1) << "Connection to client closed."; |
| - context_->main_message_loop()->PostTask( |
| - FROM_HERE, base::Bind(&ChromotingHost::OnClientDisconnected, this, |
| - make_scoped_refptr(client))); |
| + scoped_refptr<ClientSession> client_ref = client; |
| + |
| + ClientList::iterator it = std::find(clients_.begin(), clients_.end(), client); |
| + CHECK(it != clients_.end()); |
| + clients_.erase(it); |
| + |
| + if (recorder_.get()) { |
| + recorder_->RemoveConnection(client->connection()); |
| + } |
| + |
| + for (StatusObserverList::iterator it = status_observers_.begin(); |
| + it != status_observers_.end(); ++it) { |
| + (*it)->OnClientDisconnected(client->client_jid()); |
| + } |
| + |
| + if (AuthenticatedClientsCount() == 0) { |
| + if (recorder_.get()) { |
| + // Stop the recorder if there are no more clients. |
| + StopScreenRecorder(); |
| + } |
| + |
| + // Disable the "curtain" if there are no more active clients. |
| + EnableCurtainMode(false); |
| + desktop_environment_->OnLastDisconnect(); |
| + } |
| } |
| void ChromotingHost::OnSessionSequenceNumber(ClientSession* session, |
| int64 sequence_number) { |
| - // Update the sequence number in ScreenRecorder. |
| - if (MessageLoop::current() != context_->main_message_loop()) { |
| - context_->main_message_loop()->PostTask( |
| - FROM_HERE, base::Bind(&ChromotingHost::OnSessionSequenceNumber, this, |
| - make_scoped_refptr(session), sequence_number)); |
| - return; |
| - } |
| - |
| + DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
| if (recorder_.get()) |
| recorder_->UpdateSequenceNumber(sequence_number); |
| } |
| @@ -232,7 +305,6 @@ void ChromotingHost::OnIncomingSession( |
| protocol::SessionManager::IncomingSessionResponse* response) { |
| DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
| - base::AutoLock auto_lock(lock_); |
| if (state_ != kStarted) { |
| *response = protocol::SessionManager::DECLINE; |
| return; |
| @@ -291,16 +363,14 @@ void ChromotingHost::OnIncomingSession( |
| new protocol::ConnectionToClient(context_->network_message_loop(), |
| session); |
| ClientSession* client = new ClientSession( |
| - this, connection, |
| - desktop_environment_->event_executor(), |
| + this, connection, desktop_environment_->event_executor(), |
| desktop_environment_->capturer()); |
| - |
| clients_.push_back(client); |
| } |
| void ChromotingHost::set_protocol_config( |
| protocol::CandidateSessionConfig* config) { |
| - DCHECK(config_.get()); |
| + DCHECK(config); |
| DCHECK_EQ(state_, kInitial); |
| protocol_config_.reset(config); |
| } |
| @@ -311,6 +381,7 @@ void ChromotingHost::LocalMouseMoved(const SkIPoint& new_pos) { |
| FROM_HERE, base::Bind(&ChromotingHost::LocalMouseMoved, this, new_pos)); |
| return; |
| } |
| + |
| ClientList::iterator client; |
| for (client = clients_.begin(); client != clients_.end(); ++client) { |
| client->get()->LocalMouseMoved(new_pos); |
| @@ -318,14 +389,15 @@ void ChromotingHost::LocalMouseMoved(const SkIPoint& new_pos) { |
| } |
| void ChromotingHost::PauseSession(bool pause) { |
| - if (context_->main_message_loop() != MessageLoop::current()) { |
| - context_->main_message_loop()->PostTask( |
| + if (!context_->network_message_loop()->BelongsToCurrentThread()) { |
| + context_->network_message_loop()->PostTask( |
| FROM_HERE, |
| NewRunnableMethod(this, |
| &ChromotingHost::PauseSession, |
| pause)); |
| return; |
| } |
| + |
| ClientList::iterator client; |
| for (client = clients_.begin(); client != clients_.end(); ++client) { |
| client->get()->set_awaiting_continue_approval(pause); |
| @@ -340,39 +412,6 @@ void ChromotingHost::SetUiStrings(const UiStrings& ui_strings) { |
| ui_strings_ = ui_strings; |
| } |
| -void ChromotingHost::OnClientDisconnected(ClientSession* client) { |
| - DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); |
| - |
| - scoped_refptr<ClientSession> client_ref = client; |
| - |
| - ClientList::iterator it; |
| - for (it = clients_.begin(); it != clients_.end(); ++it) { |
| - if (it->get() == client) |
| - break; |
| - } |
| - clients_.erase(it); |
| - |
| - if (recorder_.get()) { |
| - recorder_->RemoveConnection(client->connection()); |
| - } |
| - |
| - for (StatusObserverList::iterator it = status_observers_.begin(); |
| - it != status_observers_.end(); ++it) { |
| - (*it)->OnClientDisconnected(client->client_jid()); |
| - } |
| - |
| - if (AuthenticatedClientsCount() == 0) { |
| - if (recorder_.get()) { |
| - // Stop the recorder if there are no more clients. |
| - StopScreenRecorder(); |
| - } |
| - |
| - // Disable the "curtain" if there are no more active clients. |
| - EnableCurtainMode(false); |
| - desktop_environment_->OnLastDisconnect(); |
| - } |
| -} |
| - |
| // TODO(sergeyu): Move this to SessionManager? |
| Encoder* ChromotingHost::CreateEncoder(const protocol::SessionConfig& config) { |
| const protocol::ChannelConfig& video_config = config.video_config(); |
| @@ -395,6 +434,8 @@ std::string ChromotingHost::GenerateHostAuthToken( |
| } |
| int ChromotingHost::AuthenticatedClientsCount() const { |
| + DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
| + |
| int authenticated_clients = 0; |
| for (ClientList::const_iterator it = clients_.begin(); it != clients_.end(); |
| ++it) { |
| @@ -414,72 +455,19 @@ void ChromotingHost::EnableCurtainMode(bool enable) { |
| is_curtained_ = enable; |
| } |
| -void ChromotingHost::AddAuthenticatedClient( |
| - ClientSession* client, |
| - const protocol::SessionConfig& config, |
| - const std::string& jid) { |
| - DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); |
| - |
| - // Disconnect all other clients. |
| - // Iterate over a copy of the list of clients, to avoid mutating the list |
| - // while iterating over it. |
| - ClientList clients_copy(clients_); |
| - for (ClientList::const_iterator other_client = clients_copy.begin(); |
| - other_client != clients_copy.end(); ++other_client) { |
| - if ((*other_client) != client) { |
| - (*other_client)->Disconnect(); |
| - OnClientDisconnected(*other_client); |
| - } |
| - } |
| - |
| - // Those disconnections should have killed the screen recorder. |
| - CHECK(recorder_.get() == NULL); |
| - |
| - // Create a new RecordSession if there was none. |
| - if (!recorder_.get()) { |
| - // Then we create a ScreenRecorder passing the message loops that |
| - // it should run on. |
| - Encoder* encoder = CreateEncoder(config); |
| - |
| - recorder_ = new ScreenRecorder(context_->main_message_loop(), |
| - context_->encode_message_loop(), |
| - context_->network_message_loop(), |
| - desktop_environment_->capturer(), |
| - encoder); |
| - } |
| - |
| - // Immediately add the connection and start the session. |
| - recorder_->AddConnection(client->connection()); |
| - recorder_->Start(); |
| - // Notify observers that there is at least one authenticated client. |
| - for (StatusObserverList::iterator it = status_observers_.begin(); |
| - it != status_observers_.end(); ++it) { |
| - (*it)->OnClientAuthenticated(jid); |
| - } |
| - // TODO(jamiewalch): Tidy up actions to be taken on connect/disconnect, |
| - // including closing the connection on failure of a critical operation. |
| - EnableCurtainMode(true); |
| - if (is_it2me_) { |
| - std::string username = jid; |
| - size_t pos = username.find('/'); |
| - if (pos != std::string::npos) |
| - username.replace(pos, std::string::npos, ""); |
| - desktop_environment_->OnConnect(username); |
| - } |
| -} |
| - |
| void ChromotingHost::StopScreenRecorder() { |
| - DCHECK(MessageLoop::current() == context_->main_message_loop()); |
| + DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
| DCHECK(recorder_.get()); |
| ++stopping_recorders_; |
| - recorder_->Stop(base::Bind(&ChromotingHost::OnScreenRecorderStopped, this)); |
| + scoped_refptr<ScreenRecorder> recorder = recorder_; |
| recorder_ = NULL; |
| + recorder->Stop(base::Bind(&ChromotingHost::OnScreenRecorderStopped, this)); |
| } |
| void ChromotingHost::OnScreenRecorderStopped() { |
| - if (MessageLoop::current() != context_->main_message_loop()) { |
| - context_->main_message_loop()->PostTask( |
| + if (!context_->network_message_loop()->BelongsToCurrentThread()) { |
| + context_->network_message_loop()->PostTask( |
| FROM_HERE, base::Bind(&ChromotingHost::OnScreenRecorderStopped, this)); |
| return; |
| } |
| @@ -487,68 +475,14 @@ void ChromotingHost::OnScreenRecorderStopped() { |
| --stopping_recorders_; |
| DCHECK_GE(stopping_recorders_, 0); |
| - bool stopping; |
| - { |
| - base::AutoLock auto_lock(lock_); |
| - stopping = state_ == kStopping; |
| - } |
| - |
| - if (!stopping_recorders_ && stopping) |
| + if (!stopping_recorders_ && state_ == kStopping) |
| ShutdownFinish(); |
| } |
| -void ChromotingHost::ShutdownNetwork() { |
| - if (!context_->network_message_loop()->BelongsToCurrentThread()) { |
| - context_->network_message_loop()->PostTask( |
| - FROM_HERE, base::Bind(&ChromotingHost::ShutdownNetwork, this)); |
| - return; |
| - } |
| - |
| - // Stop chromotocol session manager. |
| - if (session_manager_.get()) { |
| - session_manager_->Close(); |
| - session_manager_.reset(); |
| - } |
| - |
| - // Stop XMPP connection. |
| - if (signal_strategy_.get()) { |
| - signal_strategy_->Close(); |
| - signal_strategy_.reset(); |
| - |
| - for (StatusObserverList::iterator it = status_observers_.begin(); |
| - it != status_observers_.end(); ++it) { |
| - (*it)->OnSignallingDisconnected(); |
| - } |
| - } |
| - |
| - ShutdownRecorder(); |
| -} |
| - |
| -void ChromotingHost::ShutdownRecorder() { |
| - if (MessageLoop::current() != context_->main_message_loop()) { |
| - context_->main_message_loop()->PostTask( |
| - FROM_HERE, base::Bind(&ChromotingHost::ShutdownRecorder, this)); |
| - return; |
| - } |
| - |
| - if (recorder_.get()) { |
| - StopScreenRecorder(); |
| - } else if (!stopping_recorders_) { |
| - ShutdownFinish(); |
| - } |
| -} |
| - |
| void ChromotingHost::ShutdownFinish() { |
| - if (MessageLoop::current() != context_->main_message_loop()) { |
| - context_->main_message_loop()->PostTask( |
| - FROM_HERE, base::Bind(&ChromotingHost::ShutdownFinish, this)); |
| - return; |
| - } |
| + DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
| - { |
| - base::AutoLock auto_lock(lock_); |
| - state_ = kStopped; |
| - } |
| + state_ = kStopped; |
| // Keep reference to |this|, so that we don't get destroyed while |
| // sending notifications. |