Chromium Code Reviews| 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(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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |