Chromium Code Reviews| Index: remoting/host/chromoting_host.cc |
| diff --git a/remoting/host/chromoting_host.cc b/remoting/host/chromoting_host.cc |
| index df778482af73b31d566b5892ca39328ba9e5b60d..bfdd988589db1a4a902734e8bfe298f5680c0ad6 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,9 +139,9 @@ 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(); |
| } |
|
awong
2011/03/22 15:11:56
Do we care to call clients_.clear() here to drop a
simonmorris
2011/03/23 10:35:20
Added clients_.clear() .
|
| // Stop the heartbeat sender. |
| @@ -172,42 +171,33 @@ 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. |
|
Sergey Ulanov
2011/03/22 23:19:14
I don't think we can remove this TODO yet. Recorde
simonmorris
2011/03/23 10:35:20
Done.
|
| 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. |
|
awong
2011/03/22 15:11:56
Not completely sure what this means:
"the only
simonmorris
2011/03/23 10:35:20
Clarified comment.
I don't think that scenario ca
|
| + 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 +277,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 +312,20 @@ 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, |
| + NULL, |
|
awong
2011/03/22 15:11:56
Is this parameter ever non-NULL now?
simonmorris
2011/03/23 10:35:20
Only in unit tests, and it's better to be more con
|
| + 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,10 +335,6 @@ void ChromotingHost::set_protocol_config( |
| protocol_config_.reset(config); |
| } |
| -protocol::HostStub* ChromotingHost::host_stub() const { |
| - return desktop_environment_.get(); |
| -} |
| - |
| void ChromotingHost::OnServerClosed() { |
| // Don't need to do anything here. |
| } |
| @@ -371,34 +364,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. |
| + std::vector<scoped_refptr<ClientSession> > clients_copy(clients_); |
|
awong
2011/03/22 15:11:56
Add a note for why we need to copy |clients_|.
simonmorris
2011/03/23 10:35:20
Done.
|
| + 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. |
| + DCHECK(recorder_.get() == NULL); |
|
awong
2011/03/22 15:11:56
This should be a hard requirement right?
I would
simonmorris
2011/03/23 10:35:20
Done.
|
| + |
| + // 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()); |
|
awong
2011/03/22 15:11:56
It's not obvious why we're checking for the existe
simonmorris
2011/03/23 10:35:20
A comment elsewhere suggests that this test is a r
|
| + |
| + 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)); |
| } |