Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(173)

Side by Side Diff: remoting/host/chromoting_host.cc

Issue 8495024: Access ChromotingHost::clients_ only on network thread. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: - Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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(Task* shutdown_task) { 104 void ChromotingHost::Shutdown(Task* 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)
125 shutdown_tasks_.push_back(shutdown_task);
126 if (state_ == kStopping)
127 return;
128 state_ = kStopping;
129 } 117 }
118 if (shutdown_task)
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 scoped_refptr<ClientSession> client = clients_.front();
134 client->Disconnect(); 127 client->Disconnect();
135 OnClientDisconnected(client); 128 OnSessionClosed(client);
136 } 129 }
137 130
138 ShutdownNetwork(); 131 // Stop session manager.
132 if (session_manager_.get()) {
133 session_manager_->Close();
134 // It may not be safe to delete |session_manager_| here becase
135 // this method may be invoked in resonse to a libjingle event and
Wez 2011/11/09 23:18:45 typo: resonse
Sergey Ulanov 2011/11/10 21:06:14 Done.
136 // libjingle's sigslot doesn't handle it properly, so postpone
137 // the deletion.
138 context_->network_message_loop()->DeleteSoon(
139 FROM_HERE, session_manager_.release());
140 }
141
142 // Stop XMPP connection synchronously.
143 if (signal_strategy_.get()) {
144 signal_strategy_->Close();
145 signal_strategy_.reset();
146
147 for (StatusObserverList::iterator it = status_observers_.begin();
148 it != status_observers_.end(); ++it) {
149 (*it)->OnSignallingDisconnected();
150 }
151 }
152
153 if (recorder_.get()) {
154 StopScreenRecorder();
155 } else {
156 ShutdownFinish();
157 }
139 } 158 }
140 159
141 void ChromotingHost::AddStatusObserver(HostStatusObserver* observer) { 160 void ChromotingHost::AddStatusObserver(HostStatusObserver* observer) {
142 DCHECK_EQ(state_, kInitial); 161 DCHECK_EQ(state_, kInitial);
143 status_observers_.push_back(observer); 162 status_observers_.push_back(observer);
144 } 163 }
145 164
146 //////////////////////////////////////////////////////////////////////////// 165 ////////////////////////////////////////////////////////////////////////////
147 // protocol::ClientSession::EventHandler implementation. 166 // protocol::ClientSession::EventHandler implementation.
148 void ChromotingHost::OnSessionAuthenticated(ClientSession* client) { 167 void ChromotingHost::OnSessionAuthenticated(ClientSession* client) {
149 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); 168 DCHECK(context_->network_message_loop()->BelongsToCurrentThread());
150 protocol::Session* session = client->connection()->session(); 169
151 context_->main_message_loop()->PostTask( 170 // Disconnect all other clients.
152 FROM_HERE, base::Bind(&ChromotingHost::AddAuthenticatedClient, 171 // Iterate over a copy of the list of clients, to avoid mutating the list
153 this, make_scoped_refptr(client), 172 // while iterating over it.
154 session->config(), session->jid())); 173 ClientList clients_copy(clients_);
174 for (ClientList::const_iterator other_client = clients_copy.begin();
175 other_client != clients_copy.end(); ++other_client) {
176 if ((*other_client) != client) {
177 (*other_client)->Disconnect();
178 OnSessionClosed(*other_client);
179 }
180 }
181
182 // Those disconnections should have killed the screen recorder.
183 CHECK(recorder_.get() == NULL);
184
185 // Create a new RecordSession if there was none.
186 if (!recorder_.get()) {
187 // Then we create a ScreenRecorder passing the message loops that
188 // it should run on.
189 Encoder* encoder = CreateEncoder(client->connection()->session()->config());
190
191 recorder_ = new ScreenRecorder(context_->main_message_loop(),
192 context_->encode_message_loop(),
193 context_->network_message_loop(),
194 desktop_environment_->capturer(),
195 encoder);
196 }
197
198 // Immediately add the connection and start the session.
199 recorder_->AddConnection(client->connection());
200 recorder_->Start();
201
202 // Notify observers that there is at least one authenticated client.
203 const std::string& jid = client->connection()->session()->jid();
204 for (StatusObserverList::iterator it = status_observers_.begin();
205 it != status_observers_.end(); ++it) {
206 (*it)->OnClientAuthenticated(jid);
207 }
208 // TODO(jamiewalch): Tidy up actions to be taken on connect/disconnect,
209 // including closing the connection on failure of a critical operation.
210 EnableCurtainMode(true);
211
212 std::string username = jid.substr(0, jid.find('/'));
213 desktop_environment_->OnConnect(username);
155 } 214 }
156 215
157 void ChromotingHost::OnSessionClosed(ClientSession* client) { 216 void ChromotingHost::OnSessionClosed(ClientSession* client) {
158 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); 217 DCHECK(context_->network_message_loop()->BelongsToCurrentThread());
159 218
160 VLOG(1) << "Connection to client closed."; 219 scoped_refptr<ClientSession> client_ref = client;
161 context_->main_message_loop()->PostTask( 220
162 FROM_HERE, base::Bind(&ChromotingHost::OnClientDisconnected, this, 221 ClientList::iterator it = std::find(clients_.begin(), clients_.end(), client);
163 make_scoped_refptr(client))); 222 CHECK(it != clients_.end());
223 clients_.erase(it);
224
225 if (recorder_.get()) {
226 recorder_->RemoveConnection(client->connection());
227 }
228
229 for (StatusObserverList::iterator it = status_observers_.begin();
230 it != status_observers_.end(); ++it) {
231 (*it)->OnClientDisconnected(client->client_jid());
232 }
233
234 if (AuthenticatedClientsCount() == 0) {
235 if (recorder_.get()) {
236 // Stop the recorder if there are no more clients.
237 StopScreenRecorder();
238 }
239
240 // Disable the "curtain" if there are no more active clients.
241 EnableCurtainMode(false);
242 desktop_environment_->OnLastDisconnect();
243 }
164 } 244 }
165 245
166 void ChromotingHost::OnSessionSequenceNumber(ClientSession* session, 246 void ChromotingHost::OnSessionSequenceNumber(ClientSession* session,
167 int64 sequence_number) { 247 int64 sequence_number) {
168 // Update the sequence number in ScreenRecorder. 248 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()) 249 if (recorder_.get())
177 recorder_->UpdateSequenceNumber(sequence_number); 250 recorder_->UpdateSequenceNumber(sequence_number);
178 } 251 }
179 252
180 //////////////////////////////////////////////////////////////////////////// 253 ////////////////////////////////////////////////////////////////////////////
181 // SignalStrategy::StatusObserver implementations 254 // SignalStrategy::StatusObserver implementations
182 void ChromotingHost::OnStateChange( 255 void ChromotingHost::OnStateChange(
183 SignalStrategy::StatusObserver::State state) { 256 SignalStrategy::StatusObserver::State state) {
184 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); 257 DCHECK(context_->network_message_loop()->BelongsToCurrentThread());
185 258
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); 298 DCHECK(context_->network_message_loop()->BelongsToCurrentThread());
226 // Don't need to do anything here, just wait for incoming 299 // Don't need to do anything here, just wait for incoming
227 // connections. 300 // connections.
228 } 301 }
229 302
230 void ChromotingHost::OnIncomingSession( 303 void ChromotingHost::OnIncomingSession(
231 protocol::Session* session, 304 protocol::Session* session,
232 protocol::SessionManager::IncomingSessionResponse* response) { 305 protocol::SessionManager::IncomingSessionResponse* response) {
233 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); 306 DCHECK(context_->network_message_loop()->BelongsToCurrentThread());
234 307
235 base::AutoLock auto_lock(lock_);
236 if (state_ != kStarted) { 308 if (state_ != kStarted) {
237 *response = protocol::SessionManager::DECLINE; 309 *response = protocol::SessionManager::DECLINE;
238 return; 310 return;
239 } 311 }
240 312
241 // Check that the client has access to the host. 313 // Check that the client has access to the host.
242 if (!access_verifier_->VerifyPermissions(session->jid(), 314 if (!access_verifier_->VerifyPermissions(session->jid(),
243 session->initiator_token())) { 315 session->initiator_token())) {
244 *response = protocol::SessionManager::DECLINE; 316 *response = protocol::SessionManager::DECLINE;
245 317
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
284 356
285 *response = protocol::SessionManager::ACCEPT; 357 *response = protocol::SessionManager::ACCEPT;
286 358
287 LOG(INFO) << "Client connected: " << session->jid(); 359 LOG(INFO) << "Client connected: " << session->jid();
288 360
289 // Create a client object. 361 // Create a client object.
290 scoped_refptr<protocol::ConnectionToClient> connection = 362 scoped_refptr<protocol::ConnectionToClient> connection =
291 new protocol::ConnectionToClient(context_->network_message_loop(), 363 new protocol::ConnectionToClient(context_->network_message_loop(),
292 session); 364 session);
293 ClientSession* client = new ClientSession( 365 ClientSession* client = new ClientSession(
294 this, connection, 366 this, connection, desktop_environment_->event_executor(),
295 desktop_environment_->event_executor(),
296 desktop_environment_->capturer()); 367 desktop_environment_->capturer());
297
298 clients_.push_back(client); 368 clients_.push_back(client);
299 } 369 }
300 370
301 void ChromotingHost::set_protocol_config( 371 void ChromotingHost::set_protocol_config(
302 protocol::CandidateSessionConfig* config) { 372 protocol::CandidateSessionConfig* config) {
303 DCHECK(config_.get()); 373 DCHECK(config);
304 DCHECK_EQ(state_, kInitial); 374 DCHECK_EQ(state_, kInitial);
305 protocol_config_.reset(config); 375 protocol_config_.reset(config);
306 } 376 }
307 377
308 void ChromotingHost::LocalMouseMoved(const SkIPoint& new_pos) { 378 void ChromotingHost::LocalMouseMoved(const SkIPoint& new_pos) {
309 if (!context_->network_message_loop()->BelongsToCurrentThread()) { 379 if (!context_->network_message_loop()->BelongsToCurrentThread()) {
310 context_->network_message_loop()->PostTask( 380 context_->network_message_loop()->PostTask(
311 FROM_HERE, base::Bind(&ChromotingHost::LocalMouseMoved, this, new_pos)); 381 FROM_HERE, base::Bind(&ChromotingHost::LocalMouseMoved, this, new_pos));
312 return; 382 return;
313 } 383 }
384
314 ClientList::iterator client; 385 ClientList::iterator client;
315 for (client = clients_.begin(); client != clients_.end(); ++client) { 386 for (client = clients_.begin(); client != clients_.end(); ++client) {
316 client->get()->LocalMouseMoved(new_pos); 387 client->get()->LocalMouseMoved(new_pos);
317 } 388 }
318 } 389 }
319 390
320 void ChromotingHost::PauseSession(bool pause) { 391 void ChromotingHost::PauseSession(bool pause) {
321 if (context_->main_message_loop() != MessageLoop::current()) { 392 if (!context_->network_message_loop()->BelongsToCurrentThread()) {
322 context_->main_message_loop()->PostTask( 393 context_->network_message_loop()->PostTask(
323 FROM_HERE, 394 FROM_HERE,
324 NewRunnableMethod(this, 395 NewRunnableMethod(this,
325 &ChromotingHost::PauseSession, 396 &ChromotingHost::PauseSession,
326 pause)); 397 pause));
327 return; 398 return;
328 } 399 }
400
329 ClientList::iterator client; 401 ClientList::iterator client;
330 for (client = clients_.begin(); client != clients_.end(); ++client) { 402 for (client = clients_.begin(); client != clients_.end(); ++client) {
331 client->get()->set_awaiting_continue_approval(pause); 403 client->get()->set_awaiting_continue_approval(pause);
332 } 404 }
333 desktop_environment_->OnPause(pause); 405 desktop_environment_->OnPause(pause);
334 } 406 }
335 407
336 void ChromotingHost::SetUiStrings(const UiStrings& ui_strings) { 408 void ChromotingHost::SetUiStrings(const UiStrings& ui_strings) {
337 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); 409 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current());
338 DCHECK_EQ(state_, kInitial); 410 DCHECK_EQ(state_, kInitial);
339 411
340 ui_strings_ = ui_strings; 412 ui_strings_ = ui_strings;
341 } 413 }
342 414
343 void ChromotingHost::OnClientDisconnected(ClientSession* client) {
344 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current());
345
346 scoped_refptr<ClientSession> client_ref = client;
347
348 ClientList::iterator it;
349 for (it = clients_.begin(); it != clients_.end(); ++it) {
350 if (it->get() == client)
351 break;
352 }
353 clients_.erase(it);
354
355 if (recorder_.get()) {
356 recorder_->RemoveConnection(client->connection());
357 }
358
359 for (StatusObserverList::iterator it = status_observers_.begin();
360 it != status_observers_.end(); ++it) {
361 (*it)->OnClientDisconnected(client->client_jid());
362 }
363
364 if (AuthenticatedClientsCount() == 0) {
365 if (recorder_.get()) {
366 // Stop the recorder if there are no more clients.
367 StopScreenRecorder();
368 }
369
370 // Disable the "curtain" if there are no more active clients.
371 EnableCurtainMode(false);
372 desktop_environment_->OnLastDisconnect();
373 }
374 }
375
376 // TODO(sergeyu): Move this to SessionManager? 415 // TODO(sergeyu): Move this to SessionManager?
377 Encoder* ChromotingHost::CreateEncoder(const protocol::SessionConfig& config) { 416 Encoder* ChromotingHost::CreateEncoder(const protocol::SessionConfig& config) {
378 const protocol::ChannelConfig& video_config = config.video_config(); 417 const protocol::ChannelConfig& video_config = config.video_config();
379 418
380 if (video_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) { 419 if (video_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) {
381 return EncoderRowBased::CreateVerbatimEncoder(); 420 return EncoderRowBased::CreateVerbatimEncoder();
382 } else if (video_config.codec == protocol::ChannelConfig::CODEC_ZIP) { 421 } else if (video_config.codec == protocol::ChannelConfig::CODEC_ZIP) {
383 return EncoderRowBased::CreateZlibEncoder(); 422 return EncoderRowBased::CreateZlibEncoder();
384 } else if (video_config.codec == protocol::ChannelConfig::CODEC_VP8) { 423 } else if (video_config.codec == protocol::ChannelConfig::CODEC_VP8) {
385 return new remoting::EncoderVp8(); 424 return new remoting::EncoderVp8();
386 } 425 }
387 426
388 return NULL; 427 return NULL;
389 } 428 }
390 429
391 std::string ChromotingHost::GenerateHostAuthToken( 430 std::string ChromotingHost::GenerateHostAuthToken(
392 const std::string& encoded_client_token) { 431 const std::string& encoded_client_token) {
393 // TODO(ajwong): Return the signature of this instead. 432 // TODO(ajwong): Return the signature of this instead.
394 return encoded_client_token; 433 return encoded_client_token;
395 } 434 }
396 435
397 int ChromotingHost::AuthenticatedClientsCount() const { 436 int ChromotingHost::AuthenticatedClientsCount() const {
437 DCHECK(context_->network_message_loop()->BelongsToCurrentThread());
438
398 int authenticated_clients = 0; 439 int authenticated_clients = 0;
399 for (ClientList::const_iterator it = clients_.begin(); it != clients_.end(); 440 for (ClientList::const_iterator it = clients_.begin(); it != clients_.end();
400 ++it) { 441 ++it) {
401 if (it->get()->authenticated()) 442 if (it->get()->authenticated())
402 ++authenticated_clients; 443 ++authenticated_clients;
403 } 444 }
404 return authenticated_clients; 445 return authenticated_clients;
405 } 446 }
406 447
407 void ChromotingHost::EnableCurtainMode(bool enable) { 448 void ChromotingHost::EnableCurtainMode(bool enable) {
408 // TODO(jamiewalch): This will need to be more sophisticated when we think 449 // TODO(jamiewalch): This will need to be more sophisticated when we think
409 // about proper crash recovery and daemon mode. 450 // about proper crash recovery and daemon mode.
410 // TODO(wez): CurtainMode shouldn't be driven directly by ChromotingHost. 451 // TODO(wez): CurtainMode shouldn't be driven directly by ChromotingHost.
411 if (is_it2me_ || enable == is_curtained_) 452 if (is_it2me_ || enable == is_curtained_)
412 return; 453 return;
413 desktop_environment_->curtain()->EnableCurtainMode(enable); 454 desktop_environment_->curtain()->EnableCurtainMode(enable);
414 is_curtained_ = enable; 455 is_curtained_ = enable;
415 } 456 }
416 457
417 void ChromotingHost::AddAuthenticatedClient(
418 ClientSession* client,
419 const protocol::SessionConfig& config,
420 const std::string& jid) {
421 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current());
422
423 // Disconnect all other clients.
424 // Iterate over a copy of the list of clients, to avoid mutating the list
425 // while iterating over it.
426 ClientList clients_copy(clients_);
427 for (ClientList::const_iterator other_client = clients_copy.begin();
428 other_client != clients_copy.end(); ++other_client) {
429 if ((*other_client) != client) {
430 (*other_client)->Disconnect();
431 OnClientDisconnected(*other_client);
432 }
433 }
434
435 // Those disconnections should have killed the screen recorder.
436 CHECK(recorder_.get() == NULL);
437
438 // Create a new RecordSession if there was none.
439 if (!recorder_.get()) {
440 // Then we create a ScreenRecorder passing the message loops that
441 // it should run on.
442 Encoder* encoder = CreateEncoder(config);
443
444 recorder_ = new ScreenRecorder(context_->main_message_loop(),
445 context_->encode_message_loop(),
446 context_->network_message_loop(),
447 desktop_environment_->capturer(),
448 encoder);
449 }
450
451 // Immediately add the connection and start the session.
452 recorder_->AddConnection(client->connection());
453 recorder_->Start();
454 // Notify observers that there is at least one authenticated client.
455 for (StatusObserverList::iterator it = status_observers_.begin();
456 it != status_observers_.end(); ++it) {
457 (*it)->OnClientAuthenticated(jid);
458 }
459 // TODO(jamiewalch): Tidy up actions to be taken on connect/disconnect,
460 // including closing the connection on failure of a critical operation.
461 EnableCurtainMode(true);
462 if (is_it2me_) {
463 std::string username = jid;
464 size_t pos = username.find('/');
465 if (pos != std::string::npos)
466 username.replace(pos, std::string::npos, "");
467 desktop_environment_->OnConnect(username);
468 }
469 }
470
471 void ChromotingHost::StopScreenRecorder() { 458 void ChromotingHost::StopScreenRecorder() {
472 DCHECK(MessageLoop::current() == context_->main_message_loop()); 459 DCHECK(context_->network_message_loop()->BelongsToCurrentThread());
473 DCHECK(recorder_.get()); 460 DCHECK(recorder_.get());
474 461
475 ++stopping_recorders_; 462 ++stopping_recorders_;
476 recorder_->Stop(base::Bind(&ChromotingHost::OnScreenRecorderStopped, this)); 463 scoped_refptr<ScreenRecorder> recorder = recorder_;
477 recorder_ = NULL; 464 recorder_ = NULL;
465 recorder->Stop(base::Bind(&ChromotingHost::OnScreenRecorderStopped, this));
478 } 466 }
479 467
480 void ChromotingHost::OnScreenRecorderStopped() { 468 void ChromotingHost::OnScreenRecorderStopped() {
481 if (MessageLoop::current() != context_->main_message_loop()) { 469 if (!context_->network_message_loop()->BelongsToCurrentThread()) {
482 context_->main_message_loop()->PostTask( 470 context_->network_message_loop()->PostTask(
483 FROM_HERE, base::Bind(&ChromotingHost::OnScreenRecorderStopped, this)); 471 FROM_HERE, base::Bind(&ChromotingHost::OnScreenRecorderStopped, this));
484 return; 472 return;
485 } 473 }
486 474
487 --stopping_recorders_; 475 --stopping_recorders_;
488 DCHECK_GE(stopping_recorders_, 0); 476 DCHECK_GE(stopping_recorders_, 0);
489 477
490 bool stopping; 478 if (!stopping_recorders_ && state_ == kStopping)
491 {
492 base::AutoLock auto_lock(lock_);
493 stopping = state_ == kStopping;
494 }
495
496 if (!stopping_recorders_ && stopping)
497 ShutdownFinish(); 479 ShutdownFinish();
498 } 480 }
499 481
500 void ChromotingHost::ShutdownNetwork() { 482 void ChromotingHost::ShutdownFinish() {
501 if (!context_->network_message_loop()->BelongsToCurrentThread()) { 483 DCHECK(context_->network_message_loop()->BelongsToCurrentThread());
502 context_->network_message_loop()->PostTask(
503 FROM_HERE, base::Bind(&ChromotingHost::ShutdownNetwork, this));
504 return;
505 }
506 484
507 // Stop chromotocol session manager. 485 state_ = kStopped;
508 if (session_manager_.get()) {
509 session_manager_->Close();
510 session_manager_.reset();
511 }
512
513 // Stop XMPP connection.
514 if (signal_strategy_.get()) {
515 signal_strategy_->Close();
516 signal_strategy_.reset();
517
518 for (StatusObserverList::iterator it = status_observers_.begin();
519 it != status_observers_.end(); ++it) {
520 (*it)->OnSignallingDisconnected();
521 }
522 }
523
524 ShutdownRecorder();
525 }
526
527 void ChromotingHost::ShutdownRecorder() {
528 if (MessageLoop::current() != context_->main_message_loop()) {
529 context_->main_message_loop()->PostTask(
530 FROM_HERE, base::Bind(&ChromotingHost::ShutdownRecorder, this));
531 return;
532 }
533
534 if (recorder_.get()) {
535 StopScreenRecorder();
536 } else if (!stopping_recorders_) {
537 ShutdownFinish();
538 }
539 }
540
541 void ChromotingHost::ShutdownFinish() {
542 if (MessageLoop::current() != context_->main_message_loop()) {
543 context_->main_message_loop()->PostTask(
544 FROM_HERE, base::Bind(&ChromotingHost::ShutdownFinish, this));
545 return;
546 }
547
548 {
549 base::AutoLock auto_lock(lock_);
550 state_ = kStopped;
551 }
552 486
553 // Keep reference to |this|, so that we don't get destroyed while 487 // Keep reference to |this|, so that we don't get destroyed while
554 // sending notifications. 488 // sending notifications.
555 scoped_refptr<ChromotingHost> self(this); 489 scoped_refptr<ChromotingHost> self(this);
556 490
557 // Notify observers. 491 // Notify observers.
558 for (StatusObserverList::iterator it = status_observers_.begin(); 492 for (StatusObserverList::iterator it = status_observers_.begin();
559 it != status_observers_.end(); ++it) { 493 it != status_observers_.end(); ++it) {
560 (*it)->OnShutdown(); 494 (*it)->OnShutdown();
561 } 495 }
562 496
563 for (std::vector<Task*>::iterator it = shutdown_tasks_.begin(); 497 for (std::vector<Task*>::iterator it = shutdown_tasks_.begin();
564 it != shutdown_tasks_.end(); ++it) { 498 it != shutdown_tasks_.end(); ++it) {
565 (*it)->Run(); 499 (*it)->Run();
566 delete *it; 500 delete *it;
567 } 501 }
568 shutdown_tasks_.clear(); 502 shutdown_tasks_.clear();
569 } 503 }
570 504
571 } // namespace remoting 505 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698