Index: remoting/host/chromoting_host.cc |
diff --git a/remoting/host/chromoting_host.cc b/remoting/host/chromoting_host.cc |
index df778482af73b31d566b5892ca39328ba9e5b60d..46abbabf0ebd7e8bde7e7ff051430e806d7b88b1 100644 |
--- a/remoting/host/chromoting_host.cc |
+++ b/remoting/host/chromoting_host.cc |
@@ -140,9 +140,9 @@ void ChromotingHost::Shutdown() { |
recorder_->RemoveAllConnections(); |
} |
- // Disconnect the client. |
- if (connection_) { |
- connection_->Disconnect(); |
+ // Disconnect the clients. |
+ for (size_t i = 0; i < connections_.size(); i++) { |
+ connections_[i]->Disconnect(); |
} |
// Stop the heartbeat sender. |
@@ -172,42 +172,30 @@ 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) { |
DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); |
// Remove the connection from the session manager and stop the session. |
- // TODO(hclam): Stop only if the last connection disconnected. |
if (recorder_.get()) { |
recorder_->RemoveConnection(connection); |
- recorder_->Stop(NULL); |
- recorder_ = NULL; |
+ // If the client is authenticated, then it was the only reason for running |
+ // 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<protocol::ConnectionToClient>>::iterator it = |
+ std::find(connections_.begin(), connections_.end(), connection); |
+ if (it != connections_.end()) |
+ connections_.erase(it); |
} |
//////////////////////////////////////////////////////////////////////////// |
@@ -287,8 +275,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; |
} |
@@ -324,11 +311,15 @@ 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); |
+ ConnectionToClient* connection = new ConnectionToClient( |
+ context_->network_message_loop(), |
+ this, |
+ desktop_environment_.get(), |
+ desktop_environment_->input_stub()); |
+ |
+ connection->Init(session); |
+ |
+ connections_.push_back(connection); |
} |
void ChromotingHost::set_protocol_config( |
@@ -371,34 +362,66 @@ std::string ChromotingHost::GenerateHostAuthToken( |
return encoded_client_token; |
} |
-void ChromotingHost::LocalLoginSucceeded() { |
+void ChromotingHost::LocalLoginSucceeded(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. |
+ std::vector<scoped_refptr<protocol::ConnectionToClient>> conns_copy( |
+ connections_); |
+ std::vector<scoped_refptr<protocol::ConnectionToClient>>::const_iterator conn; |
+ for (conn = conns_copy.begin(); conn != conns_copy.end(); conn++) { |
+ if (conn->get() != connection) { |
+ OnClientDisconnected(conn->get()); |
+ } |
+ } |
+ // Those disconnections should have killed the screen recorder. |
+ DCHECK(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. |
+ 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); |
recorder_->Start(); |
} |
-void ChromotingHost::LocalLoginFailed() { |
+void ChromotingHost::LocalLoginFailed(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)); |
} |