| Index: remoting/host/chromoting_host.cc
|
| diff --git a/remoting/host/chromoting_host.cc b/remoting/host/chromoting_host.cc
|
| index de8c78d163f22bb06a06383bf5fb6c54735de4fd..e23102b03791f4342eb1b0ee403842800370440e 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,57 @@ void ChromotingHost::Start() {
|
|
|
| // This method is called when we need to destroy the host process.
|
| void ChromotingHost::Shutdown(const base::Closure& 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.is_null())
|
| - 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.is_null())
|
| + 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);
|
| + clients_.front()->Disconnect();
|
| + }
|
| +
|
| + // 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 response to a libjingle event and
|
| + // libjingle's sigslot doesn't handle it properly, so postpone the
|
| + // deletion.
|
| + context_->network_message_loop()->DeleteSoon(
|
| + FROM_HERE, session_manager_.release());
|
| }
|
|
|
| - ShutdownNetwork();
|
| + // 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 +164,82 @@ 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();
|
| + }
|
| + }
|
| +
|
| + // 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 +299,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 +357,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 +375,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,11 +383,12 @@ 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, base::Bind(&ChromotingHost::PauseSession, this, pause));
|
| return;
|
| }
|
| +
|
| ClientList::iterator client;
|
| for (client = clients_.begin(); client != clients_.end(); ++client) {
|
| client->get()->set_awaiting_continue_approval(pause);
|
| @@ -337,39 +403,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();
|
| @@ -392,6 +425,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) {
|
| @@ -411,72 +446,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;
|
| }
|
| @@ -484,68 +466,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.
|
|
|