diff options
Diffstat (limited to 'remoting/host/chromoting_host.cc')
-rw-r--r-- | remoting/host/chromoting_host.cc | 211 |
1 files changed, 111 insertions, 100 deletions
diff --git a/remoting/host/chromoting_host.cc b/remoting/host/chromoting_host.cc index 0fc60e2..8510678 100644 --- a/remoting/host/chromoting_host.cc +++ b/remoting/host/chromoting_host.cc @@ -5,117 +5,63 @@ #include "remoting/host/chromoting_host.h" #include "base/stl_util-inl.h" -#include "base/waitable_event.h" +#include "base/task.h" #include "build/build_config.h" #include "remoting/base/constants.h" #include "remoting/base/protocol_decoder.h" +#include "remoting/host/chromoting_host_context.h" #include "remoting/host/host_config.h" #include "remoting/host/session_manager.h" #include "remoting/jingle_glue/jingle_channel.h" namespace remoting { -ChromotingHost::ChromotingHost(MutableHostConfig* config, +ChromotingHost::ChromotingHost(ChromotingHostContext* context, + MutableHostConfig* config, Capturer* capturer, Encoder* encoder, - EventExecutor* executor, - base::WaitableEvent* host_done) - : main_thread_("MainThread"), - capture_thread_("CaptureThread"), - encode_thread_("EncodeThread"), - config_(config), - capturer_(capturer), - encoder_(encoder), - executor_(executor), - host_done_(host_done) { - // TODO(ajwong): The thread injection and object ownership is odd here. - // Fix so we do not start this thread in the constructor, so we only - // take in a session manager, don't let session manager own the - // capturer/encoder, and then associate the capturer and encoder threads with - // the capturer and encoder objects directly. This will require a - // non-refcounted NewRunnableMethod. - main_thread_.StartWithOptions( - base::Thread::Options(MessageLoop::TYPE_UI, 0)); - network_thread_.Start(); + EventExecutor* executor) + : context_(context), + config_(config), + capturer_(capturer), + encoder_(encoder), + executor_(executor), + state_(kInitial) { } ChromotingHost::~ChromotingHost() { - // TODO(ajwong): We really need to inject these threads and get rid of these - // start/stops. - main_thread_.Stop(); - network_thread_.Stop(); - DCHECK(!encode_thread_.IsRunning()); - DCHECK(!capture_thread_.IsRunning()); } -void ChromotingHost::Run() { +void ChromotingHost::Start(Task* shutdown_task) { // Submit a task to perform host registration. We'll also start // listening to connection if registration is done. - message_loop()->PostTask( + context_->main_message_loop()->PostTask( FROM_HERE, - NewRunnableMethod(this, &ChromotingHost::RegisterHost)); + NewRunnableMethod(this, &ChromotingHost::DoStart, shutdown_task)); } // This method is called when we need to destroy the host process. -void ChromotingHost::DestroySession() { - DCHECK_EQ(message_loop(), MessageLoop::current()); - - // First we tell the session to pause and then we wait until all - // the tasks are done. - if (session_.get()) { - session_->Pause(); - - // TODO(hclam): Revise the order. - DCHECK(encode_thread_.IsRunning()); - encode_thread_.Stop(); - - DCHECK(capture_thread_.IsRunning()); - capture_thread_.Stop(); - } -} - -// This method talks to the cloud to register the host process. If -// successful we will start listening to network requests. -void ChromotingHost::RegisterHost() { - DCHECK_EQ(message_loop(), MessageLoop::current()); - DCHECK(!jingle_client_); - - std::string xmpp_login; - std::string xmpp_auth_token; - if (!config_->GetString(kXmppLoginConfigPath, &xmpp_login) || - !config_->GetString(kXmppAuthTokenConfigPath, &xmpp_auth_token)) { - LOG(ERROR) << "XMMP credentials are not defined in config."; - return; - } - - // Connect to the talk network with a JingleClient. - jingle_client_ = new JingleClient(&network_thread_); - jingle_client_->Init(xmpp_login, xmpp_auth_token, - kChromotingTokenServiceName, this); +void ChromotingHost::Shutdown() { + context_->main_message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(this, &ChromotingHost::DoShutdown)); } // This method is called if a client is connected to this object. void ChromotingHost::OnClientConnected(ClientConnection* client) { - DCHECK_EQ(message_loop(), MessageLoop::current()); + DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); // Create a new RecordSession if there was none. if (!session_.get()) { - // The first we need to make sure capture and encode thread are - // running. - capture_thread_.Start(); - encode_thread_.Start(); - // Then we create a SessionManager passing the message loops that // it should run on. - // Note that we pass the ownership of the capturer and encoder to - // the session manager. DCHECK(capturer_.get()); DCHECK(encoder_.get()); - session_ = new SessionManager(capture_thread_.message_loop(), - encode_thread_.message_loop(), - message_loop(), - capturer_.release(), - encoder_.release()); + session_ = new SessionManager(context_->capture_message_loop(), + context_->encode_message_loop(), + context_->main_message_loop(), + capturer_.get(), + encoder_.get()); // Immediately add the client and start the session. session_->AddClient(client); @@ -128,26 +74,24 @@ void ChromotingHost::OnClientConnected(ClientConnection* client) { } void ChromotingHost::OnClientDisconnected(ClientConnection* client) { - DCHECK_EQ(message_loop(), MessageLoop::current()); + DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); - // Remove the client from the session manager. - if (session_.get()) + // Remove the client from the session manager and pause the session. + // TODO(hclam): Pause only if the last client disconnected. + if (session_.get()) { session_->RemoveClient(client); + session_->Pause(); + } // Also remove reference to ClientConnection from this object. client_ = NULL; - - // TODO(hclam): If the last client has disconnected we need to destroy - // the session manager and shutdown the capture and encode threads. - // Right now we assume that there's only one client. - DestroySession(); } //////////////////////////////////////////////////////////////////////////// // ClientConnection::EventHandler implementations void ChromotingHost::HandleMessages(ClientConnection* client, ClientMessageList* messages) { - DCHECK_EQ(message_loop(), MessageLoop::current()); + DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); // Delegate the messages to EventExecutor and delete the unhandled // messages. @@ -157,7 +101,7 @@ void ChromotingHost::HandleMessages(ClientConnection* client, } void ChromotingHost::OnConnectionOpened(ClientConnection* client) { - DCHECK_EQ(message_loop(), MessageLoop::current()); + DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); // Completes the client connection. LOG(INFO) << "Connection to client established."; @@ -165,7 +109,7 @@ void ChromotingHost::OnConnectionOpened(ClientConnection* client) { } void ChromotingHost::OnConnectionClosed(ClientConnection* client) { - DCHECK_EQ(message_loop(), MessageLoop::current()); + DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); // Completes the client connection. LOG(INFO) << "Connection to client closed."; @@ -173,7 +117,7 @@ void ChromotingHost::OnConnectionClosed(ClientConnection* client) { } void ChromotingHost::OnConnectionFailed(ClientConnection* client) { - DCHECK_EQ(message_loop(), MessageLoop::current()); + DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); // The client has disconnected. LOG(ERROR) << "Connection failed unexpectedly."; @@ -183,10 +127,9 @@ void ChromotingHost::OnConnectionFailed(ClientConnection* client) { //////////////////////////////////////////////////////////////////////////// // JingleClient::Callback implementations void ChromotingHost::OnStateChange(JingleClient* jingle_client, - JingleClient::State state) { - DCHECK_EQ(jingle_client_.get(), jingle_client); - + JingleClient::State state) { if (state == JingleClient::CONNECTED) { + DCHECK_EQ(jingle_client_.get(), jingle_client); LOG(INFO) << "Host connected as " << jingle_client->GetFullJid() << "." << std::endl; @@ -197,17 +140,21 @@ void ChromotingHost::OnStateChange(JingleClient* jingle_client, LOG(INFO) << "Host disconnected from talk network." << std::endl; heartbeat_sender_ = NULL; - // Quit the message loop if disconected. // TODO(sergeyu): We should try reconnecting here instead of terminating // the host. - message_loop()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); - host_done_->Signal(); + // Post a shutdown task to properly shutdown the chromoting host. + context_->main_message_loop()->PostTask( + FROM_HERE, NewRunnableMethod(this, &ChromotingHost::DoShutdown)); } } bool ChromotingHost::OnAcceptConnection( JingleClient* jingle_client, const std::string& jid, JingleChannel::Callback** channel_callback) { + AutoLock auto_lock(lock_); + if (state_ != kStarted) + return false; + DCHECK_EQ(jingle_client_.get(), jingle_client); // TODO(hclam): Allow multiple clients to connect to the host. @@ -218,13 +165,18 @@ bool ChromotingHost::OnAcceptConnection( // If we accept the connected then create a client object and set the // callback. - client_ = new ClientConnection(message_loop(), new ProtocolDecoder(), this); + client_ = new ClientConnection(context_->main_message_loop(), + new ProtocolDecoder(), this); *channel_callback = client_.get(); return true; } void ChromotingHost::OnNewConnection(JingleClient* jingle_client, - scoped_refptr<JingleChannel> channel) { + scoped_refptr<JingleChannel> channel) { + AutoLock auto_lock(lock_); + if (state_ != kStarted) + return; + DCHECK_EQ(jingle_client_.get(), jingle_client); // Since the session manager has not started, it is still safe to access @@ -233,8 +185,67 @@ void ChromotingHost::OnNewConnection(JingleClient* jingle_client, client_->set_jingle_channel(channel); } -MessageLoop* ChromotingHost::message_loop() { - return main_thread_.message_loop(); +void ChromotingHost::DoStart(Task* shutdown_task) { + DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); + DCHECK(!jingle_client_); + DCHECK(shutdown_task); + + // Make sure this object is not started. + { + AutoLock auto_lock(lock_); + if (state_ != kInitial) + return; + state_ = kStarted; + } + + // Save the shutdown task. + shutdown_task_.reset(shutdown_task); + + std::string xmpp_login; + std::string xmpp_auth_token; + if (!config_->GetString(kXmppLoginConfigPath, &xmpp_login) || + !config_->GetString(kXmppAuthTokenConfigPath, &xmpp_auth_token)) { + LOG(ERROR) << "XMMP credentials are not defined in config."; + return; + } + + // Connect to the talk network with a JingleClient. + jingle_client_ = new JingleClient(context_->jingle_thread()); + jingle_client_->Init(xmpp_login, xmpp_auth_token, + kChromotingTokenServiceName, this); +} + +void ChromotingHost::DoShutdown() { + DCHECK_EQ(context_->main_message_loop(), MessageLoop::current()); + + // No-op if this object is not started yet. + { + AutoLock auto_lock(lock_); + if (state_ != kStarted) + return; + state_ = kStopped; + } + + // Tell the session to pause and then disconnect all clients. + if (session_.get()) { + session_->Pause(); + session_->RemoveAllClients(); + } + + // Disconnect all clients. + if (client_) { + client_->Disconnect(); + } + + // Disconnect from the talk network. + if (jingle_client_) { + jingle_client_->Close(); + } + + // Lastly call the shutdown task. + if (shutdown_task_.get()) { + shutdown_task_->Run(); + } } } // namespace remoting |