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 |
(...skipping 29 matching lines...) Expand all Loading... | |
98 | 98 |
99 signal_strategy_.reset( | 99 signal_strategy_.reset( |
100 new XmppSignalStrategy(context_->jingle_thread(), xmpp_login, | 100 new XmppSignalStrategy(context_->jingle_thread(), xmpp_login, |
101 xmpp_auth_token, | 101 xmpp_auth_token, |
102 xmpp_auth_service)); | 102 xmpp_auth_service)); |
103 signal_strategy_->Init(this); | 103 signal_strategy_->Init(this); |
104 } | 104 } |
105 | 105 |
106 // This method is called when we need to destroy the host process. | 106 // This method is called when we need to destroy the host process. |
107 void ChromotingHost::Shutdown(Task* shutdown_task) { | 107 void ChromotingHost::Shutdown(Task* shutdown_task) { |
108 if (MessageLoop::current() != context_->main_message_loop()) { | 108 if (!context_->network_message_loop()->BelongsToCurrentThread()) { |
109 context_->main_message_loop()->PostTask( | 109 context_->network_message_loop()->PostTask( |
110 FROM_HERE, | 110 FROM_HERE, base::Bind(&ChromotingHost::Shutdown, this, shutdown_task)); |
111 base::Bind(&ChromotingHost::Shutdown, this, shutdown_task)); | |
112 return; | 111 return; |
113 } | 112 } |
114 | 113 |
115 // No-op if this object is not started yet. | 114 // No-op if this object is not started yet. |
116 { | 115 { |
117 base::AutoLock auto_lock(lock_); | 116 base::AutoLock auto_lock(lock_); |
118 if (state_ == kInitial || state_ == kStopped) { | 117 if (state_ == kInitial || state_ == kStopped) { |
119 // Nothing to do if we are not started. | 118 // Nothing to do if we are not started. |
120 state_ = kStopped; | 119 state_ = kStopped; |
121 context_->main_message_loop()->PostTask(FROM_HERE, shutdown_task); | 120 context_->network_message_loop()->PostTask(FROM_HERE, shutdown_task); |
122 return; | 121 return; |
123 } | 122 } |
124 if (shutdown_task) | 123 if (shutdown_task) |
125 shutdown_tasks_.push_back(shutdown_task); | 124 shutdown_tasks_.push_back(shutdown_task); |
126 if (state_ == kStopping) | 125 if (state_ == kStopping) |
127 return; | 126 return; |
128 state_ = kStopping; | 127 state_ = kStopping; |
129 } | 128 } |
130 | 129 |
131 // Disconnect all of the clients, implicitly stopping the ScreenRecorder. | 130 // Disconnect all of the clients, implicitly stopping the ScreenRecorder. |
132 while (!clients_.empty()) { | 131 while (!clients_.empty()) { |
133 scoped_refptr<ClientSession> client = clients_.front(); | 132 scoped_refptr<ClientSession> client = clients_.front(); |
134 client->Disconnect(); | 133 client->Disconnect(); |
135 OnClientDisconnected(client); | 134 OnSessionClosed(client); |
136 } | 135 } |
137 | 136 |
138 ShutdownNetwork(); | 137 // Stop chromotocol session manager. |
Wez
2011/11/09 02:32:22
nit: chromotocol -> Chromotocol.
Wez
2011/11/09 02:32:22
Clarify that we're guaranteed no more callbacks af
Sergey Ulanov
2011/11/09 21:24:00
Changed to Stop session manager.
Sergey Ulanov
2011/11/09 21:24:00
This is specified in SessionManager header. Don't
| |
138 if (session_manager_.get()) { | |
139 session_manager_->Close(); | |
140 context_->network_message_loop()->PostTask(FROM_HERE, base::Bind( | |
141 &DeletePointer<protocol::SessionManager>, session_manager_.release())); | |
Wez
2011/11/09 02:32:22
This looks like a DeleteSoon()? Clarify in the co
Sergey Ulanov
2011/11/09 21:24:00
Done.
| |
142 } | |
143 | |
144 // Stop XMPP connection. | |
Wez
2011/11/09 02:32:22
Clarify that this is synchronous?
Sergey Ulanov
2011/11/09 21:24:00
Done.
| |
145 if (signal_strategy_.get()) { | |
146 signal_strategy_->Close(); | |
147 signal_strategy_.reset(); | |
148 | |
149 for (StatusObserverList::iterator it = status_observers_.begin(); | |
150 it != status_observers_.end(); ++it) { | |
151 (*it)->OnSignallingDisconnected(); | |
152 } | |
153 } | |
154 | |
155 if (recorder_.get()) { | |
156 StopScreenRecorder(); | |
157 } else { | |
158 ShutdownFinish(); | |
159 } | |
139 } | 160 } |
140 | 161 |
141 void ChromotingHost::AddStatusObserver(HostStatusObserver* observer) { | 162 void ChromotingHost::AddStatusObserver(HostStatusObserver* observer) { |
142 DCHECK_EQ(state_, kInitial); | 163 DCHECK_EQ(state_, kInitial); |
143 status_observers_.push_back(observer); | 164 status_observers_.push_back(observer); |
144 } | 165 } |
145 | 166 |
146 //////////////////////////////////////////////////////////////////////////// | 167 //////////////////////////////////////////////////////////////////////////// |
147 // protocol::ClientSession::EventHandler implementation. | 168 // protocol::ClientSession::EventHandler implementation. |
148 void ChromotingHost::OnSessionAuthenticated(ClientSession* client) { | 169 void ChromotingHost::OnSessionAuthenticated(ClientSession* client) { |
149 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); | 170 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
150 protocol::Session* session = client->connection()->session(); | 171 |
151 context_->main_message_loop()->PostTask( | 172 // Disconnect all other clients. |
152 FROM_HERE, base::Bind(&ChromotingHost::AddAuthenticatedClient, | 173 // Iterate over a copy of the list of clients, to avoid mutating the list |
153 this, make_scoped_refptr(client), | 174 // while iterating over it. |
154 session->config(), session->jid())); | 175 ClientList clients_copy(clients_); |
176 for (ClientList::const_iterator other_client = clients_copy.begin(); | |
177 other_client != clients_copy.end(); ++other_client) { | |
178 if ((*other_client) != client) { | |
179 (*other_client)->Disconnect(); | |
180 OnSessionClosed(*other_client); | |
Wez
2011/11/09 02:32:22
If Disconnect() is made to trigger OnSessionClosed
Sergey Ulanov
2011/11/09 21:24:00
I don't think that Disconnect() should trigger OnS
Wez
2011/11/09 23:18:45
Why not? The EventHandler really only cares that
Sergey Ulanov
2011/11/10 21:06:14
Ok. I've changed Disconnect() to trigger OnSession
| |
181 } | |
182 } | |
183 | |
184 // Those disconnections should have killed the screen recorder. | |
185 CHECK(recorder_.get() == NULL); | |
Wez
2011/11/09 02:32:22
We're in OnSessionAuthenticated(), so surely this
Sergey Ulanov
2011/11/09 21:24:00
Recorder is created after client is authenticated,
Wez
2011/11/09 23:18:45
But by the time we reach here the client we're add
Sergey Ulanov
2011/11/10 21:06:14
I see your point now. Removed this CHECK because i
| |
186 | |
187 // Create a new RecordSession if there was none. | |
188 if (!recorder_.get()) { | |
189 // Then we create a ScreenRecorder passing the message loops that | |
190 // it should run on. | |
191 Encoder* encoder = CreateEncoder(client->connection()->session()->config()); | |
192 | |
193 recorder_ = new ScreenRecorder(context_->main_message_loop(), | |
194 context_->encode_message_loop(), | |
195 context_->network_message_loop(), | |
196 desktop_environment_->capturer(), | |
197 encoder); | |
198 } | |
199 | |
200 // Immediately add the connection and start the session. | |
201 recorder_->AddConnection(client->connection()); | |
202 recorder_->Start(); | |
203 | |
204 const std::string& jid = client->connection()->session()->jid(); | |
Wez
2011/11/09 02:32:22
nit: Move this after the Notify observers comment?
Sergey Ulanov
2011/11/09 21:24:00
Done.
| |
205 | |
206 // Notify observers that there is at least one authenticated client. | |
207 for (StatusObserverList::iterator it = status_observers_.begin(); | |
208 it != status_observers_.end(); ++it) { | |
209 (*it)->OnClientAuthenticated(jid); | |
210 } | |
211 // TODO(jamiewalch): Tidy up actions to be taken on connect/disconnect, | |
212 // including closing the connection on failure of a critical operation. | |
213 EnableCurtainMode(true); | |
214 | |
215 std::string username = jid; | |
Wez
2011/11/09 02:32:22
Why not just take a copy of the JID in the first p
Sergey Ulanov
2011/11/09 21:24:00
Simplified this code to use substr().
| |
216 size_t pos = username.find('/'); | |
217 if (pos != std::string::npos) | |
218 username.erase(pos); | |
219 desktop_environment_->OnConnect(username); | |
155 } | 220 } |
156 | 221 |
157 void ChromotingHost::OnSessionClosed(ClientSession* client) { | 222 void ChromotingHost::OnSessionClosed(ClientSession* client) { |
158 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); | 223 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
159 | 224 |
160 VLOG(1) << "Connection to client closed."; | 225 scoped_refptr<ClientSession> client_ref = client; |
161 context_->main_message_loop()->PostTask( | 226 |
162 FROM_HERE, base::Bind(&ChromotingHost::OnClientDisconnected, this, | 227 ClientList::iterator it = std::find(clients_.begin(), clients_.end(), client); |
163 make_scoped_refptr(client))); | 228 CHECK(it != clients_.end()); |
229 clients_.erase(it); | |
230 | |
231 if (recorder_.get()) { | |
232 recorder_->RemoveConnection(client->connection()); | |
233 } | |
234 | |
235 for (StatusObserverList::iterator it = status_observers_.begin(); | |
236 it != status_observers_.end(); ++it) { | |
237 (*it)->OnClientDisconnected(client->client_jid()); | |
238 } | |
239 | |
240 if (AuthenticatedClientsCount() == 0) { | |
241 if (recorder_.get()) { | |
242 // Stop the recorder if there are no more clients. | |
243 StopScreenRecorder(); | |
244 } | |
245 | |
246 // Disable the "curtain" if there are no more active clients. | |
247 EnableCurtainMode(false); | |
248 desktop_environment_->OnLastDisconnect(); | |
249 } | |
164 } | 250 } |
165 | 251 |
166 void ChromotingHost::OnSessionSequenceNumber(ClientSession* session, | 252 void ChromotingHost::OnSessionSequenceNumber(ClientSession* session, |
167 int64 sequence_number) { | 253 int64 sequence_number) { |
168 // Update the sequence number in ScreenRecorder. | 254 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()) | 255 if (recorder_.get()) |
177 recorder_->UpdateSequenceNumber(sequence_number); | 256 recorder_->UpdateSequenceNumber(sequence_number); |
178 } | 257 } |
179 | 258 |
180 //////////////////////////////////////////////////////////////////////////// | 259 //////////////////////////////////////////////////////////////////////////// |
181 // SignalStrategy::StatusObserver implementations | 260 // SignalStrategy::StatusObserver implementations |
182 void ChromotingHost::OnStateChange( | 261 void ChromotingHost::OnStateChange( |
183 SignalStrategy::StatusObserver::State state) { | 262 SignalStrategy::StatusObserver::State state) { |
184 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); | 263 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
185 | 264 |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
284 | 363 |
285 *response = protocol::SessionManager::ACCEPT; | 364 *response = protocol::SessionManager::ACCEPT; |
286 | 365 |
287 LOG(INFO) << "Client connected: " << session->jid(); | 366 LOG(INFO) << "Client connected: " << session->jid(); |
288 | 367 |
289 // Create a client object. | 368 // Create a client object. |
290 scoped_refptr<protocol::ConnectionToClient> connection = | 369 scoped_refptr<protocol::ConnectionToClient> connection = |
291 new protocol::ConnectionToClient(context_->network_message_loop(), | 370 new protocol::ConnectionToClient(context_->network_message_loop(), |
292 session); | 371 session); |
293 ClientSession* client = new ClientSession( | 372 ClientSession* client = new ClientSession( |
294 this, connection, | 373 this, connection, desktop_environment_->event_executor(), |
295 desktop_environment_->event_executor(), | |
296 desktop_environment_->capturer()); | 374 desktop_environment_->capturer()); |
297 | |
298 clients_.push_back(client); | 375 clients_.push_back(client); |
299 } | 376 } |
300 | 377 |
301 void ChromotingHost::set_protocol_config( | 378 void ChromotingHost::set_protocol_config( |
302 protocol::CandidateSessionConfig* config) { | 379 protocol::CandidateSessionConfig* config) { |
303 DCHECK(config_.get()); | 380 DCHECK(config_.get()); |
304 DCHECK_EQ(state_, kInitial); | 381 DCHECK_EQ(state_, kInitial); |
305 protocol_config_.reset(config); | 382 protocol_config_.reset(config); |
Wez
2011/11/09 02:32:22
Not part of this CL, but this is client-specific,
Sergey Ulanov
2011/11/09 21:24:00
Actually it is not client-specific - this sets Can
| |
306 } | 383 } |
307 | 384 |
308 void ChromotingHost::LocalMouseMoved(const SkIPoint& new_pos) { | 385 void ChromotingHost::LocalMouseMoved(const SkIPoint& new_pos) { |
309 if (!context_->network_message_loop()->BelongsToCurrentThread()) { | 386 if (!context_->network_message_loop()->BelongsToCurrentThread()) { |
310 context_->network_message_loop()->PostTask( | 387 context_->network_message_loop()->PostTask( |
311 FROM_HERE, base::Bind(&ChromotingHost::LocalMouseMoved, this, new_pos)); | 388 FROM_HERE, base::Bind(&ChromotingHost::LocalMouseMoved, this, new_pos)); |
312 return; | 389 return; |
313 } | 390 } |
391 | |
314 ClientList::iterator client; | 392 ClientList::iterator client; |
315 for (client = clients_.begin(); client != clients_.end(); ++client) { | 393 for (client = clients_.begin(); client != clients_.end(); ++client) { |
316 client->get()->LocalMouseMoved(new_pos); | 394 client->get()->LocalMouseMoved(new_pos); |
317 } | 395 } |
318 } | 396 } |
319 | 397 |
320 void ChromotingHost::PauseSession(bool pause) { | 398 void ChromotingHost::PauseSession(bool pause) { |
321 if (context_->main_message_loop() != MessageLoop::current()) { | 399 if (!context_->network_message_loop()->BelongsToCurrentThread()) { |
322 context_->main_message_loop()->PostTask( | 400 context_->network_message_loop()->PostTask( |
323 FROM_HERE, | 401 FROM_HERE, |
324 NewRunnableMethod(this, | 402 NewRunnableMethod(this, |
325 &ChromotingHost::PauseSession, | 403 &ChromotingHost::PauseSession, |
326 pause)); | 404 pause)); |
327 return; | 405 return; |
328 } | 406 } |
407 | |
329 ClientList::iterator client; | 408 ClientList::iterator client; |
330 for (client = clients_.begin(); client != clients_.end(); ++client) { | 409 for (client = clients_.begin(); client != clients_.end(); ++client) { |
331 client->get()->set_awaiting_continue_approval(pause); | 410 client->get()->set_awaiting_continue_approval(pause); |
332 } | 411 } |
333 desktop_environment_->OnPause(pause); | 412 desktop_environment_->OnPause(pause); |
Wez
2011/11/09 02:32:22
Is this callable on the network thread?
Sergey Ulanov
2011/11/09 21:24:00
Yes. All DesktopEnvironment methods can be called
| |
334 } | 413 } |
335 | 414 |
336 void ChromotingHost::SetUiStrings(const UiStrings& ui_strings) { | 415 void ChromotingHost::SetUiStrings(const UiStrings& ui_strings) { |
337 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); | 416 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); |
338 DCHECK_EQ(state_, kInitial); | 417 DCHECK_EQ(state_, kInitial); |
339 | 418 |
340 ui_strings_ = ui_strings; | 419 ui_strings_ = ui_strings; |
341 } | 420 } |
342 | 421 |
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? | 422 // TODO(sergeyu): Move this to SessionManager? |
377 Encoder* ChromotingHost::CreateEncoder(const protocol::SessionConfig& config) { | 423 Encoder* ChromotingHost::CreateEncoder(const protocol::SessionConfig& config) { |
378 const protocol::ChannelConfig& video_config = config.video_config(); | 424 const protocol::ChannelConfig& video_config = config.video_config(); |
379 | 425 |
380 if (video_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) { | 426 if (video_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) { |
381 return EncoderRowBased::CreateVerbatimEncoder(); | 427 return EncoderRowBased::CreateVerbatimEncoder(); |
382 } else if (video_config.codec == protocol::ChannelConfig::CODEC_ZIP) { | 428 } else if (video_config.codec == protocol::ChannelConfig::CODEC_ZIP) { |
383 return EncoderRowBased::CreateZlibEncoder(); | 429 return EncoderRowBased::CreateZlibEncoder(); |
384 } else if (video_config.codec == protocol::ChannelConfig::CODEC_VP8) { | 430 } else if (video_config.codec == protocol::ChannelConfig::CODEC_VP8) { |
385 return new remoting::EncoderVp8(); | 431 return new remoting::EncoderVp8(); |
386 } | 432 } |
387 | 433 |
388 return NULL; | 434 return NULL; |
389 } | 435 } |
390 | 436 |
391 std::string ChromotingHost::GenerateHostAuthToken( | 437 std::string ChromotingHost::GenerateHostAuthToken( |
392 const std::string& encoded_client_token) { | 438 const std::string& encoded_client_token) { |
393 // TODO(ajwong): Return the signature of this instead. | 439 // TODO(ajwong): Return the signature of this instead. |
394 return encoded_client_token; | 440 return encoded_client_token; |
395 } | 441 } |
396 | 442 |
397 int ChromotingHost::AuthenticatedClientsCount() const { | 443 int ChromotingHost::AuthenticatedClientsCount() const { |
444 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); | |
445 | |
398 int authenticated_clients = 0; | 446 int authenticated_clients = 0; |
399 for (ClientList::const_iterator it = clients_.begin(); it != clients_.end(); | 447 for (ClientList::const_iterator it = clients_.begin(); it != clients_.end(); |
400 ++it) { | 448 ++it) { |
401 if (it->get()->authenticated()) | 449 if (it->get()->authenticated()) |
402 ++authenticated_clients; | 450 ++authenticated_clients; |
403 } | 451 } |
404 return authenticated_clients; | 452 return authenticated_clients; |
405 } | 453 } |
406 | 454 |
407 void ChromotingHost::EnableCurtainMode(bool enable) { | 455 void ChromotingHost::EnableCurtainMode(bool enable) { |
408 // TODO(jamiewalch): This will need to be more sophisticated when we think | 456 // TODO(jamiewalch): This will need to be more sophisticated when we think |
409 // about proper crash recovery and daemon mode. | 457 // about proper crash recovery and daemon mode. |
410 // TODO(wez): CurtainMode shouldn't be driven directly by ChromotingHost. | 458 // TODO(wez): CurtainMode shouldn't be driven directly by ChromotingHost. |
411 if (is_it2me_ || enable == is_curtained_) | 459 if (is_it2me_ || enable == is_curtained_) |
412 return; | 460 return; |
413 desktop_environment_->curtain()->EnableCurtainMode(enable); | 461 desktop_environment_->curtain()->EnableCurtainMode(enable); |
414 is_curtained_ = enable; | 462 is_curtained_ = enable; |
415 } | 463 } |
416 | 464 |
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() { | 465 void ChromotingHost::StopScreenRecorder() { |
472 DCHECK(MessageLoop::current() == context_->main_message_loop()); | 466 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
473 DCHECK(recorder_.get()); | 467 DCHECK(recorder_.get()); |
474 | 468 |
475 ++stopping_recorders_; | 469 ++stopping_recorders_; |
476 recorder_->Stop(base::Bind(&ChromotingHost::OnScreenRecorderStopped, this)); | 470 recorder_->Stop(base::Bind(&ChromotingHost::OnScreenRecorderStopped, this)); |
477 recorder_ = NULL; | 471 recorder_ = NULL; |
Wez
2011/11/09 02:32:22
Does ScreenRecorder::Stop() guarantee to NOT invok
Sergey Ulanov
2011/11/09 21:24:00
Good catch. Fixed, though it should not be a probl
| |
478 } | 472 } |
479 | 473 |
480 void ChromotingHost::OnScreenRecorderStopped() { | 474 void ChromotingHost::OnScreenRecorderStopped() { |
481 if (MessageLoop::current() != context_->main_message_loop()) { | 475 if (!context_->network_message_loop()->BelongsToCurrentThread()) { |
482 context_->main_message_loop()->PostTask( | 476 context_->network_message_loop()->PostTask( |
483 FROM_HERE, base::Bind(&ChromotingHost::OnScreenRecorderStopped, this)); | 477 FROM_HERE, base::Bind(&ChromotingHost::OnScreenRecorderStopped, this)); |
484 return; | 478 return; |
485 } | 479 } |
486 | 480 |
487 --stopping_recorders_; | 481 --stopping_recorders_; |
488 DCHECK_GE(stopping_recorders_, 0); | 482 DCHECK_GE(stopping_recorders_, 0); |
489 | 483 |
490 bool stopping; | 484 bool stopping; |
491 { | 485 { |
492 base::AutoLock auto_lock(lock_); | 486 base::AutoLock auto_lock(lock_); |
493 stopping = state_ == kStopping; | 487 stopping = state_ == kStopping; |
494 } | 488 } |
495 | 489 |
496 if (!stopping_recorders_ && stopping) | 490 if (!stopping_recorders_ && stopping) |
497 ShutdownFinish(); | 491 ShutdownFinish(); |
498 } | 492 } |
499 | 493 |
500 void ChromotingHost::ShutdownNetwork() { | |
501 if (!context_->network_message_loop()->BelongsToCurrentThread()) { | |
502 context_->network_message_loop()->PostTask( | |
503 FROM_HERE, base::Bind(&ChromotingHost::ShutdownNetwork, this)); | |
504 return; | |
505 } | |
506 | |
507 // Stop chromotocol session manager. | |
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() { | 494 void ChromotingHost::ShutdownFinish() { |
542 if (MessageLoop::current() != context_->main_message_loop()) { | 495 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
543 context_->main_message_loop()->PostTask( | |
544 FROM_HERE, base::Bind(&ChromotingHost::ShutdownFinish, this)); | |
545 return; | |
546 } | |
547 | 496 |
548 { | 497 { |
549 base::AutoLock auto_lock(lock_); | 498 base::AutoLock auto_lock(lock_); |
550 state_ = kStopped; | 499 state_ = kStopped; |
551 } | 500 } |
552 | 501 |
553 // Keep reference to |this|, so that we don't get destroyed while | 502 // Keep reference to |this|, so that we don't get destroyed while |
554 // sending notifications. | 503 // sending notifications. |
555 scoped_refptr<ChromotingHost> self(this); | 504 scoped_refptr<ChromotingHost> self(this); |
556 | 505 |
557 // Notify observers. | 506 // Notify observers. |
558 for (StatusObserverList::iterator it = status_observers_.begin(); | 507 for (StatusObserverList::iterator it = status_observers_.begin(); |
559 it != status_observers_.end(); ++it) { | 508 it != status_observers_.end(); ++it) { |
560 (*it)->OnShutdown(); | 509 (*it)->OnShutdown(); |
Wez
2011/11/09 02:32:22
We're notifying observers on a different thread to
Sergey Ulanov
2011/11/09 21:24:00
There is only one observer that cares about this e
| |
561 } | 510 } |
562 | 511 |
563 for (std::vector<Task*>::iterator it = shutdown_tasks_.begin(); | 512 for (std::vector<Task*>::iterator it = shutdown_tasks_.begin(); |
564 it != shutdown_tasks_.end(); ++it) { | 513 it != shutdown_tasks_.end(); ++it) { |
565 (*it)->Run(); | 514 (*it)->Run(); |
566 delete *it; | 515 delete *it; |
567 } | 516 } |
568 shutdown_tasks_.clear(); | 517 shutdown_tasks_.clear(); |
569 } | 518 } |
570 | 519 |
520 | |
571 } // namespace remoting | 521 } // namespace remoting |
OLD | NEW |