summaryrefslogtreecommitdiffstats
path: root/remoting
diff options
context:
space:
mode:
Diffstat (limited to 'remoting')
-rw-r--r--remoting/chromoting.gyp3
-rw-r--r--remoting/client/client_util.cc24
-rw-r--r--remoting/client/client_util.h6
-rw-r--r--remoting/client/host_connection.cc86
-rw-r--r--remoting/client/host_connection.h45
-rw-r--r--remoting/client/jingle_host_connection.cc134
-rw-r--r--remoting/client/jingle_host_connection.h83
-rw-r--r--remoting/client/simple_client.cc64
-rw-r--r--remoting/host/simple_host.cc73
-rw-r--r--remoting/host/simple_host.h20
-rw-r--r--remoting/host/simple_host_process.cc6
-rw-r--r--remoting/jingle_glue/jingle_client.cc77
-rw-r--r--remoting/jingle_glue/jingle_client.h23
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);
};