diff options
Diffstat (limited to 'remoting')
-rw-r--r-- | remoting/chromoting.gyp | 3 | ||||
-rw-r--r-- | remoting/client/client_util.cc | 24 | ||||
-rw-r--r-- | remoting/client/client_util.h | 6 | ||||
-rw-r--r-- | remoting/client/host_connection.cc | 86 | ||||
-rw-r--r-- | remoting/client/host_connection.h | 45 | ||||
-rw-r--r-- | remoting/client/jingle_host_connection.cc | 134 | ||||
-rw-r--r-- | remoting/client/jingle_host_connection.h | 83 | ||||
-rw-r--r-- | remoting/client/simple_client.cc | 64 | ||||
-rw-r--r-- | remoting/host/simple_host.cc | 73 | ||||
-rw-r--r-- | remoting/host/simple_host.h | 20 | ||||
-rw-r--r-- | remoting/host/simple_host_process.cc | 6 | ||||
-rw-r--r-- | remoting/jingle_glue/jingle_client.cc | 77 | ||||
-rw-r--r-- | remoting/jingle_glue/jingle_client.h | 23 |
13 files changed, 392 insertions, 252 deletions
diff --git a/remoting/chromoting.gyp b/remoting/chromoting.gyp index 689ebd9..1ef15e7 100644 --- a/remoting/chromoting.gyp +++ b/remoting/chromoting.gyp @@ -226,8 +226,9 @@ 'client/decoder.h', 'client/decoder_verbatim.cc', 'client/decoder_verbatim.h', - 'client/host_connection.cc', 'client/host_connection.h', + 'client/jingle_host_connection.cc', + 'client/jingle_host_connection.h', ], }, # end of target 'chromoting_client' diff --git a/remoting/client/client_util.cc b/remoting/client/client_util.cc index a6bf1877..2bc50c0 100644 --- a/remoting/client/client_util.cc +++ b/remoting/client/client_util.cc @@ -9,14 +9,14 @@ namespace remoting { // Get host JID from command line arguments, or stdin if not specified. -bool GetLoginInfo(std::string& host_jid, - std::string& username, - std::string& auth_token) { +bool GetLoginInfo(std::string* host_jid, + std::string* username, + std::string* auth_token) { std::cout << "Host JID: "; - std::cin >> host_jid; + std::cin >> *host_jid; std::cin.ignore(); // Consume the leftover '\n' - if (host_jid.find("/chromoting") == std::string::npos) { + if (host_jid->find("/chromoting") == std::string::npos) { std::cerr << "Error: Expected Host JID in format: <jid>/chromoting<id>" << std::endl; return false; @@ -25,23 +25,23 @@ bool GetLoginInfo(std::string& host_jid, // Get username (JID). // Extract default JID from host_jid. std::string default_username; - size_t jid_end = host_jid.find('/'); + size_t jid_end = host_jid->find('/'); if (jid_end != std::string::npos) { - default_username = host_jid.substr(0, jid_end); + default_username = host_jid->substr(0, jid_end); } std::cout << "JID [" << default_username << "]: "; - getline(std::cin, username); - if (username.length() == 0) { - username = default_username; + getline(std::cin, *username); + if (username->length() == 0) { + username->swap(default_username); } - if (username.length() == 0) { + if (username->length() == 0) { std::cerr << "Error: Expected valid JID username" << std::endl; return 1; } // Get authenication token (with console echo turned off). std::cout << "Auth token: "; - getline(std::cin, auth_token); + getline(std::cin, *auth_token); std::cout << std::endl; return true; } diff --git a/remoting/client/client_util.h b/remoting/client/client_util.h index ba9fefe..78ebcc0 100644 --- a/remoting/client/client_util.h +++ b/remoting/client/client_util.h @@ -9,10 +9,10 @@ namespace remoting { -// Get the login info from the console and writes into |host_jid|, |username| +// Get the login info from the console and writes into |host_jid|, |username|, // and |auth_token|. Return true if successful. -bool GetLoginInfo(std::string& host_jid, std::string& username, - std::string& auth_token); +bool GetLoginInfo(std::string* host_jid, std::string* username, + std::string* auth_token); } // namespace remoting diff --git a/remoting/client/host_connection.cc b/remoting/client/host_connection.cc deleted file mode 100644 index cc73b73..0000000 --- a/remoting/client/host_connection.cc +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "remoting/client/host_connection.h" - -#include "remoting/base/constants.h" - -namespace remoting { - -HostConnection::HostConnection(ProtocolDecoder* decoder, - EventHandler* handler) - : decoder_(decoder), handler_(handler) { -} - -HostConnection::~HostConnection() { - Disconnect(); -} - -void HostConnection::Connect(const std::string& username, - const std::string& auth_token, - const std::string& host_jid) { - jingle_client_ = new JingleClient(); - jingle_client_->Init(username, auth_token, kChromotingTokenServiceName, this); - jingle_channel_ = jingle_client_->Connect(host_jid, this); -} - -void HostConnection::Disconnect() { - // TODO(hclam): It's not thread safe to read the state. - if (jingle_channel_.get() && - jingle_channel_->state() != JingleChannel::CLOSED) { - jingle_channel_->Close(); - } - - // TODO(hclam): It's not thread safe to read the state. - if (jingle_client_.get() && - jingle_client_->state() != JingleClient::CLOSED) { - jingle_client_->Close(); - } -} - -void HostConnection::OnStateChange(JingleChannel* channel, - JingleChannel::State state) { - DCHECK(handler_); - if (state == JingleChannel::OPEN) - handler_->OnConnectionOpened(this); - else if (state == JingleChannel::FAILED) - handler_->OnConnectionFailed(this); - else if (state == JingleChannel::CLOSED) - handler_->OnConnectionClosed(this); -} - -void HostConnection::OnPacketReceived(JingleChannel* channel, - scoped_refptr<media::DataBuffer> buffer) { - HostMessageList list; - decoder_->ParseHostMessages(buffer, &list); - DCHECK(handler_); - handler_->HandleMessages(this, &list); -} - -// JingleClient::Callback interface. -void HostConnection::OnStateChange(JingleClient* client, - JingleClient::State state) { - DCHECK(client); - DCHECK(handler_); - if (state == JingleClient::CONNECTED) { - LOG(INFO) << "Connected as: " << client->GetFullJid(); - } else if (state == JingleClient::CLOSED) { - LOG(INFO) << "Connection closed."; - handler_->OnConnectionClosed(this); - } -} - -bool HostConnection::OnAcceptConnection(JingleClient* client, - const std::string& jid, - JingleChannel::Callback** callback) { - // Client rejects all connection. - return false; -} - -void HostConnection::OnNewConnection(JingleClient* client, - scoped_refptr<JingleChannel> channel) { - NOTREACHED() << "SimpleClient can't accept connection."; -} - -} // namespace remoting diff --git a/remoting/client/host_connection.h b/remoting/client/host_connection.h index 8cd2a76..adbb876 100644 --- a/remoting/client/host_connection.h +++ b/remoting/client/host_connection.h @@ -5,25 +5,17 @@ #ifndef REMOTING_CLIENT_HOST_CONNECTION_H_ #define REMOTING_CLIENT_HOST_CONNECTION_H_ -#include <deque> -#include <vector> - -#include "base/message_loop.h" #include "base/ref_counted.h" #include "base/scoped_ptr.h" #include "remoting/base/protocol_decoder.h" -#include "remoting/base/protocol/chromotocol.pb.h" -#include "remoting/jingle_glue/jingle_channel.h" -#include "remoting/jingle_glue/jingle_client.h" namespace remoting { -class HostConnection : public JingleChannel::Callback, - public JingleClient::Callback { +class HostConnection { public: - class EventHandler { + class HostEventCallback { public: - virtual ~EventHandler() {} + virtual ~HostEventCallback() {} // Handles an event received by the HostConnection. Receiver will own the // HostMessages in HostMessageList and needs to delete them. @@ -42,33 +34,18 @@ class HostConnection : public JingleChannel::Callback, virtual void OnConnectionFailed(HostConnection* conn) = 0; }; - // Constructs a HostConnection object. - HostConnection(ProtocolDecoder* decoder, EventHandler* handler); - - virtual ~HostConnection(); + virtual ~HostConnection() {} - void Connect(const std::string& username, const std::string& auth_token, - const std::string& host_jid); - void Disconnect(); + // TODO(ajwong): We need to generalize this API. + virtual void Connect(const std::string& username, + const std::string& auth_token, + const std::string& host_jid) = 0; + virtual void Disconnect() = 0; - // JingleChannel::Callback interface. - void OnStateChange(JingleChannel* channel, JingleChannel::State state); - void OnPacketReceived(JingleChannel* channel, - scoped_refptr<media::DataBuffer> buffer); - - // JingleClient::Callback interface. - void OnStateChange(JingleClient* client, JingleClient::State state); - bool OnAcceptConnection(JingleClient* client, const std::string& jid, - JingleChannel::Callback** callback); - void OnNewConnection(JingleClient* client, - scoped_refptr<JingleChannel> channel); + protected: + HostConnection() {} private: - scoped_refptr<JingleClient> jingle_client_; - scoped_refptr<JingleChannel> jingle_channel_; - scoped_ptr<ProtocolDecoder> decoder_; - EventHandler* handler_; - DISALLOW_COPY_AND_ASSIGN(HostConnection); }; diff --git a/remoting/client/jingle_host_connection.cc b/remoting/client/jingle_host_connection.cc new file mode 100644 index 0000000..7b9241c --- /dev/null +++ b/remoting/client/jingle_host_connection.cc @@ -0,0 +1,134 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/message_loop.h" +#include "remoting/base/constants.h" +#include "remoting/client/jingle_host_connection.h" +#include "remoting/jingle_glue/jingle_thread.h" + +namespace remoting { + +JingleHostConnection::JingleHostConnection(JingleThread* network_thread, + HostEventCallback* event_callback) + : network_thread_(network_thread), event_callback_(event_callback) { +} + +JingleHostConnection::~JingleHostConnection() { +} + +void JingleHostConnection::Connect(const std::string& username, + const std::string& password, + const std::string& host_jid) { + message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(this, + &JingleHostConnection::DoConnect, + username, password, host_jid)); +} + +void JingleHostConnection::Disconnect() { + message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(this, &JingleHostConnection::DoDisconnect)); +} + +void JingleHostConnection::OnStateChange(JingleChannel* channel, + JingleChannel::State state) { + DCHECK_EQ(message_loop(), MessageLoop::current()); + DCHECK(event_callback_); + + switch (state) { + case JingleChannel::FAILED: + event_callback_->OnConnectionFailed(this); + break; + + case JingleChannel::CLOSED: + event_callback_->OnConnectionClosed(this); + break; + + case JingleChannel::OPEN: + event_callback_->OnConnectionOpened(this); + break; + + default: + // Ignore the other states by default. + break; + } +} + +void JingleHostConnection::OnPacketReceived( + JingleChannel* channel, + scoped_refptr<media::DataBuffer> buffer) { + DCHECK_EQ(message_loop(), MessageLoop::current()); + DCHECK(event_callback_); + + HostMessageList list; + decoder_.ParseHostMessages(buffer, &list); + event_callback_->HandleMessages(this, &list); +} + +// JingleClient::Callback interface. +void JingleHostConnection::OnStateChange(JingleClient* client, + JingleClient::State state) { + DCHECK_EQ(message_loop(), MessageLoop::current()); + DCHECK(client); + DCHECK(event_callback_); + + if (state == JingleClient::CONNECTED) { + LOG(INFO) << "Connected as: " << client->GetFullJid(); + } else if (state == JingleClient::CLOSED) { + LOG(INFO) << "Connection closed."; + event_callback_->OnConnectionClosed(this); + } +} + +bool JingleHostConnection::OnAcceptConnection( + JingleClient* client, + const std::string& jid, + JingleChannel::Callback** callback) { + DCHECK_EQ(message_loop(), MessageLoop::current()); + + // Client rejects all connection. + return false; +} + +void JingleHostConnection::OnNewConnection( + JingleClient* client, + scoped_refptr<JingleChannel> channel) { + DCHECK_EQ(message_loop(), MessageLoop::current()); + + // TODO(ajwong): Should we log more aggressively on this and above? We + // shouldn't be getting any inbound connections. + NOTREACHED() << "Clients can't accept inbound connections."; +} + +MessageLoop* JingleHostConnection::message_loop() { + return network_thread_->message_loop(); +} + +void JingleHostConnection::DoConnect(const std::string& username, + const std::string& auth_token, + const std::string& host_jid) { + DCHECK_EQ(message_loop(), MessageLoop::current()); + + jingle_client_ = new JingleClient(network_thread_); + jingle_client_->Init(username, auth_token, kChromotingTokenServiceName, this); + jingle_channel_ = jingle_client_->Connect(host_jid, this); +} + +void JingleHostConnection::DoDisconnect() { + DCHECK_EQ(message_loop(), MessageLoop::current()); + + if (jingle_channel_.get()) { + jingle_channel_->Close(); + jingle_channel_ = NULL; + } + + if (jingle_client_.get()) { + jingle_client_->Close(); + jingle_client_ = NULL; + } +} + +} // namespace remoting diff --git a/remoting/client/jingle_host_connection.h b/remoting/client/jingle_host_connection.h new file mode 100644 index 0000000..00faaa1 --- /dev/null +++ b/remoting/client/jingle_host_connection.h @@ -0,0 +1,83 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// JingleHostConnection implements the HostConnection interface using +// libjingle as the transport protocol. +// +// Much of this class focuses on translating JingleClient and JingleChannel +// callbacks into HostConnection::HostEventCallback messages. +// +// The public API of this class is designed to be asynchronous, and thread +// safe for invocation from other threads. +// +// Internally though, all work delegeated to the |network_thread| given +// during construction. Any event handlers running on the |network_thread| +// should not block. + +#ifndef REMOTING_CLIENT_JINGLE_HOST_CONNECTION_H_ +#define REMOTING_CLIENT_JINGLE_HOST_CONNECTION_H_ + +#include "base/ref_counted.h" +#include "base/scoped_ptr.h" +#include "remoting/base/protocol_decoder.h" +#include "remoting/client/host_connection.h" +#include "remoting/jingle_glue/jingle_channel.h" +#include "remoting/jingle_glue/jingle_client.h" + +class MessageLoop; + +namespace remoting { + +class JingleThread; + +class JingleHostConnection : + public base::RefCountedThreadSafe<JingleHostConnection>, + public HostConnection, + public JingleChannel::Callback, + public JingleClient::Callback { + public: + JingleHostConnection(JingleThread* network_thread, + HostEventCallback* event_callback); + virtual ~JingleHostConnection(); + + virtual void Connect(const std::string& username, + const std::string& auth_token, + const std::string& host_jid); + virtual void Disconnect(); + + // JingleChannel::Callback interface. + virtual void OnStateChange(JingleChannel* channel, + JingleChannel::State state); + virtual void OnPacketReceived(JingleChannel* channel, + scoped_refptr<media::DataBuffer> buffer); + + // JingleClient::Callback interface. + virtual void OnStateChange(JingleClient* client, JingleClient::State state); + virtual bool OnAcceptConnection(JingleClient* client, const std::string& jid, + JingleChannel::Callback** callback); + virtual void OnNewConnection(JingleClient* client, + scoped_refptr<JingleChannel> channel); + + private: + MessageLoop* message_loop(); + + void DoConnect(const std::string& username, + const std::string& auth_token, + const std::string& host_jid); + void DoDisconnect(); + + JingleThread* network_thread_; + + scoped_refptr<JingleClient> jingle_client_; + scoped_refptr<JingleChannel> jingle_channel_; + + ProtocolDecoder decoder_; + HostEventCallback* event_callback_; + + DISALLOW_COPY_AND_ASSIGN(JingleHostConnection); +}; + +} // namespace remoting + +#endif // REMOTING_CLIENT_JINGLE_HOST_CONNECTION_H_ diff --git a/remoting/client/simple_client.cc b/remoting/client/simple_client.cc index 474f02f..7672ec3 100644 --- a/remoting/client/simple_client.cc +++ b/remoting/client/simple_client.cc @@ -1,8 +1,8 @@ // Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// -// A simple client implements a minimalize Chromoting client and shows + +// A simple client implements a minimal Chromoting client and shows // network traffic for debugging. #include <iostream> @@ -11,9 +11,14 @@ #include "base/at_exit.h" #include "base/message_loop.h" #include "base/stl_util-inl.h" + +#include "base/waitable_event.h" +#include "media/base/data_buffer.h" #include "remoting/base/protocol_decoder.h" #include "remoting/client/client_util.h" -#include "remoting/client/host_connection.h" +#include "remoting/client/jingle_host_connection.h" +#include "remoting/jingle_glue/jingle_client.h" +#include "remoting/jingle_glue/jingle_thread.h" using remoting::BeginUpdateStreamMessage; using remoting::EndUpdateStreamMessage; @@ -22,14 +27,16 @@ using remoting::HostMessage; using remoting::HostMessageList; using remoting::InitClientMessage; using remoting::JingleClient; -using remoting::JingleChannel; +using remoting::JingleHostConnection; +using remoting::JingleThread; using remoting::ProtocolDecoder; using remoting::UpdateStreamPacketMessage; -class SimpleHostEventHandler : public HostConnection::EventHandler { +class SimpleHostEventCallback : public HostConnection::HostEventCallback { public: - SimpleHostEventHandler(MessageLoop* loop) - : main_loop_(loop) { + explicit SimpleHostEventCallback(MessageLoop* loop, + base::WaitableEvent* client_done) + : main_loop_(loop), client_done_(client_done) { } virtual void HandleMessages(HostConnection* conn, @@ -57,18 +64,12 @@ class SimpleHostEventHandler : public HostConnection::EventHandler { virtual void OnConnectionClosed(HostConnection* conn) { std::cout << "Connection closed." << std::endl; - - // Quit the message if the connection has closed. - DCHECK(main_loop_); - main_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask()); + client_done_->Signal(); } virtual void OnConnectionFailed(HostConnection* conn) { std::cout << "Conection failed." << std::endl; - - // Quit the message if the connection has failed. - DCHECK(main_loop_); - main_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask()); + client_done_->Signal(); } private: @@ -104,26 +105,39 @@ class SimpleHostEventHandler : public HostConnection::EventHandler { } MessageLoop* main_loop_; + base::WaitableEvent* client_done_; - DISALLOW_COPY_AND_ASSIGN(SimpleHostEventHandler); + DISALLOW_COPY_AND_ASSIGN(SimpleHostEventCallback); }; int main(int argc, char** argv) { base::AtExitManager exit_manager; - std::string host_jid, username, auth_token; + std::string host_jid; + std::string username; + std::string auth_token; - if (remoting::GetLoginInfo(host_jid, username, auth_token)) { + if (!remoting::GetLoginInfo(&host_jid, &username, &auth_token)) { std::cerr << "Cannot get valid login info." << std::endl; return 1; } - // The message loop that everything runs on. - MessageLoop main_loop; - SimpleHostEventHandler handler(&main_loop); - HostConnection connection(new ProtocolDecoder(), &handler); - connection.Connect(username, auth_token, host_jid); + // Start up a thread to run everything. + JingleThread network_thread; + network_thread.Start(); + + base::WaitableEvent client_done(false, false); + SimpleHostEventCallback handler(network_thread.message_loop(), &client_done); + scoped_refptr<JingleHostConnection> connection = + new JingleHostConnection(&network_thread, &handler); + connection->Connect(username, auth_token, host_jid); + + // Wait until the mainloop has been signaled to exit. + client_done.Wait(); + + connection->Disconnect(); + network_thread.message_loop()->PostTask(FROM_HERE, + new MessageLoop::QuitTask()); + network_thread.Stop(); - // Run the message. - main_loop.Run(); return 0; } diff --git a/remoting/host/simple_host.cc b/remoting/host/simple_host.cc index bfff330..ac83d85 100644 --- a/remoting/host/simple_host.cc +++ b/remoting/host/simple_host.cc @@ -5,6 +5,7 @@ #include "remoting/host/simple_host.h" #include "base/stl_util-inl.h" +#include "base/waitable_event.h" #include "build/build_config.h" #include "remoting/base/constants.h" #include "remoting/base/protocol_decoder.h" @@ -13,44 +14,51 @@ namespace remoting { -#if defined (OS_MACOSX) -// The Mac depends on system callbacks to tell it what rectangles need to -// be updated, so we need to use the system message loop. -const MessageLoop::Type kSimpleHostMessageLoopType = MessageLoop::TYPE_UI; -#else -const MessageLoop::Type kSimpleHostMessageLoopType = MessageLoop::TYPE_DEFAULT; -#endif // defined (OS_MACOSX) - SimpleHost::SimpleHost(const std::string& username, const std::string& auth_token, Capturer* capturer, Encoder* encoder, - EventExecutor* executor) - : main_loop_(kSimpleHostMessageLoopType), + EventExecutor* executor, + base::WaitableEvent* host_done) + : main_thread_("MainThread"), capture_thread_("CaptureThread"), encode_thread_("EncodeThread"), username_(username), auth_token_(auth_token), capturer_(capturer), encoder_(encoder), - executor_(executor) { + 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(); } -void SimpleHost::Run() { - DCHECK_EQ(&main_loop_, MessageLoop::current()); +SimpleHost::~SimpleHost() { + // 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 SimpleHost::Run() { // Submit a task to perform host registration. We'll also start // listening to connection if registration is done. - RegisterHost(); - - // Run the main message loop. This is the main loop of this host - // object. - main_loop_.Run(); + message_loop()->PostTask(FROM_HERE, + NewRunnableMethod(this, &SimpleHost::RegisterHost)); } // This method is called when we need to destroy the host process. void SimpleHost::DestroySession() { - DCHECK_EQ(&main_loop_, MessageLoop::current()); + DCHECK_EQ(message_loop(), MessageLoop::current()); // First we tell the session to pause and then we wait until all // the tasks are done. @@ -69,18 +77,18 @@ void SimpleHost::DestroySession() { // This method talks to the cloud to register the host process. If // successful we will start listening to network requests. void SimpleHost::RegisterHost() { - DCHECK_EQ(&main_loop_, MessageLoop::current()); + DCHECK_EQ(message_loop(), MessageLoop::current()); DCHECK(!jingle_client_); // Connect to the talk network with a JingleClient. - jingle_client_ = new JingleClient(); + jingle_client_ = new JingleClient(&network_thread_); jingle_client_->Init(username_, auth_token_, kChromotingTokenServiceName, this); } // This method is called if a client is connected to this object. void SimpleHost::OnClientConnected(ClientConnection* client) { - DCHECK_EQ(&main_loop_, MessageLoop::current()); + DCHECK_EQ(message_loop(), MessageLoop::current()); // Create a new RecordSession if there was none. if (!session_.get()) { @@ -97,7 +105,7 @@ void SimpleHost::OnClientConnected(ClientConnection* client) { DCHECK(encoder_.get()); session_ = new SessionManager(capture_thread_.message_loop(), encode_thread_.message_loop(), - &main_loop_, + message_loop(), capturer_.release(), encoder_.release()); @@ -112,7 +120,7 @@ void SimpleHost::OnClientConnected(ClientConnection* client) { } void SimpleHost::OnClientDisconnected(ClientConnection* client) { - DCHECK_EQ(&main_loop_, MessageLoop::current()); + DCHECK_EQ(message_loop(), MessageLoop::current()); // Remove the client from the session manager. if (session_.get()) @@ -131,7 +139,7 @@ void SimpleHost::OnClientDisconnected(ClientConnection* client) { // ClientConnection::EventHandler implementations void SimpleHost::HandleMessages(ClientConnection* client, ClientMessageList* messages) { - DCHECK_EQ(&main_loop_, MessageLoop::current()); + DCHECK_EQ(message_loop(), MessageLoop::current()); // Delegate the messages to EventExecutor and delete the unhandled // messages. @@ -141,7 +149,7 @@ void SimpleHost::HandleMessages(ClientConnection* client, } void SimpleHost::OnConnectionOpened(ClientConnection* client) { - DCHECK_EQ(&main_loop_, MessageLoop::current()); + DCHECK_EQ(message_loop(), MessageLoop::current()); // Completes the client connection. LOG(INFO) << "Connection to client established."; @@ -149,7 +157,7 @@ void SimpleHost::OnConnectionOpened(ClientConnection* client) { } void SimpleHost::OnConnectionClosed(ClientConnection* client) { - DCHECK_EQ(&main_loop_, MessageLoop::current()); + DCHECK_EQ(message_loop(), MessageLoop::current()); // Completes the client connection. LOG(INFO) << "Connection to client closed."; @@ -157,7 +165,7 @@ void SimpleHost::OnConnectionClosed(ClientConnection* client) { } void SimpleHost::OnConnectionFailed(ClientConnection* client) { - DCHECK_EQ(&main_loop_, MessageLoop::current()); + DCHECK_EQ(message_loop(), MessageLoop::current()); // The client has disconnected. LOG(ERROR) << "Connection failed unexpectedly."; @@ -183,7 +191,8 @@ void SimpleHost::OnStateChange(JingleClient* jingle_client, heartbeat_sender_ = NULL; // Quit the message loop if disconected. - main_loop_.PostTask(FROM_HERE, new MessageLoop::QuitTask()); + message_loop()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); + host_done_->Signal(); } } @@ -200,7 +209,7 @@ bool SimpleHost::OnAcceptConnection( // If we accept the connected then create a client object and set the // callback. - client_ = new ClientConnection(&main_loop_, new ProtocolDecoder(), this); + client_ = new ClientConnection(message_loop(), new ProtocolDecoder(), this); *channel_callback = client_.get(); return true; } @@ -215,4 +224,8 @@ void SimpleHost::OnNewConnection(JingleClient* jingle_client, client_->set_jingle_channel(channel); } +MessageLoop* SimpleHost::message_loop() { + return main_thread_.message_loop(); +} + } // namespace remoting diff --git a/remoting/host/simple_host.h b/remoting/host/simple_host.h index 7f9227a..858a7bb 100644 --- a/remoting/host/simple_host.h +++ b/remoting/host/simple_host.h @@ -15,6 +15,11 @@ #include "remoting/host/heartbeat_sender.h" #include "remoting/host/session_manager.h" #include "remoting/jingle_glue/jingle_client.h" +#include "remoting/jingle_glue/jingle_thread.h" + +namespace base { +class WaitableEvent; +} // namespace base namespace remoting { @@ -48,7 +53,9 @@ class SimpleHost : public base::RefCountedThreadSafe<SimpleHost>, public JingleClient::Callback { public: SimpleHost(const std::string& username, const std::string& auth_token, - Capturer* capturer, Encoder* encoder, EventExecutor* executor); + Capturer* capturer, Encoder* encoder, EventExecutor* executor, + base::WaitableEvent* host_done); + virtual ~SimpleHost(); // Run the host porcess. This method returns only after the message loop // of the host process exits. @@ -87,7 +94,13 @@ class SimpleHost : public base::RefCountedThreadSafe<SimpleHost>, private: // The message loop that this class runs on. - MessageLoop main_loop_; + MessageLoop* message_loop(); + + // The main thread that this object runs on. + base::Thread main_thread_; + + // Used to handle the Jingle connection. + JingleThread network_thread_; // A thread that hosts capture operations. base::Thread capture_thread_; @@ -123,6 +136,9 @@ class SimpleHost : public base::RefCountedThreadSafe<SimpleHost>, // Session manager for the host process. scoped_refptr<SessionManager> session_; + // Signals the host is ready to be destroyed. + base::WaitableEvent* host_done_; + DISALLOW_COPY_AND_ASSIGN(SimpleHost); }; diff --git a/remoting/host/simple_host_process.cc b/remoting/host/simple_host_process.cc index 613cf52..d7f454c 100644 --- a/remoting/host/simple_host_process.cc +++ b/remoting/host/simple_host_process.cc @@ -22,6 +22,7 @@ #endif // defined (OS_POSIX) #include "base/at_exit.h" +#include "base/waitable_event.h" #include "remoting/host/capturer_fake.h" #include "remoting/host/encoder_verbatim.h" #include "remoting/host/simple_host.h" @@ -105,11 +106,14 @@ int main(int argc, char** argv) { // Construct a simple host with username and auth_token. // TODO(hclam): Allow the host to load saved credentials. + base::WaitableEvent host_done(false, false); scoped_refptr<remoting::SimpleHost> host = new remoting::SimpleHost(username, auth_token, capturer.release(), encoder.release(), - executor.release()); + executor.release(), + &host_done); host->Run(); + host_done.Wait(); return 0; } diff --git a/remoting/jingle_glue/jingle_client.cc b/remoting/jingle_glue/jingle_client.cc index bf6baee..8fb0714 100644 --- a/remoting/jingle_glue/jingle_client.cc +++ b/remoting/jingle_glue/jingle_client.cc @@ -2,6 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// TODO(ajwong): Check the initialization sentinels. Can we base it off of +// state_ instead of a member variable? Also, we assign and read from a few of +// the member variables on two threads. We need to audit this for thread +// safety. + #include "remoting/jingle_glue/jingle_client.h" #include "base/logging.h" @@ -24,9 +29,12 @@ namespace remoting { -JingleClient::JingleClient() - : callback_(NULL), - state_(START) { } +JingleClient::JingleClient(JingleThread* thread) + : client_(NULL), + thread_(thread), + state_(START), + callback_(NULL) { +} JingleClient::~JingleClient() { // JingleClient can be destroyed only after it's closed. @@ -38,67 +46,46 @@ void JingleClient::Init( const std::string& auth_token_service, Callback* callback) { DCHECK(username != ""); DCHECK(callback != NULL); - DCHECK(thread_ == NULL); // Init() can be called only once. + DCHECK(callback_ == NULL); // Init() can be called only once. callback_ = callback; - thread_.reset(new JingleThread()); - thread_->Start(); - thread_->message_loop()->PostTask( + message_loop()->PostTask( FROM_HERE, NewRunnableMethod(this, &JingleClient::DoInitialize, username, auth_token, auth_token_service)); } -class JingleClient::ConnectRequest { - public: - ConnectRequest() - : completed_event_(true, false) { } - - JingleChannel* Wait() { - completed_event_.Wait(); - return channel_; - }; - - void Done(JingleChannel* channel) { - channel_ = channel; - completed_event_.Signal(); - }; - - private: - base::WaitableEvent completed_event_; - JingleChannel* channel_; -}; - JingleChannel* JingleClient::Connect(const std::string& host_jid, JingleChannel::Callback* callback) { - ConnectRequest request; - thread_->message_loop()->PostTask( + // Ownership if channel is given to DoConnect. + scoped_refptr<JingleChannel> channel = new JingleChannel(callback); + message_loop()->PostTask( FROM_HERE, NewRunnableMethod(this, &JingleClient::DoConnect, - &request, host_jid, callback)); - return request.Wait(); + channel, host_jid, callback)); + return channel; } -void JingleClient::DoConnect(ConnectRequest* request, +void JingleClient::DoConnect(scoped_refptr<JingleChannel> channel, const std::string& host_jid, JingleChannel::Callback* callback) { + DCHECK_EQ(message_loop(), MessageLoop::current()); + talk_base::StreamInterface* stream = tunnel_session_client_->CreateTunnel(buzz::Jid(host_jid), ""); DCHECK(stream != NULL); - JingleChannel* channel = new JingleChannel(callback); - channel->Init(thread_.get(), stream, host_jid); - request->Done(channel); + channel->Init(thread_, stream, host_jid); } void JingleClient::Close() { - DCHECK(thread_ != NULL); // Close() be called only after Init(). message_loop()->PostTask( FROM_HERE, NewRunnableMethod(this, &JingleClient::DoClose)); - thread_->Stop(); - thread_.reset(NULL); } void JingleClient::DoClose() { + DCHECK_EQ(message_loop(), MessageLoop::current()); + DCHECK(callback_ != NULL); // Close() should only be called after Init(). + client_->Disconnect(); // Client is deleted by TaskRunner. client_ = NULL; @@ -112,6 +99,8 @@ void JingleClient::DoClose() { void JingleClient::DoInitialize(const std::string& username, const std::string& auth_token, const std::string& auth_token_service) { + DCHECK_EQ(message_loop(), MessageLoop::current()); + buzz::Jid login_jid(username); buzz::XmppClientSettings settings; @@ -154,9 +143,10 @@ void JingleClient::DoInitialize(const std::string& username, session_manager_.get())); #endif // USE_SSL_TUNNEL - receiver_ = new cricket::SessionManagerTask(client_, session_manager_.get()); - receiver_->EnableOutgoingMessages(); - receiver_->Start(); + cricket::SessionManagerTask* receiver = + new cricket::SessionManagerTask(client_, session_manager_.get()); + receiver->EnableOutgoingMessages(); + receiver->Start(); tunnel_session_client_->SignalIncomingTunnel.connect( this, &JingleClient::OnIncomingTunnel); @@ -168,9 +158,6 @@ std::string JingleClient::GetFullJid() { } MessageLoop* JingleClient::message_loop() { - if (thread_ == NULL) { - return NULL; - } return thread_->message_loop(); } @@ -210,7 +197,7 @@ void JingleClient::OnIncomingTunnel( talk_base::StreamInterface* stream = client->AcceptTunnel(session); scoped_refptr<JingleChannel> channel(new JingleChannel(channel_callback)); - channel->Init(thread_.get(), stream, jid.Str()); + channel->Init(thread_, stream, jid.Str()); callback_->OnNewConnection(this, channel); } else { client->DeclineTunnel(session); diff --git a/remoting/jingle_glue/jingle_client.h b/remoting/jingle_glue/jingle_client.h index 2a68042..a074757 100644 --- a/remoting/jingle_glue/jingle_client.h +++ b/remoting/jingle_glue/jingle_client.h @@ -60,13 +60,15 @@ class JingleClient : public base::RefCountedThreadSafe<JingleClient>, scoped_refptr<JingleChannel> channel) = 0; }; - JingleClient(); + // Creates a JingleClient object that executes on |thread|. This does not + // take ownership of |thread| and expects that the thread is started before + // the constructor is called, and only stopped after the JingleClient object + // has been destructed. + JingleClient(JingleThread* thread); virtual ~JingleClient(); - // Starts jingle thread and XMPP connection inialization. Must be called - // only once. message_loop() is guaranteed to exist after this method returns, - // but the connection may not be open yet. |callback| specifies callback - // object for the client and must not be NULL. + // Starts the XMPP connection inialization. Must be called only once. + // |callback| specifies callback object for the client and must not be NULL. void Init(const std::string& username, const std::string& auth_token, const std::string& auth_token_service, Callback* callback); @@ -92,13 +94,10 @@ class JingleClient : public base::RefCountedThreadSafe<JingleClient>, // Returns XmppClient object for the xmpp connection or NULL if not connected. buzz::XmppClient* xmpp_client() { return client_; } - // Message loop for the jingle thread or NULL if the thread is not started. + // Message loop used by this object to execute tasks. MessageLoop* message_loop(); private: - // Used by Connect(). - class ConnectRequest; - void OnConnectionStateChanged(buzz::XmppEngine::State state); void OnIncomingTunnel(cricket::TunnelSessionClient* client, buzz::Jid jid, @@ -109,7 +108,7 @@ class JingleClient : public base::RefCountedThreadSafe<JingleClient>, const std::string& auth_token_service); // Used by Connect(). - void DoConnect(ConnectRequest* request, + void DoConnect(scoped_refptr<JingleChannel> channel, const std::string& host_jid, JingleChannel::Callback* callback); @@ -123,9 +122,8 @@ class JingleClient : public base::RefCountedThreadSafe<JingleClient>, buzz::PreXmppAuth* CreatePreXmppAuth( const buzz::XmppClientSettings& settings); - buzz::XmppClient* client_; - scoped_ptr<JingleThread> thread_; + JingleThread* thread_; State state_; Callback* callback_; @@ -136,7 +134,6 @@ class JingleClient : public base::RefCountedThreadSafe<JingleClient>, scoped_ptr<cricket::BasicPortAllocator> port_allocator_; scoped_ptr<cricket::SessionManager> session_manager_; scoped_ptr<cricket::TunnelSessionClient> tunnel_session_client_; - cricket::SessionManagerTask* receiver_; DISALLOW_COPY_AND_ASSIGN(JingleClient); }; |