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)); |
} |