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 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
123 } | 123 } |
124 if (shutdown_task) | 124 if (shutdown_task) |
125 shutdown_tasks_.push_back(shutdown_task); | 125 shutdown_tasks_.push_back(shutdown_task); |
126 if (state_ == kStopping) | 126 if (state_ == kStopping) |
127 return; | 127 return; |
128 state_ = kStopping; | 128 state_ = kStopping; |
129 } | 129 } |
130 | 130 |
131 // Disconnect all of the clients, implicitly stopping the ScreenRecorder. | 131 // Disconnect all of the clients, implicitly stopping the ScreenRecorder. |
132 while (!clients_.empty()) { | 132 while (!clients_.empty()) { |
133 OnClientDisconnected(clients_.front()->connection()); | 133 scoped_refptr<ClientSession> client = clients_.front(); |
134 client->Disconnect(); | |
135 OnClientDisconnected(client); | |
Wez
2011/11/09 01:35:07
It seems strange that client->Disconnect() doesn't
Sergey Ulanov
2011/11/09 19:26:13
That is intentional. I think the code is simpler w
Wez
2011/11/09 23:34:50
I think it's different in this case. ChromotingHo
Sergey Ulanov
2011/11/10 00:55:57
I agree that it may not be a problem in this parti
Wez
2011/11/10 01:25:12
The caller can't touch the session object after Di
| |
134 } | 136 } |
135 | 137 |
136 ShutdownNetwork(); | 138 ShutdownNetwork(); |
137 } | 139 } |
138 | 140 |
139 void ChromotingHost::AddStatusObserver(HostStatusObserver* observer) { | 141 void ChromotingHost::AddStatusObserver(HostStatusObserver* observer) { |
140 DCHECK_EQ(state_, kInitial); | 142 DCHECK_EQ(state_, kInitial); |
141 status_observers_.push_back(observer); | 143 status_observers_.push_back(observer); |
142 } | 144 } |
143 | 145 |
144 //////////////////////////////////////////////////////////////////////////// | 146 //////////////////////////////////////////////////////////////////////////// |
145 // protocol::ConnectionToClient::EventHandler implementations | 147 // protocol::ClientSession::EventHandler implementation. |
146 void ChromotingHost::OnConnectionOpened(ConnectionToClient* connection) { | 148 void ChromotingHost::OnSessionAuthenticated(ClientSession* client) { |
147 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); | 149 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
148 VLOG(1) << "Connection to client established."; | 150 protocol::Session* session = client->connection()->session(); |
149 context_->main_message_loop()->PostTask( | 151 context_->main_message_loop()->PostTask( |
150 FROM_HERE, base::Bind(&ChromotingHost::ProcessPreAuthentication, this, | 152 FROM_HERE, base::Bind(&ChromotingHost::AddAuthenticatedClient, |
151 make_scoped_refptr(connection))); | 153 this, make_scoped_refptr(client), |
154 session->config(), session->jid())); | |
152 } | 155 } |
153 | 156 |
154 void ChromotingHost::OnConnectionClosed(ConnectionToClient* connection) { | 157 void ChromotingHost::OnSessionClosed(ClientSession* client) { |
155 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); | 158 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); |
156 | 159 |
157 VLOG(1) << "Connection to client closed."; | 160 VLOG(1) << "Connection to client closed."; |
158 context_->main_message_loop()->PostTask( | 161 context_->main_message_loop()->PostTask( |
159 FROM_HERE, base::Bind(&ChromotingHost::OnClientDisconnected, this, | 162 FROM_HERE, base::Bind(&ChromotingHost::OnClientDisconnected, this, |
160 make_scoped_refptr(connection))); | 163 make_scoped_refptr(client))); |
161 } | 164 } |
162 | 165 |
163 void ChromotingHost::OnConnectionFailed(ConnectionToClient* connection) { | 166 void ChromotingHost::OnSessionSequenceNumber(ClientSession* session, |
164 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); | |
165 | |
166 LOG(ERROR) << "Connection failed unexpectedly."; | |
167 context_->main_message_loop()->PostTask( | |
168 FROM_HERE, base::Bind(&ChromotingHost::OnClientDisconnected, this, | |
169 make_scoped_refptr(connection))); | |
170 } | |
171 | |
172 void ChromotingHost::OnSequenceNumberUpdated(ConnectionToClient* connection, | |
173 int64 sequence_number) { | 167 int64 sequence_number) { |
174 // Update the sequence number in ScreenRecorder. | 168 // Update the sequence number in ScreenRecorder. |
175 if (MessageLoop::current() != context_->main_message_loop()) { | 169 if (MessageLoop::current() != context_->main_message_loop()) { |
176 context_->main_message_loop()->PostTask( | 170 context_->main_message_loop()->PostTask( |
177 FROM_HERE, base::Bind(&ChromotingHost::OnSequenceNumberUpdated, this, | 171 FROM_HERE, base::Bind(&ChromotingHost::OnSessionSequenceNumber, this, |
178 make_scoped_refptr(connection), sequence_number)); | 172 make_scoped_refptr(session), sequence_number)); |
179 return; | 173 return; |
180 } | 174 } |
181 | 175 |
182 if (recorder_.get()) | 176 if (recorder_.get()) |
183 recorder_->UpdateSequenceNumber(sequence_number); | 177 recorder_->UpdateSequenceNumber(sequence_number); |
184 } | 178 } |
185 | 179 |
186 //////////////////////////////////////////////////////////////////////////// | 180 //////////////////////////////////////////////////////////////////////////// |
187 // SignalStrategy::StatusObserver implementations | 181 // SignalStrategy::StatusObserver implementations |
188 void ChromotingHost::OnStateChange( | 182 void ChromotingHost::OnStateChange( |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
285 session->set_receiver_token( | 279 session->set_receiver_token( |
286 GenerateHostAuthToken(session->initiator_token())); | 280 GenerateHostAuthToken(session->initiator_token())); |
287 | 281 |
288 // Provide the Access Code as shared secret for SSL channel authentication. | 282 // Provide the Access Code as shared secret for SSL channel authentication. |
289 session->set_shared_secret(access_code_); | 283 session->set_shared_secret(access_code_); |
290 | 284 |
291 *response = protocol::SessionManager::ACCEPT; | 285 *response = protocol::SessionManager::ACCEPT; |
292 | 286 |
293 LOG(INFO) << "Client connected: " << session->jid(); | 287 LOG(INFO) << "Client connected: " << session->jid(); |
294 | 288 |
295 // We accept the connection, so create a connection object. | |
296 ConnectionToClient* connection = new ConnectionToClient( | |
297 context_->network_message_loop(), this); | |
298 connection->Init(session); | |
299 | |
300 // Create a client object. | 289 // Create a client object. |
290 scoped_refptr<protocol::ConnectionToClient> connection = | |
291 new protocol::ConnectionToClient(context_->network_message_loop(), | |
292 session); | |
301 ClientSession* client = new ClientSession( | 293 ClientSession* client = new ClientSession( |
302 this, | 294 this, connection, |
303 connection, | |
304 desktop_environment_->event_executor(), | 295 desktop_environment_->event_executor(), |
305 desktop_environment_->capturer()); | 296 desktop_environment_->capturer()); |
306 connection->set_host_stub(client); | |
307 connection->set_input_stub(client); | |
308 | 297 |
309 clients_.push_back(client); | 298 clients_.push_back(client); |
310 } | 299 } |
311 | 300 |
312 void ChromotingHost::set_protocol_config( | 301 void ChromotingHost::set_protocol_config( |
313 protocol::CandidateSessionConfig* config) { | 302 protocol::CandidateSessionConfig* config) { |
314 DCHECK(config_.get()); | 303 DCHECK(config_.get()); |
315 DCHECK_EQ(state_, kInitial); | 304 DCHECK_EQ(state_, kInitial); |
316 protocol_config_.reset(config); | 305 protocol_config_.reset(config); |
317 } | 306 } |
(...skipping 26 matching lines...) Expand all Loading... | |
344 desktop_environment_->OnPause(pause); | 333 desktop_environment_->OnPause(pause); |
345 } | 334 } |
346 | 335 |
347 void ChromotingHost::SetUiStrings(const UiStrings& ui_strings) { | 336 void ChromotingHost::SetUiStrings(const UiStrings& ui_strings) { |
348 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); | 337 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); |
349 DCHECK_EQ(state_, kInitial); | 338 DCHECK_EQ(state_, kInitial); |
350 | 339 |
351 ui_strings_ = ui_strings; | 340 ui_strings_ = ui_strings; |
352 } | 341 } |
353 | 342 |
354 void ChromotingHost::OnClientDisconnected(ConnectionToClient* connection) { | 343 void ChromotingHost::OnClientDisconnected(ClientSession* client) { |
355 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); | 344 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); |
356 | 345 |
357 // Find the client session corresponding to the given connection. | 346 scoped_refptr<ClientSession> client_ref = client; |
347 | |
358 ClientList::iterator it; | 348 ClientList::iterator it; |
359 for (it = clients_.begin(); it != clients_.end(); ++it) { | 349 for (it = clients_.begin(); it != clients_.end(); ++it) { |
360 if (it->get()->connection() == connection) | 350 if (it->get() == client) |
361 break; | 351 break; |
362 } | 352 } |
363 if (it == clients_.end()) | |
364 return; | |
365 | |
366 scoped_refptr<ClientSession> client = *it; | |
367 | |
368 clients_.erase(it); | 353 clients_.erase(it); |
369 | 354 |
370 if (recorder_.get()) { | 355 if (recorder_.get()) { |
371 recorder_->RemoveConnection(connection); | 356 recorder_->RemoveConnection(client->connection()); |
372 } | 357 } |
373 | 358 |
374 // Close the connection to client just to be safe. | |
375 // TODO(garykac): This should be removed when we revisit our shutdown and | |
376 // disconnect code. This should only need to be done in | |
377 // ClientSession::Disconnect(). | |
378 connection->Disconnect(); | |
379 | |
380 for (StatusObserverList::iterator it = status_observers_.begin(); | 359 for (StatusObserverList::iterator it = status_observers_.begin(); |
381 it != status_observers_.end(); ++it) { | 360 it != status_observers_.end(); ++it) { |
382 (*it)->OnClientDisconnected(client->client_jid()); | 361 (*it)->OnClientDisconnected(client->client_jid()); |
383 } | 362 } |
384 | 363 |
385 if (AuthenticatedClientsCount() == 0) { | 364 if (AuthenticatedClientsCount() == 0) { |
386 if (recorder_.get()) { | 365 if (recorder_.get()) { |
387 // Stop the recorder if there are no more clients. | 366 // Stop the recorder if there are no more clients. |
388 StopScreenRecorder(); | 367 StopScreenRecorder(); |
389 } | 368 } |
390 | 369 |
391 // Disable the "curtain" if there are no more active clients. | 370 // Disable the "curtain" if there are no more active clients. |
392 EnableCurtainMode(false); | 371 EnableCurtainMode(false); |
393 if (is_it2me_) { | 372 desktop_environment_->OnLastDisconnect(); |
394 desktop_environment_->OnLastDisconnect(); | |
395 } | |
396 } | 373 } |
397 | |
398 client->OnDisconnected(); | |
399 } | 374 } |
400 | 375 |
401 // TODO(sergeyu): Move this to SessionManager? | 376 // TODO(sergeyu): Move this to SessionManager? |
402 Encoder* ChromotingHost::CreateEncoder(const protocol::SessionConfig& config) { | 377 Encoder* ChromotingHost::CreateEncoder(const protocol::SessionConfig& config) { |
403 const protocol::ChannelConfig& video_config = config.video_config(); | 378 const protocol::ChannelConfig& video_config = config.video_config(); |
404 | 379 |
405 if (video_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) { | 380 if (video_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) { |
406 return EncoderRowBased::CreateVerbatimEncoder(); | 381 return EncoderRowBased::CreateVerbatimEncoder(); |
407 } else if (video_config.codec == protocol::ChannelConfig::CODEC_ZIP) { | 382 } else if (video_config.codec == protocol::ChannelConfig::CODEC_ZIP) { |
408 return EncoderRowBased::CreateZlibEncoder(); | 383 return EncoderRowBased::CreateZlibEncoder(); |
(...skipping 23 matching lines...) Expand all Loading... | |
432 void ChromotingHost::EnableCurtainMode(bool enable) { | 407 void ChromotingHost::EnableCurtainMode(bool enable) { |
433 // TODO(jamiewalch): This will need to be more sophisticated when we think | 408 // TODO(jamiewalch): This will need to be more sophisticated when we think |
434 // about proper crash recovery and daemon mode. | 409 // about proper crash recovery and daemon mode. |
435 // TODO(wez): CurtainMode shouldn't be driven directly by ChromotingHost. | 410 // TODO(wez): CurtainMode shouldn't be driven directly by ChromotingHost. |
436 if (is_it2me_ || enable == is_curtained_) | 411 if (is_it2me_ || enable == is_curtained_) |
437 return; | 412 return; |
438 desktop_environment_->curtain()->EnableCurtainMode(enable); | 413 desktop_environment_->curtain()->EnableCurtainMode(enable); |
439 is_curtained_ = enable; | 414 is_curtained_ = enable; |
440 } | 415 } |
441 | 416 |
442 void ChromotingHost::OnAuthenticationComplete( | |
443 scoped_refptr<ConnectionToClient> connection) { | |
444 DCHECK(context_->network_message_loop()->BelongsToCurrentThread()); | |
445 | |
446 context_->main_message_loop()->PostTask( | |
447 FROM_HERE, base::Bind(&ChromotingHost::AddAuthenticatedClient, | |
448 this, connection, connection->session()->config(), | |
449 connection->session()->jid())); | |
450 } | |
451 | |
452 void ChromotingHost::AddAuthenticatedClient( | 417 void ChromotingHost::AddAuthenticatedClient( |
453 scoped_refptr<ConnectionToClient> connection, | 418 ClientSession* client, |
454 const protocol::SessionConfig& config, | 419 const protocol::SessionConfig& config, |
455 const std::string& jid) { | 420 const std::string& jid) { |
456 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); | 421 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); |
457 | 422 |
458 // Disconnect all other clients. | 423 // Disconnect all other clients. |
459 // Iterate over a copy of the list of clients, to avoid mutating the list | 424 // Iterate over a copy of the list of clients, to avoid mutating the list |
460 // while iterating over it. | 425 // while iterating over it. |
461 ClientList clients_copy(clients_); | 426 ClientList clients_copy(clients_); |
462 for (ClientList::const_iterator client = clients_copy.begin(); | 427 for (ClientList::const_iterator other_client = clients_copy.begin(); |
463 client != clients_copy.end(); client++) { | 428 other_client != clients_copy.end(); ++other_client) { |
464 ConnectionToClient* connection_other = client->get()->connection(); | 429 if ((*other_client) != client) { |
465 if (connection_other != connection) { | 430 (*other_client)->Disconnect(); |
466 OnClientDisconnected(connection_other); | 431 OnClientDisconnected(*other_client); |
467 } | 432 } |
468 } | 433 } |
434 | |
469 // Those disconnections should have killed the screen recorder. | 435 // Those disconnections should have killed the screen recorder. |
470 CHECK(recorder_.get() == NULL); | 436 CHECK(recorder_.get() == NULL); |
471 | 437 |
472 // Create a new RecordSession if there was none. | 438 // Create a new RecordSession if there was none. |
473 if (!recorder_.get()) { | 439 if (!recorder_.get()) { |
474 // Then we create a ScreenRecorder passing the message loops that | 440 // Then we create a ScreenRecorder passing the message loops that |
475 // it should run on. | 441 // it should run on. |
476 Encoder* encoder = CreateEncoder(config); | 442 Encoder* encoder = CreateEncoder(config); |
477 | 443 |
478 recorder_ = new ScreenRecorder(context_->main_message_loop(), | 444 recorder_ = new ScreenRecorder(context_->main_message_loop(), |
479 context_->encode_message_loop(), | 445 context_->encode_message_loop(), |
480 context_->network_message_loop(), | 446 context_->network_message_loop(), |
481 desktop_environment_->capturer(), | 447 desktop_environment_->capturer(), |
482 encoder); | 448 encoder); |
483 } | 449 } |
484 | 450 |
485 // Immediately add the connection and start the session. | 451 // Immediately add the connection and start the session. |
486 recorder_->AddConnection(connection); | 452 recorder_->AddConnection(client->connection()); |
487 recorder_->Start(); | 453 recorder_->Start(); |
488 // Notify observers that there is at least one authenticated client. | 454 // Notify observers that there is at least one authenticated client. |
489 for (StatusObserverList::iterator it = status_observers_.begin(); | 455 for (StatusObserverList::iterator it = status_observers_.begin(); |
490 it != status_observers_.end(); ++it) { | 456 it != status_observers_.end(); ++it) { |
491 (*it)->OnClientAuthenticated(jid); | 457 (*it)->OnClientAuthenticated(jid); |
492 } | 458 } |
493 // TODO(jamiewalch): Tidy up actions to be taken on connect/disconnect, | 459 // TODO(jamiewalch): Tidy up actions to be taken on connect/disconnect, |
494 // including closing the connection on failure of a critical operation. | 460 // including closing the connection on failure of a critical operation. |
495 EnableCurtainMode(true); | 461 EnableCurtainMode(true); |
496 if (is_it2me_) { | 462 if (is_it2me_) { |
497 std::string username = jid; | 463 std::string username = jid; |
498 size_t pos = username.find('/'); | 464 size_t pos = username.find('/'); |
499 if (pos != std::string::npos) | 465 if (pos != std::string::npos) |
500 username.replace(pos, std::string::npos, ""); | 466 username.replace(pos, std::string::npos, ""); |
501 desktop_environment_->OnConnect(username); | 467 desktop_environment_->OnConnect(username); |
502 } | 468 } |
503 } | 469 } |
504 | 470 |
505 void ChromotingHost::ProcessPreAuthentication( | |
506 const scoped_refptr<ConnectionToClient>& connection) { | |
507 DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); | |
508 // Find the client session corresponding to the given connection. | |
509 ClientList::iterator client; | |
510 for (client = clients_.begin(); client != clients_.end(); ++client) { | |
511 if (client->get()->connection() == connection) | |
512 break; | |
513 } | |
514 CHECK(client != clients_.end()); | |
515 | |
516 context_->network_message_loop()->PostTask( | |
517 FROM_HERE, base::Bind(&ClientSession::OnAuthenticationComplete, | |
518 client->get())); | |
519 } | |
520 | |
521 void ChromotingHost::StopScreenRecorder() { | 471 void ChromotingHost::StopScreenRecorder() { |
522 DCHECK(MessageLoop::current() == context_->main_message_loop()); | 472 DCHECK(MessageLoop::current() == context_->main_message_loop()); |
523 DCHECK(recorder_.get()); | 473 DCHECK(recorder_.get()); |
524 | 474 |
525 ++stopping_recorders_; | 475 ++stopping_recorders_; |
526 recorder_->Stop(base::Bind(&ChromotingHost::OnScreenRecorderStopped, this)); | 476 recorder_->Stop(base::Bind(&ChromotingHost::OnScreenRecorderStopped, this)); |
527 recorder_ = NULL; | 477 recorder_ = NULL; |
528 } | 478 } |
529 | 479 |
530 void ChromotingHost::OnScreenRecorderStopped() { | 480 void ChromotingHost::OnScreenRecorderStopped() { |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
612 | 562 |
613 for (std::vector<Task*>::iterator it = shutdown_tasks_.begin(); | 563 for (std::vector<Task*>::iterator it = shutdown_tasks_.begin(); |
614 it != shutdown_tasks_.end(); ++it) { | 564 it != shutdown_tasks_.end(); ++it) { |
615 (*it)->Run(); | 565 (*it)->Run(); |
616 delete *it; | 566 delete *it; |
617 } | 567 } |
618 shutdown_tasks_.clear(); | 568 shutdown_tasks_.clear(); |
619 } | 569 } |
620 | 570 |
621 } // namespace remoting | 571 } // namespace remoting |
OLD | NEW |