OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "remoting/host/chromoting_host.h" | 5 #include "remoting/host/chromoting_host.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback.h" | 8 #include "base/callback.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/message_loop_proxy.h" | 10 #include "base/message_loop_proxy.h" |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
47 ChromotingHost::ChromotingHost(ChromotingHostContext* context, | 47 ChromotingHost::ChromotingHost(ChromotingHostContext* context, |
48 MutableHostConfig* config, | 48 MutableHostConfig* config, |
49 DesktopEnvironment* environment, | 49 DesktopEnvironment* environment, |
50 AccessVerifier* access_verifier, | 50 AccessVerifier* access_verifier, |
51 bool allow_nat_traversal) | 51 bool allow_nat_traversal) |
52 : context_(context), | 52 : context_(context), |
53 desktop_environment_(environment), | 53 desktop_environment_(environment), |
54 config_(config), | 54 config_(config), |
55 access_verifier_(access_verifier), | 55 access_verifier_(access_verifier), |
56 allow_nat_traversal_(allow_nat_traversal), | 56 allow_nat_traversal_(allow_nat_traversal), |
| 57 stopping_recorders_(0), |
57 state_(kInitial), | 58 state_(kInitial), |
58 stopping_recorders_(0), | |
59 protocol_config_(protocol::CandidateSessionConfig::CreateDefault()), | 59 protocol_config_(protocol::CandidateSessionConfig::CreateDefault()), |
60 is_curtained_(false), | 60 is_curtained_(false), |
61 is_it2me_(false) { | 61 is_it2me_(false) { |
62 DCHECK(desktop_environment_); | 62 DCHECK(desktop_environment_); |
63 desktop_environment_->set_host(this); | 63 desktop_environment_->set_host(this); |
64 } | 64 } |
65 | 65 |
66 ChromotingHost::~ChromotingHost() { | 66 ChromotingHost::~ChromotingHost() { |
67 } | 67 } |
68 | 68 |
69 void ChromotingHost::Start() { | 69 void ChromotingHost::Start() { |
70 if (!context_->network_message_loop()->BelongsToCurrentThread()) { | 70 if (!context_->network_message_loop()->BelongsToCurrentThread()) { |
71 context_->network_message_loop()->PostTask( | 71 context_->network_message_loop()->PostTask( |
72 FROM_HERE, base::Bind(&ChromotingHost::Start, this)); | 72 FROM_HERE, base::Bind(&ChromotingHost::Start, this)); |
73 return; | 73 return; |
74 } | 74 } |
75 | 75 |
76 LOG(INFO) << "Starting host"; | 76 LOG(INFO) << "Starting host"; |
77 DCHECK(!signal_strategy_.get()); | 77 DCHECK(!signal_strategy_.get()); |
78 DCHECK(access_verifier_.get()); | 78 DCHECK(access_verifier_.get()); |
79 | 79 |
80 // Make sure this object is not started. | 80 // Make sure this object is not started. |
81 { | 81 if (state_ != kInitial) |
82 base::AutoLock auto_lock(lock_); | 82 return; |
83 if (state_ != kInitial) | 83 state_ = kStarted; |
84 return; | |
85 state_ = kStarted; | |
86 } | |
87 | 84 |
88 // Use an XMPP connection to the Talk network for session signalling. | 85 // Use an XMPP connection to the Talk network for session signalling. |
89 std::string xmpp_login; | 86 std::string xmpp_login; |
90 std::string xmpp_auth_token; | 87 std::string xmpp_auth_token; |
91 std::string xmpp_auth_service; | 88 std::string xmpp_auth_service; |
92 if (!config_->GetString(kXmppLoginConfigPath, &xmpp_login) || | 89 if (!config_->GetString(kXmppLoginConfigPath, &xmpp_login) || |
93 !config_->GetString(kXmppAuthTokenConfigPath, &xmpp_auth_token) || | 90 !config_->GetString(kXmppAuthTokenConfigPath, &xmpp_auth_token) || |
94 !config_->GetString(kXmppAuthServiceConfigPath, &xmpp_auth_service)) { | 91 !config_->GetString(kXmppAuthServiceConfigPath, &xmpp_auth_service)) { |
95 LOG(ERROR) << "XMPP credentials are not defined in the config."; | 92 LOG(ERROR) << "XMPP credentials are not defined in the config."; |
96 return; | 93 return; |
97 } | 94 } |
98 | 95 |
99 signal_strategy_.reset( | 96 signal_strategy_.reset( |
100 new XmppSignalStrategy(context_->jingle_thread(), xmpp_login, | 97 new XmppSignalStrategy(context_->jingle_thread(), xmpp_login, |
101 xmpp_auth_token, | 98 xmpp_auth_token, |
102 xmpp_auth_service)); | 99 xmpp_auth_service)); |
103 signal_strategy_->Init(this); | 100 signal_strategy_->Init(this); |
104 } | 101 } |
105 | 102 |
106 // This method is called when we need to destroy the host process. | 103 // This method is called when we need to destroy the host process. |
107 void ChromotingHost::Shutdown(const base::Closure& shutdown_task) { | 104 void ChromotingHost::Shutdown(const base::Closure& shutdown_task) { |
108 if (MessageLoop::current() != context_->main_message_loop()) { | 105 if (!context_->network_message_loop()->BelongsToCurrentThread()) { |
109 context_->main_message_loop()->PostTask( | 106 context_->network_message_loop()->PostTask( |
110 FROM_HERE, | 107 FROM_HERE, base::Bind(&ChromotingHost::Shutdown, this, shutdown_task)); |
111 base::Bind(&ChromotingHost::Shutdown, this, shutdown_task)); | |
112 return; | 108 return; |
113 } | 109 } |
114 | 110 |
115 // No-op if this object is not started yet. | 111 // No-op if this object is not started yet. |
116 { | 112 if (state_ == kInitial || state_ == kStopped) { |
117 base::AutoLock auto_lock(lock_); | |
118 if (state_ == kInitial || state_ == kStopped) { | |
119 // Nothing to do if we are not started. | 113 // Nothing to do if we are not started. |
120 state_ = kStopped; | 114 state_ = kStopped; |
121 context_->main_message_loop()->PostTask(FROM_HERE, shutdown_task); | 115 context_->network_message_loop()->PostTask(FROM_HERE, shutdown_task); |
122 return; | 116 return; |
123 } | |
124 if (!shutdown_task.is_null()) | |
125 shutdown_tasks_.push_back(shutdown_task); | |
126 if (state_ == kStopping) | |
127 return; | |
128 state_ = kStopping; | |
129 } | 117 } |
| 118 if (!shutdown_task.is_null()) |
| 119 shutdown_tasks_.push_back(shutdown_task); |
| 120 if (state_ == kStopping) |
| 121 return; |
| 122 state_ = kStopping; |
130 | 123 |
131 // Disconnect all of the clients, implicitly stopping the ScreenRecorder. | 124 // Disconnect all of the clients, implicitly stopping the ScreenRecorder. |
132 while (!clients_.empty()) { | 125 while (!clients_.empty()) { |
133 scoped_refptr<ClientSession> client = clients_.front(); | 126 clients_.front()->Disconnect(); |
134 client->Disconnect(); | |
135 OnClientDisconnected(client); | |
136 } | 127 } |
137 | 128 |
138 ShutdownNetwork(); | 129 // Stop session manager. |
| 130 if (session_manager_.get()) { |
| 131 session_manager_->Close(); |
| 132 // It may not be safe to delete |session_manager_| here becase |
| 133 // this method may be invoked in response to a libjingle event and |
| 134 // libjingle's sigslot doesn't handle it properly, so postpone the |
| 135 // deletion. |
| 136 context_->network_message_loop()->DeleteSoon( |
| 137 FROM_HERE, session_manager_.release()); |
| 138 } |
| 139 |
| 140 // Stop XMPP connection synchronously. |
| 141 if (signal_strategy_.get()) { |
| 142 signal_strategy_->Close(); |
| 143 signal_strategy_.reset(); |
| 144 |
| 145 for (StatusObserverList::iterator it = status_observers_.begin(); |
| 146 it != status_observers_.end(); ++it) { |
| 147 (*it)->OnSignallingDisconnected(); |
| 148 } |
| 149 } |
| 150 |
| 151 if (recorder_.get()) { |
| 152 StopScreenRecorder(); |
| 153 } else { |
| 154 ShutdownFinish(); |
| 155 } |
139 } | 156 } |
140 | 157 |
141 void ChromotingHost::AddStatusObserver(HostStatusObserver* observer) { | 158 void ChromotingHost::AddStatusObserver(HostStatusObserver* observer) { |
142 DCHECK_EQ(state_, kInitial); | 159 DCHECK_EQ(state_, kInitial); |
143 status_observers_.push_back(observer); | 160 status_observers_.push_back(observer); |
144 } | 161 } |
145 | 162 |
146 //////////////////////////////////////////////////////////////////////////// | 163 //////////////////////////////////////////////////////////////////////////// |
147 // protocol::ClientSession::EventHandler implementation. | 164 // protocol::ClientSession::EventHandler implementation. |
148 void ChromotingHost::OnSessionAuthenticated(ClientSession* client) { | 165 void ChromotingHost::OnSessionAuthenticated(ClientSession* client) { |
149 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); | 166 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
150 protocol::Session* session = client->connection()->session(); | 167 |
151 context_->main_message_loop()->PostTask( | 168 // Disconnect all other clients. |
152 FROM_HERE, base::Bind(&ChromotingHost::AddAuthenticatedClient, | 169 // Iterate over a copy of the list of clients, to avoid mutating the list |
153 this, make_scoped_refptr(client), | 170 // while iterating over it. |
154 session->config(), session->jid())); | 171 ClientList clients_copy(clients_); |
| 172 for (ClientList::const_iterator other_client = clients_copy.begin(); |
| 173 other_client != clients_copy.end(); ++other_client) { |
| 174 if ((*other_client) != client) { |
| 175 (*other_client)->Disconnect(); |
| 176 } |
| 177 } |
| 178 |
| 179 // Create a new RecordSession if there was none. |
| 180 if (!recorder_.get()) { |
| 181 // Then we create a ScreenRecorder passing the message loops that |
| 182 // it should run on. |
| 183 Encoder* encoder = CreateEncoder(client->connection()->session()->config()); |
| 184 |
| 185 recorder_ = new ScreenRecorder(context_->main_message_loop(), |
| 186 context_->encode_message_loop(), |
| 187 context_->network_message_loop(), |
| 188 desktop_environment_->capturer(), |
| 189 encoder); |
| 190 } |
| 191 |
| 192 // Immediately add the connection and start the session. |
| 193 recorder_->AddConnection(client->connection()); |
| 194 recorder_->Start(); |
| 195 |
| 196 // Notify observers that there is at least one authenticated client. |
| 197 const std::string& jid = client->connection()->session()->jid(); |
| 198 for (StatusObserverList::iterator it = status_observers_.begin(); |
| 199 it != status_observers_.end(); ++it) { |
| 200 (*it)->OnClientAuthenticated(jid); |
| 201 } |
| 202 // TODO(jamiewalch): Tidy up actions to be taken on connect/disconnect, |
| 203 // including closing the connection on failure of a critical operation. |
| 204 EnableCurtainMode(true); |
| 205 |
| 206 std::string username = jid.substr(0, jid.find('/')); |
| 207 desktop_environment_->OnConnect(username); |
155 } | 208 } |
156 | 209 |
157 void ChromotingHost::OnSessionClosed(ClientSession* client) { | 210 void ChromotingHost::OnSessionClosed(ClientSession* client) { |
158 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); | 211 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
159 | 212 |
160 VLOG(1) << "Connection to client closed."; | 213 scoped_refptr<ClientSession> client_ref = client; |
161 context_->main_message_loop()->PostTask( | 214 |
162 FROM_HERE, base::Bind(&ChromotingHost::OnClientDisconnected, this, | 215 ClientList::iterator it = std::find(clients_.begin(), clients_.end(), client); |
163 make_scoped_refptr(client))); | 216 CHECK(it != clients_.end()); |
| 217 clients_.erase(it); |
| 218 |
| 219 if (recorder_.get()) { |
| 220 recorder_->RemoveConnection(client->connection()); |
| 221 } |
| 222 |
| 223 for (StatusObserverList::iterator it = status_observers_.begin(); |
| 224 it != status_observers_.end(); ++it) { |
| 225 (*it)->OnClientDisconnected(client->client_jid()); |
| 226 } |
| 227 |
| 228 if (AuthenticatedClientsCount() == 0) { |
| 229 if (recorder_.get()) { |
| 230 // Stop the recorder if there are no more clients. |
| 231 StopScreenRecorder(); |
| 232 } |
| 233 |
| 234 // Disable the "curtain" if there are no more active clients. |
| 235 EnableCurtainMode(false); |
| 236 desktop_environment_->OnLastDisconnect(); |
| 237 } |
164 } | 238 } |
165 | 239 |
166 void ChromotingHost::OnSessionSequenceNumber(ClientSession* session, | 240 void ChromotingHost::OnSessionSequenceNumber(ClientSession* session, |
167 int64 sequence_number) { | 241 int64 sequence_number) { |
168 // Update the sequence number in ScreenRecorder. | 242 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
169 if (MessageLoop::current() != context_->main_message_loop()) { | |
170 context_->main_message_loop()->PostTask( | |
171 FROM_HERE, base::Bind(&ChromotingHost::OnSessionSequenceNumber, this, | |
172 make_scoped_refptr(session), sequence_number)); | |
173 return; | |
174 } | |
175 | |
176 if (recorder_.get()) | 243 if (recorder_.get()) |
177 recorder_->UpdateSequenceNumber(sequence_number); | 244 recorder_->UpdateSequenceNumber(sequence_number); |
178 } | 245 } |
179 | 246 |
180 //////////////////////////////////////////////////////////////////////////// | 247 //////////////////////////////////////////////////////////////////////////// |
181 // SignalStrategy::StatusObserver implementations | 248 // SignalStrategy::StatusObserver implementations |
182 void ChromotingHost::OnStateChange( | 249 void ChromotingHost::OnStateChange( |
183 SignalStrategy::StatusObserver::State state) { | 250 SignalStrategy::StatusObserver::State state) { |
184 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); | 251 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
185 | 252 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
225 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); | 292 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
226 // Don't need to do anything here, just wait for incoming | 293 // Don't need to do anything here, just wait for incoming |
227 // connections. | 294 // connections. |
228 } | 295 } |
229 | 296 |
230 void ChromotingHost::OnIncomingSession( | 297 void ChromotingHost::OnIncomingSession( |
231 protocol::Session* session, | 298 protocol::Session* session, |
232 protocol::SessionManager::IncomingSessionResponse* response) { | 299 protocol::SessionManager::IncomingSessionResponse* response) { |
233 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); | 300 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
234 | 301 |
235 base::AutoLock auto_lock(lock_); | |
236 if (state_ != kStarted) { | 302 if (state_ != kStarted) { |
237 *response = protocol::SessionManager::DECLINE; | 303 *response = protocol::SessionManager::DECLINE; |
238 return; | 304 return; |
239 } | 305 } |
240 | 306 |
241 // Check that the client has access to the host. | 307 // Check that the client has access to the host. |
242 if (!access_verifier_->VerifyPermissions(session->jid(), | 308 if (!access_verifier_->VerifyPermissions(session->jid(), |
243 session->initiator_token())) { | 309 session->initiator_token())) { |
244 *response = protocol::SessionManager::DECLINE; | 310 *response = protocol::SessionManager::DECLINE; |
245 | 311 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
284 | 350 |
285 *response = protocol::SessionManager::ACCEPT; | 351 *response = protocol::SessionManager::ACCEPT; |
286 | 352 |
287 LOG(INFO) << "Client connected: " << session->jid(); | 353 LOG(INFO) << "Client connected: " << session->jid(); |
288 | 354 |
289 // Create a client object. | 355 // Create a client object. |
290 scoped_refptr<protocol::ConnectionToClient> connection = | 356 scoped_refptr<protocol::ConnectionToClient> connection = |
291 new protocol::ConnectionToClient(context_->network_message_loop(), | 357 new protocol::ConnectionToClient(context_->network_message_loop(), |
292 session); | 358 session); |
293 ClientSession* client = new ClientSession( | 359 ClientSession* client = new ClientSession( |
294 this, connection, | 360 this, connection, desktop_environment_->event_executor(), |
295 desktop_environment_->event_executor(), | |
296 desktop_environment_->capturer()); | 361 desktop_environment_->capturer()); |
297 | |
298 clients_.push_back(client); | 362 clients_.push_back(client); |
299 } | 363 } |
300 | 364 |
301 void ChromotingHost::set_protocol_config( | 365 void ChromotingHost::set_protocol_config( |
302 protocol::CandidateSessionConfig* config) { | 366 protocol::CandidateSessionConfig* config) { |
303 DCHECK(config_.get()); | 367 DCHECK(config); |
304 DCHECK_EQ(state_, kInitial); | 368 DCHECK_EQ(state_, kInitial); |
305 protocol_config_.reset(config); | 369 protocol_config_.reset(config); |
306 } | 370 } |
307 | 371 |
308 void ChromotingHost::LocalMouseMoved(const SkIPoint& new_pos) { | 372 void ChromotingHost::LocalMouseMoved(const SkIPoint& new_pos) { |
309 if (!context_->network_message_loop()->BelongsToCurrentThread()) { | 373 if (!context_->network_message_loop()->BelongsToCurrentThread()) { |
310 context_->network_message_loop()->PostTask( | 374 context_->network_message_loop()->PostTask( |
311 FROM_HERE, base::Bind(&ChromotingHost::LocalMouseMoved, this, new_pos)); | 375 FROM_HERE, base::Bind(&ChromotingHost::LocalMouseMoved, this, new_pos)); |
312 return; | 376 return; |
313 } | 377 } |
| 378 |
314 ClientList::iterator client; | 379 ClientList::iterator client; |
315 for (client = clients_.begin(); client != clients_.end(); ++client) { | 380 for (client = clients_.begin(); client != clients_.end(); ++client) { |
316 client->get()->LocalMouseMoved(new_pos); | 381 client->get()->LocalMouseMoved(new_pos); |
317 } | 382 } |
318 } | 383 } |
319 | 384 |
320 void ChromotingHost::PauseSession(bool pause) { | 385 void ChromotingHost::PauseSession(bool pause) { |
321 if (context_->main_message_loop() != MessageLoop::current()) { | 386 if (!context_->network_message_loop()->BelongsToCurrentThread()) { |
322 context_->main_message_loop()->PostTask( | 387 context_->network_message_loop()->PostTask( |
323 FROM_HERE, base::Bind(&ChromotingHost::PauseSession, this, pause)); | 388 FROM_HERE, base::Bind(&ChromotingHost::PauseSession, this, pause)); |
324 return; | 389 return; |
325 } | 390 } |
| 391 |
326 ClientList::iterator client; | 392 ClientList::iterator client; |
327 for (client = clients_.begin(); client != clients_.end(); ++client) { | 393 for (client = clients_.begin(); client != clients_.end(); ++client) { |
328 client->get()->set_awaiting_continue_approval(pause); | 394 client->get()->set_awaiting_continue_approval(pause); |
329 } | 395 } |
330 desktop_environment_->OnPause(pause); | 396 desktop_environment_->OnPause(pause); |
331 } | 397 } |
332 | 398 |
333 void ChromotingHost::SetUiStrings(const UiStrings& ui_strings) { | 399 void ChromotingHost::SetUiStrings(const UiStrings& ui_strings) { |
334 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); | 400 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); |
335 DCHECK_EQ(state_, kInitial); | 401 DCHECK_EQ(state_, kInitial); |
336 | 402 |
337 ui_strings_ = ui_strings; | 403 ui_strings_ = ui_strings; |
338 } | 404 } |
339 | 405 |
340 void ChromotingHost::OnClientDisconnected(ClientSession* client) { | |
341 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); | |
342 | |
343 scoped_refptr<ClientSession> client_ref = client; | |
344 | |
345 ClientList::iterator it; | |
346 for (it = clients_.begin(); it != clients_.end(); ++it) { | |
347 if (it->get() == client) | |
348 break; | |
349 } | |
350 clients_.erase(it); | |
351 | |
352 if (recorder_.get()) { | |
353 recorder_->RemoveConnection(client->connection()); | |
354 } | |
355 | |
356 for (StatusObserverList::iterator it = status_observers_.begin(); | |
357 it != status_observers_.end(); ++it) { | |
358 (*it)->OnClientDisconnected(client->client_jid()); | |
359 } | |
360 | |
361 if (AuthenticatedClientsCount() == 0) { | |
362 if (recorder_.get()) { | |
363 // Stop the recorder if there are no more clients. | |
364 StopScreenRecorder(); | |
365 } | |
366 | |
367 // Disable the "curtain" if there are no more active clients. | |
368 EnableCurtainMode(false); | |
369 desktop_environment_->OnLastDisconnect(); | |
370 } | |
371 } | |
372 | |
373 // TODO(sergeyu): Move this to SessionManager? | 406 // TODO(sergeyu): Move this to SessionManager? |
374 Encoder* ChromotingHost::CreateEncoder(const protocol::SessionConfig& config) { | 407 Encoder* ChromotingHost::CreateEncoder(const protocol::SessionConfig& config) { |
375 const protocol::ChannelConfig& video_config = config.video_config(); | 408 const protocol::ChannelConfig& video_config = config.video_config(); |
376 | 409 |
377 if (video_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) { | 410 if (video_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) { |
378 return EncoderRowBased::CreateVerbatimEncoder(); | 411 return EncoderRowBased::CreateVerbatimEncoder(); |
379 } else if (video_config.codec == protocol::ChannelConfig::CODEC_ZIP) { | 412 } else if (video_config.codec == protocol::ChannelConfig::CODEC_ZIP) { |
380 return EncoderRowBased::CreateZlibEncoder(); | 413 return EncoderRowBased::CreateZlibEncoder(); |
381 } else if (video_config.codec == protocol::ChannelConfig::CODEC_VP8) { | 414 } else if (video_config.codec == protocol::ChannelConfig::CODEC_VP8) { |
382 return new remoting::EncoderVp8(); | 415 return new remoting::EncoderVp8(); |
383 } | 416 } |
384 | 417 |
385 return NULL; | 418 return NULL; |
386 } | 419 } |
387 | 420 |
388 std::string ChromotingHost::GenerateHostAuthToken( | 421 std::string ChromotingHost::GenerateHostAuthToken( |
389 const std::string& encoded_client_token) { | 422 const std::string& encoded_client_token) { |
390 // TODO(ajwong): Return the signature of this instead. | 423 // TODO(ajwong): Return the signature of this instead. |
391 return encoded_client_token; | 424 return encoded_client_token; |
392 } | 425 } |
393 | 426 |
394 int ChromotingHost::AuthenticatedClientsCount() const { | 427 int ChromotingHost::AuthenticatedClientsCount() const { |
| 428 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
| 429 |
395 int authenticated_clients = 0; | 430 int authenticated_clients = 0; |
396 for (ClientList::const_iterator it = clients_.begin(); it != clients_.end(); | 431 for (ClientList::const_iterator it = clients_.begin(); it != clients_.end(); |
397 ++it) { | 432 ++it) { |
398 if (it->get()->authenticated()) | 433 if (it->get()->authenticated()) |
399 ++authenticated_clients; | 434 ++authenticated_clients; |
400 } | 435 } |
401 return authenticated_clients; | 436 return authenticated_clients; |
402 } | 437 } |
403 | 438 |
404 void ChromotingHost::EnableCurtainMode(bool enable) { | 439 void ChromotingHost::EnableCurtainMode(bool enable) { |
405 // TODO(jamiewalch): This will need to be more sophisticated when we think | 440 // TODO(jamiewalch): This will need to be more sophisticated when we think |
406 // about proper crash recovery and daemon mode. | 441 // about proper crash recovery and daemon mode. |
407 // TODO(wez): CurtainMode shouldn't be driven directly by ChromotingHost. | 442 // TODO(wez): CurtainMode shouldn't be driven directly by ChromotingHost. |
408 if (is_it2me_ || enable == is_curtained_) | 443 if (is_it2me_ || enable == is_curtained_) |
409 return; | 444 return; |
410 desktop_environment_->curtain()->EnableCurtainMode(enable); | 445 desktop_environment_->curtain()->EnableCurtainMode(enable); |
411 is_curtained_ = enable; | 446 is_curtained_ = enable; |
412 } | 447 } |
413 | 448 |
414 void ChromotingHost::AddAuthenticatedClient( | |
415 ClientSession* client, | |
416 const protocol::SessionConfig& config, | |
417 const std::string& jid) { | |
418 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); | |
419 | |
420 // Disconnect all other clients. | |
421 // Iterate over a copy of the list of clients, to avoid mutating the list | |
422 // while iterating over it. | |
423 ClientList clients_copy(clients_); | |
424 for (ClientList::const_iterator other_client = clients_copy.begin(); | |
425 other_client != clients_copy.end(); ++other_client) { | |
426 if ((*other_client) != client) { | |
427 (*other_client)->Disconnect(); | |
428 OnClientDisconnected(*other_client); | |
429 } | |
430 } | |
431 | |
432 // Those disconnections should have killed the screen recorder. | |
433 CHECK(recorder_.get() == NULL); | |
434 | |
435 // Create a new RecordSession if there was none. | |
436 if (!recorder_.get()) { | |
437 // Then we create a ScreenRecorder passing the message loops that | |
438 // it should run on. | |
439 Encoder* encoder = CreateEncoder(config); | |
440 | |
441 recorder_ = new ScreenRecorder(context_->main_message_loop(), | |
442 context_->encode_message_loop(), | |
443 context_->network_message_loop(), | |
444 desktop_environment_->capturer(), | |
445 encoder); | |
446 } | |
447 | |
448 // Immediately add the connection and start the session. | |
449 recorder_->AddConnection(client->connection()); | |
450 recorder_->Start(); | |
451 // Notify observers that there is at least one authenticated client. | |
452 for (StatusObserverList::iterator it = status_observers_.begin(); | |
453 it != status_observers_.end(); ++it) { | |
454 (*it)->OnClientAuthenticated(jid); | |
455 } | |
456 // TODO(jamiewalch): Tidy up actions to be taken on connect/disconnect, | |
457 // including closing the connection on failure of a critical operation. | |
458 EnableCurtainMode(true); | |
459 if (is_it2me_) { | |
460 std::string username = jid; | |
461 size_t pos = username.find('/'); | |
462 if (pos != std::string::npos) | |
463 username.replace(pos, std::string::npos, ""); | |
464 desktop_environment_->OnConnect(username); | |
465 } | |
466 } | |
467 | |
468 void ChromotingHost::StopScreenRecorder() { | 449 void ChromotingHost::StopScreenRecorder() { |
469 DCHECK(MessageLoop::current() == context_->main_message_loop()); | 450 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
470 DCHECK(recorder_.get()); | 451 DCHECK(recorder_.get()); |
471 | 452 |
472 ++stopping_recorders_; | 453 ++stopping_recorders_; |
473 recorder_->Stop(base::Bind(&ChromotingHost::OnScreenRecorderStopped, this)); | 454 scoped_refptr<ScreenRecorder> recorder = recorder_; |
474 recorder_ = NULL; | 455 recorder_ = NULL; |
| 456 recorder->Stop(base::Bind(&ChromotingHost::OnScreenRecorderStopped, this)); |
475 } | 457 } |
476 | 458 |
477 void ChromotingHost::OnScreenRecorderStopped() { | 459 void ChromotingHost::OnScreenRecorderStopped() { |
478 if (MessageLoop::current() != context_->main_message_loop()) { | 460 if (!context_->network_message_loop()->BelongsToCurrentThread()) { |
479 context_->main_message_loop()->PostTask( | 461 context_->network_message_loop()->PostTask( |
480 FROM_HERE, base::Bind(&ChromotingHost::OnScreenRecorderStopped, this)); | 462 FROM_HERE, base::Bind(&ChromotingHost::OnScreenRecorderStopped, this)); |
481 return; | 463 return; |
482 } | 464 } |
483 | 465 |
484 --stopping_recorders_; | 466 --stopping_recorders_; |
485 DCHECK_GE(stopping_recorders_, 0); | 467 DCHECK_GE(stopping_recorders_, 0); |
486 | 468 |
487 bool stopping; | 469 if (!stopping_recorders_ && state_ == kStopping) |
488 { | |
489 base::AutoLock auto_lock(lock_); | |
490 stopping = state_ == kStopping; | |
491 } | |
492 | |
493 if (!stopping_recorders_ && stopping) | |
494 ShutdownFinish(); | 470 ShutdownFinish(); |
495 } | 471 } |
496 | 472 |
497 void ChromotingHost::ShutdownNetwork() { | 473 void ChromotingHost::ShutdownFinish() { |
498 if (!context_->network_message_loop()->BelongsToCurrentThread()) { | 474 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
499 context_->network_message_loop()->PostTask( | |
500 FROM_HERE, base::Bind(&ChromotingHost::ShutdownNetwork, this)); | |
501 return; | |
502 } | |
503 | 475 |
504 // Stop chromotocol session manager. | 476 state_ = kStopped; |
505 if (session_manager_.get()) { | |
506 session_manager_->Close(); | |
507 session_manager_.reset(); | |
508 } | |
509 | |
510 // Stop XMPP connection. | |
511 if (signal_strategy_.get()) { | |
512 signal_strategy_->Close(); | |
513 signal_strategy_.reset(); | |
514 | |
515 for (StatusObserverList::iterator it = status_observers_.begin(); | |
516 it != status_observers_.end(); ++it) { | |
517 (*it)->OnSignallingDisconnected(); | |
518 } | |
519 } | |
520 | |
521 ShutdownRecorder(); | |
522 } | |
523 | |
524 void ChromotingHost::ShutdownRecorder() { | |
525 if (MessageLoop::current() != context_->main_message_loop()) { | |
526 context_->main_message_loop()->PostTask( | |
527 FROM_HERE, base::Bind(&ChromotingHost::ShutdownRecorder, this)); | |
528 return; | |
529 } | |
530 | |
531 if (recorder_.get()) { | |
532 StopScreenRecorder(); | |
533 } else if (!stopping_recorders_) { | |
534 ShutdownFinish(); | |
535 } | |
536 } | |
537 | |
538 void ChromotingHost::ShutdownFinish() { | |
539 if (MessageLoop::current() != context_->main_message_loop()) { | |
540 context_->main_message_loop()->PostTask( | |
541 FROM_HERE, base::Bind(&ChromotingHost::ShutdownFinish, this)); | |
542 return; | |
543 } | |
544 | |
545 { | |
546 base::AutoLock auto_lock(lock_); | |
547 state_ = kStopped; | |
548 } | |
549 | 477 |
550 // Keep reference to |this|, so that we don't get destroyed while | 478 // Keep reference to |this|, so that we don't get destroyed while |
551 // sending notifications. | 479 // sending notifications. |
552 scoped_refptr<ChromotingHost> self(this); | 480 scoped_refptr<ChromotingHost> self(this); |
553 | 481 |
554 // Notify observers. | 482 // Notify observers. |
555 for (StatusObserverList::iterator it = status_observers_.begin(); | 483 for (StatusObserverList::iterator it = status_observers_.begin(); |
556 it != status_observers_.end(); ++it) { | 484 it != status_observers_.end(); ++it) { |
557 (*it)->OnShutdown(); | 485 (*it)->OnShutdown(); |
558 } | 486 } |
559 | 487 |
560 for (std::vector<base::Closure>::iterator it = shutdown_tasks_.begin(); | 488 for (std::vector<base::Closure>::iterator it = shutdown_tasks_.begin(); |
561 it != shutdown_tasks_.end(); ++it) { | 489 it != shutdown_tasks_.end(); ++it) { |
562 it->Run(); | 490 it->Run(); |
563 } | 491 } |
564 shutdown_tasks_.clear(); | 492 shutdown_tasks_.clear(); |
565 } | 493 } |
566 | 494 |
567 } // namespace remoting | 495 } // namespace remoting |
OLD | NEW |