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
« no previous file with comments | « remoting/host/chromoting_host.h ('k') | remoting/host/chromoting_host_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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(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
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
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
OLDNEW
« no previous file with comments | « remoting/host/chromoting_host.h ('k') | remoting/host/chromoting_host_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698