Index: remoting/host/chromoting_host.cc |
diff --git a/remoting/host/chromoting_host.cc b/remoting/host/chromoting_host.cc |
index df778482af73b31d566b5892ca39328ba9e5b60d..6b5803ee872972772b43e30c8c3649ae7d2f5627 100644 |
--- a/remoting/host/chromoting_host.cc |
+++ b/remoting/host/chromoting_host.cc |
@@ -57,7 +57,6 @@ ChromotingHost::ChromotingHost(ChromotingHostContext* context, |
state_(kInitial), |
protocol_config_(protocol::CandidateSessionConfig::CreateDefault()) { |
DCHECK(desktop_environment_.get()); |
- desktop_environment_->set_event_handler(this); |
} |
ChromotingHost::~ChromotingHost() { |
@@ -140,10 +139,11 @@ void ChromotingHost::Shutdown() { |
recorder_->RemoveAllConnections(); |
} |
- // Disconnect the client. |
- if (connection_) { |
- connection_->Disconnect(); |
+ // Disconnect the clients. |
+ for (size_t i = 0; i < clients_.size(); i++) { |
+ clients_[i]->Disconnect(); |
} |
+ clients_.clear(); |
// Stop the heartbeat sender. |
if (heartbeat_sender_) { |
@@ -172,24 +172,6 @@ void ChromotingHost::Shutdown() { |
// This method is called when a client connects. |
void ChromotingHost::OnClientConnected(ConnectionToClient* connection) { |
DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); |
- |
- // 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. |
- DCHECK(desktop_environment_->capturer()); |
- |
- Encoder* encoder = CreateEncoder(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(connection); |
} |
void ChromotingHost::OnClientDisconnected(ConnectionToClient* connection) { |
@@ -199,15 +181,25 @@ void ChromotingHost::OnClientDisconnected(ConnectionToClient* connection) { |
// TODO(hclam): Stop only if the last connection disconnected. |
if (recorder_.get()) { |
recorder_->RemoveConnection(connection); |
- recorder_->Stop(NULL); |
- recorder_ = NULL; |
+ // The recorder only exists to serve the unique authenticated client. |
+ // If that client has disconnected, then we can kill the recorder. |
+ if (connection->client_authenticated()) { |
+ recorder_->Stop(NULL); |
+ recorder_ = NULL; |
+ } |
} |
// Close the connection to connection just to be safe. |
connection->Disconnect(); |
// Also remove reference to ConnectionToClient from this object. |
- connection_ = NULL; |
+ std::vector<scoped_refptr<ClientSession> >::iterator it; |
+ for (it = clients_.begin(); it != clients_.end(); ++it) { |
+ if (it->get()->connection() == connection) { |
+ clients_.erase(it); |
+ break; |
+ } |
+ } |
} |
//////////////////////////////////////////////////////////////////////////// |
@@ -287,8 +279,7 @@ void ChromotingHost::OnNewClientSession( |
protocol::Session* session, |
protocol::SessionManager::IncomingSessionResponse* response) { |
base::AutoLock auto_lock(lock_); |
- // TODO(hclam): Allow multiple clients to connect to the host. |
- if (connection_.get() || state_ != kStarted) { |
+ if (state_ != kStarted) { |
*response = protocol::SessionManager::DECLINE; |
return; |
} |
@@ -323,12 +314,19 @@ void ChromotingHost::OnNewClientSession( |
VLOG(1) << "Client connected: " << session->jid(); |
- // If we accept the connected then create a connection object. |
- connection_ = new ConnectionToClient(context_->network_message_loop(), |
- this, |
- desktop_environment_.get(), |
- desktop_environment_->input_stub()); |
- connection_->Init(session); |
+ // We accept the connection, so create a connection object. |
+ ConnectionToClient* connection = new ConnectionToClient( |
+ context_->network_message_loop(), |
+ this, |
+ desktop_environment_->input_stub()); |
+ |
+ // Create a client object. |
+ ClientSession* client = new ClientSession(this, connection); |
+ connection->set_host_stub(client); |
+ |
+ connection->Init(session); |
+ |
+ clients_.push_back(client); |
} |
void ChromotingHost::set_protocol_config( |
@@ -338,8 +336,8 @@ void ChromotingHost::set_protocol_config( |
protocol_config_.reset(config); |
} |
-protocol::HostStub* ChromotingHost::host_stub() const { |
- return desktop_environment_.get(); |
+void ChromotingHost::AddClient(ClientSession* client) { |
+ clients_.push_back(client); |
} |
void ChromotingHost::OnServerClosed() { |
@@ -371,34 +369,68 @@ std::string ChromotingHost::GenerateHostAuthToken( |
return encoded_client_token; |
} |
-void ChromotingHost::LocalLoginSucceeded() { |
+void ChromotingHost::LocalLoginSucceeded( |
+ scoped_refptr<ConnectionToClient> connection) { |
if (MessageLoop::current() != context_->main_message_loop()) { |
context_->main_message_loop()->PostTask( |
FROM_HERE, |
- NewRunnableMethod(this, &ChromotingHost::LocalLoginSucceeded)); |
+ NewRunnableMethod(this, |
+ &ChromotingHost::LocalLoginSucceeded, |
+ connection)); |
return; |
} |
protocol::LocalLoginStatus* status = new protocol::LocalLoginStatus(); |
status->set_success(true); |
- connection_->client_stub()->BeginSessionResponse( |
+ connection->client_stub()->BeginSessionResponse( |
status, new DeleteTask<protocol::LocalLoginStatus>(status)); |
- connection_->OnClientAuthenticated(); |
+ connection->OnClientAuthenticated(); |
+ |
+ // Disconnect all other clients. |
+ // Iterate over a copy of the list of clients, to avoid mutating the list |
+ // while iterating over it. |
+ std::vector<scoped_refptr<ClientSession> > clients_copy(clients_); |
+ std::vector<scoped_refptr<ClientSession> >::const_iterator client; |
+ for (client = clients_copy.begin(); client != clients_copy.end(); client++) { |
+ ConnectionToClient* connection_other = client->get()->connection(); |
+ if (connection_other != connection) { |
+ OnClientDisconnected(connection_other); |
+ } |
+ } |
+ // 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(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(connection); |
recorder_->Start(); |
} |
-void ChromotingHost::LocalLoginFailed() { |
+void ChromotingHost::LocalLoginFailed( |
+ scoped_refptr<ConnectionToClient> connection) { |
if (MessageLoop::current() != context_->main_message_loop()) { |
context_->main_message_loop()->PostTask( |
FROM_HERE, |
- NewRunnableMethod(this, &ChromotingHost::LocalLoginFailed)); |
+ NewRunnableMethod(this, &ChromotingHost::LocalLoginFailed, connection)); |
return; |
} |
protocol::LocalLoginStatus* status = new protocol::LocalLoginStatus(); |
status->set_success(false); |
- connection_->client_stub()->BeginSessionResponse( |
+ connection->client_stub()->BeginSessionResponse( |
status, new DeleteTask<protocol::LocalLoginStatus>(status)); |
} |