summaryrefslogtreecommitdiffstats
path: root/remoting/jingle_glue
diff options
context:
space:
mode:
authorajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-03 15:56:57 +0000
committerajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-03 15:56:57 +0000
commite05eb1d621ca0a26e0b33c650d4dbf456dba6863 (patch)
tree97322432de7e2381eb065cc3af19d53abba6e2f3 /remoting/jingle_glue
parentfbc94a82c898c17dffbb7bad4f2ed70ffc15b133 (diff)
downloadchromium_src-e05eb1d621ca0a26e0b33c650d4dbf456dba6863.zip
chromium_src-e05eb1d621ca0a26e0b33c650d4dbf456dba6863.tar.gz
chromium_src-e05eb1d621ca0a26e0b33c650d4dbf456dba6863.tar.bz2
Refactor JingleClient to support thunking the xmpp signaling into Javascript.
We do this so that we may make HTTP requests using the javascript libraries available to Google Talk. This is required to allow us to sandbox. BUG=none TEST=none Review URL: http://codereview.chromium.org/6597092 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@76746 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting/jingle_glue')
-rw-r--r--remoting/jingle_glue/iq_request.cc90
-rw-r--r--remoting/jingle_glue/iq_request.h98
-rw-r--r--remoting/jingle_glue/jingle_client.cc245
-rw-r--r--remoting/jingle_glue/jingle_client.h153
-rw-r--r--remoting/jingle_glue/jingle_client_unittest.cc15
5 files changed, 412 insertions, 189 deletions
diff --git a/remoting/jingle_glue/iq_request.cc b/remoting/jingle_glue/iq_request.cc
index c56ef4c..8d53b40 100644
--- a/remoting/jingle_glue/iq_request.cc
+++ b/remoting/jingle_glue/iq_request.cc
@@ -7,28 +7,42 @@
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
-#include "remoting/jingle_glue/jingle_client.h"
#include "third_party/libjingle/source/talk/xmpp/constants.h"
-#include "third_party/libjingle/source/talk/xmpp/xmppengine.h"
+#include "third_party/libjingle/source/talk/xmpp/xmppclient.h"
namespace remoting {
-IqRequest::IqRequest(JingleClient* jingle_client)
- : jingle_client_(jingle_client),
+// static
+buzz::XmlElement* IqRequest::MakeIqStanza(const std::string& type,
+ const std::string& addressee,
+ buzz::XmlElement* iq_body,
+ const std::string& id) {
+ buzz::XmlElement* stanza = new buzz::XmlElement(buzz::QN_IQ);
+ stanza->AddAttr(buzz::QN_TYPE, type);
+ stanza->AddAttr(buzz::QN_TO, addressee);
+ stanza->AddAttr(buzz::QN_ID, id);
+ stanza->AddElement(iq_body);
+ return stanza;
+}
+
+XmppIqRequest::XmppIqRequest(MessageLoop* message_loop,
+ buzz::XmppClient* xmpp_client)
+ : message_loop_(message_loop),
+ xmpp_client_(xmpp_client),
cookie_(NULL) {
- DCHECK(jingle_client_ != NULL);
- DCHECK(MessageLoop::current() == jingle_client_->message_loop());
+ DCHECK(xmpp_client_);
+ DCHECK_EQ(MessageLoop::current(), message_loop_);
}
-IqRequest::~IqRequest() {
- DCHECK(MessageLoop::current() == jingle_client_->message_loop());
+XmppIqRequest::~XmppIqRequest() {
+ DCHECK_EQ(MessageLoop::current(), message_loop_);
Unregister();
}
-void IqRequest::SendIq(const std::string& type,
+void XmppIqRequest::SendIq(const std::string& type,
const std::string& addressee,
buzz::XmlElement* iq_body) {
- DCHECK(MessageLoop::current() == jingle_client_->message_loop());
+ DCHECK_EQ(MessageLoop::current(), message_loop_);
// Unregister the handler if it is already registered.
Unregister();
@@ -36,44 +50,54 @@ void IqRequest::SendIq(const std::string& type,
DCHECK_GT(type.length(), 0U);
DCHECK_GT(addressee.length(), 0U);
- buzz::XmppClient* xmpp_client = jingle_client_->xmpp_client();
- DCHECK(xmpp_client); // Expect that connection is active.
-
scoped_ptr<buzz::XmlElement> stanza(MakeIqStanza(type, addressee, iq_body,
- xmpp_client->NextId()));
+ xmpp_client_->NextId()));
- xmpp_client->engine()->SendIq(stanza.get(), this, &cookie_);
-}
-
-// static
-buzz::XmlElement* IqRequest::MakeIqStanza(const std::string& type,
- const std::string& addressee,
- buzz::XmlElement* iq_body,
- const std::string& id) {
- buzz::XmlElement* stanza = new buzz::XmlElement(buzz::QN_IQ);
- stanza->AddAttr(buzz::QN_TYPE, type);
- stanza->AddAttr(buzz::QN_TO, addressee);
- stanza->AddAttr(buzz::QN_ID, id);
- stanza->AddElement(iq_body);
- return stanza;
+ xmpp_client_->engine()->SendIq(stanza.get(), this, &cookie_);
}
-void IqRequest::Unregister() {
+void XmppIqRequest::Unregister() {
if (cookie_) {
- buzz::XmppClient* xmpp_client = jingle_client_->xmpp_client();
// No need to unregister the handler if the client has been destroyed.
- if (xmpp_client) {
- xmpp_client->engine()->RemoveIqHandler(cookie_, NULL);
+ if (xmpp_client_) {
+ xmpp_client_->engine()->RemoveIqHandler(cookie_, NULL);
}
cookie_ = NULL;
}
}
-void IqRequest::IqResponse(buzz::XmppIqCookie cookie,
+void XmppIqRequest::IqResponse(buzz::XmppIqCookie cookie,
const buzz::XmlElement* stanza) {
if (callback_.get() != NULL) {
callback_->Run(stanza);
}
}
+JavascriptIqRequest::JavascriptIqRequest() {
+}
+
+JavascriptIqRequest::~JavascriptIqRequest() {
+}
+
+void JavascriptIqRequest::SendIq(const std::string& type,
+ const std::string& addressee,
+ buzz::XmlElement* iq_body) {
+ NOTIMPLEMENTED();
+ // TODO(ajwong): The "1" below is completely wrong. Need to change to use a
+ // sequence that just increments or something.
+ scoped_ptr<buzz::XmlElement> stanza(
+ MakeIqStanza(type, addressee, iq_body, "1"));
+
+ xmpp_proxy_->SendIq(stanza->Str());
+}
+
+void JavascriptIqRequest::ReceiveIq(const std::string& iq_response) {
+ // TODO(ajwong): Somehow send this to callback_ here.
+ LOG(ERROR) << "Got IQ!!!!!!\n" << iq_response;
+}
+
+void JavascriptIqRequest::set_callback(ReplyCallback* callback) {
+ callback_.reset(callback);
+}
+
} // namespace remoting
diff --git a/remoting/jingle_glue/iq_request.h b/remoting/jingle_glue/iq_request.h
index 6933b17..3d11034 100644
--- a/remoting/jingle_glue/iq_request.h
+++ b/remoting/jingle_glue/iq_request.h
@@ -9,11 +9,42 @@
#include "base/callback.h"
#include "base/gtest_prod_util.h"
+#include "base/weak_ptr.h"
#include "third_party/libjingle/source/talk/xmpp/xmppengine.h"
+class MessageLoop;
+
+namespace buzz {
+class XmppClient;
+} // namespace buzz
+
namespace remoting {
-class JingleClient;
+class JavascriptIqRequest;
+class ChromotingScriptableObject;
+
+class XmppProxy : public base::RefCountedThreadSafe<XmppProxy> {
+ public:
+ XmppProxy() {}
+
+ // Must be run on pepper thread.
+ virtual void AttachScriptableObject(
+ ChromotingScriptableObject* scriptable_object) = 0;
+
+ // Must be run on jingle thread.
+ virtual void AttachJavascriptIqRequest(
+ JavascriptIqRequest* javascript_iq_request) = 0;
+
+ virtual void SendIq(const std::string& iq_request_xml) = 0;
+ virtual void ReceiveIq(const std::string& iq_response_xml) = 0;
+
+ protected:
+ friend class base::RefCountedThreadSafe<XmppProxy>;
+ virtual ~XmppProxy() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(XmppProxy);
+};
// IqRequest class can be used to send an IQ stanza and then receive reply
// stanza for that request. It sends outgoing stanza when SendIq() is called,
@@ -21,22 +52,67 @@ class JingleClient;
// set_callback(). If multiple IQ stanzas are send with SendIq() then only reply
// to the last one will be received.
// The class must be used on the jingle thread only.
-class IqRequest : private buzz::XmppIqHandler {
+class IqRequest {
public:
typedef Callback1<const buzz::XmlElement*>::Type ReplyCallback;
- explicit IqRequest(JingleClient* jingle_client);
- virtual ~IqRequest();
+ IqRequest() {}
+ virtual ~IqRequest() {}
// Sends stanza of type |type| to |addressee|. |iq_body| contains body of
// the stanza. Ownership of |iq_body| is transfered to IqRequest. Must
// be called on the jingle thread.
virtual void SendIq(const std::string& type, const std::string& addressee,
- buzz::XmlElement* iq_body);
+ buzz::XmlElement* iq_body) = 0;
// Sets callback that is called when reply stanza is received. Callback
// is called on the jingle thread.
- void set_callback(ReplyCallback* callback) {
+ virtual void set_callback(ReplyCallback* callback) = 0;
+
+ protected:
+ static buzz::XmlElement* MakeIqStanza(const std::string& type,
+ const std::string& addressee,
+ buzz::XmlElement* iq_body,
+ const std::string& id);
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(IqRequestTest, MakeIqStanza);
+
+ DISALLOW_COPY_AND_ASSIGN(IqRequest);
+};
+
+// TODO(ajwong): Is this class even used? The client side may never use
+// IqRequests in the JingleClient.
+class JavascriptIqRequest : public IqRequest,
+ public base::SupportsWeakPtr<JavascriptIqRequest> {
+ public:
+ JavascriptIqRequest();
+ virtual ~JavascriptIqRequest();
+
+ virtual void SendIq(const std::string& type, const std::string& addressee,
+ buzz::XmlElement* iq_body);
+
+ virtual void ReceiveIq(const std::string& iq_response);
+
+ virtual void set_callback(ReplyCallback* callback);
+
+ private:
+ scoped_ptr<ReplyCallback> callback_;
+ scoped_refptr<XmppProxy> xmpp_proxy_;
+
+ FRIEND_TEST_ALL_PREFIXES(IqRequestTest, MakeIqStanza);
+};
+
+class XmppIqRequest : public IqRequest, private buzz::XmppIqHandler {
+ public:
+ typedef Callback1<const buzz::XmlElement*>::Type ReplyCallback;
+
+ XmppIqRequest(MessageLoop* message_loop, buzz::XmppClient* xmpp_client);
+ virtual ~XmppIqRequest();
+
+ virtual void SendIq(const std::string& type, const std::string& addressee,
+ buzz::XmlElement* iq_body);
+ virtual void set_callback(ReplyCallback* callback) {
callback_.reset(callback);
}
@@ -47,14 +123,12 @@ class IqRequest : private buzz::XmppIqHandler {
virtual void IqResponse(buzz::XmppIqCookie cookie,
const buzz::XmlElement* stanza);
- static buzz::XmlElement* MakeIqStanza(const std::string& type,
- const std::string& addressee,
- buzz::XmlElement* iq_body,
- const std::string& id);
-
void Unregister();
- scoped_refptr<JingleClient> jingle_client_;
+ // TODO(ajwong): This used to hold a reference to the jingle client...make
+ // sure the lifetime names sense now.
+ MessageLoop* message_loop_;
+ buzz::XmppClient* xmpp_client_;
buzz::XmppIqCookie cookie_;
scoped_ptr<ReplyCallback> callback_;
};
diff --git a/remoting/jingle_glue/jingle_client.cc b/remoting/jingle_glue/jingle_client.cc
index 7b00d79..02593ed 100644
--- a/remoting/jingle_glue/jingle_client.cc
+++ b/remoting/jingle_glue/jingle_client.cc
@@ -22,79 +22,178 @@
namespace remoting {
-JingleClient::JingleClient(JingleThread* thread)
- : thread_(thread),
- callback_(NULL),
- client_(NULL),
- state_(START),
- initialized_(false),
- closed_(false) {
-}
-
-JingleClient::~JingleClient() {
- base::AutoLock auto_lock(state_lock_);
- DCHECK(!initialized_ || closed_);
+// The XmppSignalStrategy encapsulates all the logic to perform the signaling
+// STUN/ICE for jingle via a direct XMPP connection.
+//
+// This class is not threadsafe.
+XmppSignalStrategy::XmppSignalStrategy(JingleThread* jingle_thread,
+ const std::string& username,
+ const std::string& auth_token,
+ const std::string& auth_token_service)
+ : thread_(jingle_thread),
+ username_(username),
+ auth_token_(auth_token),
+ auth_token_service_(auth_token_service),
+ xmpp_client_(NULL),
+ observer_(NULL) {
}
-void JingleClient::Init(
- const std::string& username, const std::string& auth_token,
- const std::string& auth_token_service, Callback* callback) {
- DCHECK_NE(username, "");
-
- {
- base::AutoLock auto_lock(state_lock_);
- DCHECK(!initialized_ && !closed_);
- initialized_ = true;
-
- DCHECK(callback != NULL);
- callback_ = callback;
- }
-
- message_loop()->PostTask(
- FROM_HERE, NewRunnableMethod(this, &JingleClient::DoInitialize,
- username, auth_token, auth_token_service));
+XmppSignalStrategy::~XmppSignalStrategy() {
}
-void JingleClient::DoInitialize(const std::string& username,
- const std::string& auth_token,
- const std::string& auth_token_service) {
- DCHECK_EQ(message_loop(), MessageLoop::current());
+void XmppSignalStrategy::Init(StatusObserver* observer) {
+ observer_ = observer;
- buzz::Jid login_jid(username);
+ buzz::Jid login_jid(username_);
buzz::XmppClientSettings settings;
settings.set_user(login_jid.node());
settings.set_host(login_jid.domain());
settings.set_resource("chromoting");
settings.set_use_tls(true);
- settings.set_token_service(auth_token_service);
- settings.set_auth_cookie(auth_token);
+ settings.set_token_service(auth_token_service_);
+ settings.set_auth_cookie(auth_token_);
settings.set_server(talk_base::SocketAddress("talk.google.com", 5222));
- client_ = new buzz::XmppClient(thread_->task_pump());
- client_->SignalStateChange.connect(
- this, &JingleClient::OnConnectionStateChanged);
-
buzz::AsyncSocket* socket = new XmppSocketAdapter(settings, false);
- client_->Connect(settings, "", socket, CreatePreXmppAuth(settings));
- client_->Start();
+ xmpp_client_ = new buzz::XmppClient(thread_->task_pump());
+ xmpp_client_->Connect(settings, "", socket, CreatePreXmppAuth(settings));
+ xmpp_client_->SignalStateChange.connect(
+ this, &XmppSignalStrategy::OnConnectionStateChanged);
+ xmpp_client_->Start();
+ // Setup the port allocation based on jingle connections.
network_manager_.reset(new talk_base::NetworkManager());
-
RelayPortAllocator* port_allocator =
new RelayPortAllocator(network_manager_.get(), "transp2");
+ port_allocator->SetJingleInfo(xmpp_client_);
port_allocator_.reset(port_allocator);
- port_allocator->SetJingleInfo(client_);
+}
- session_manager_.reset(new cricket::SessionManager(port_allocator_.get()));
+cricket::BasicPortAllocator* XmppSignalStrategy::port_allocator() {
+ return port_allocator_.get();
+}
+void XmppSignalStrategy::StartSession(
+ cricket::SessionManager* session_manager) {
cricket::SessionManagerTask* receiver =
- new cricket::SessionManagerTask(client_, session_manager_.get());
+ new cricket::SessionManagerTask(xmpp_client_, session_manager);
receiver->EnableOutgoingMessages();
receiver->Start();
}
+void XmppSignalStrategy::EndSession() {
+ if (xmpp_client_) {
+ xmpp_client_->Disconnect();
+ // Client is deleted by TaskRunner.
+ xmpp_client_ = NULL;
+ }
+}
+
+IqRequest* XmppSignalStrategy::CreateIqRequest() {
+ return new XmppIqRequest(thread_->message_loop(), xmpp_client_);
+}
+
+void XmppSignalStrategy::OnConnectionStateChanged(
+ buzz::XmppEngine::State state) {
+ switch (state) {
+ case buzz::XmppEngine::STATE_START:
+ observer_->OnStateChange(StatusObserver::START);
+ break;
+ case buzz::XmppEngine::STATE_OPENING:
+ observer_->OnStateChange(StatusObserver::CONNECTING);
+ break;
+ case buzz::XmppEngine::STATE_OPEN:
+ observer_->OnJidChange(xmpp_client_->jid().Str());
+ observer_->OnStateChange(StatusObserver::CONNECTED);
+ break;
+ case buzz::XmppEngine::STATE_CLOSED:
+ observer_->OnStateChange(StatusObserver::CLOSED);
+ // Client is destroyed by the TaskRunner after the client is
+ // closed. Reset the pointer so we don't try to use it later.
+ xmpp_client_ = NULL;
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+buzz::PreXmppAuth* XmppSignalStrategy::CreatePreXmppAuth(
+ const buzz::XmppClientSettings& settings) {
+ buzz::Jid jid(settings.user(), settings.host(), buzz::STR_EMPTY);
+ return new notifier::GaiaTokenPreXmppAuth(jid.Str(), settings.auth_cookie(),
+ settings.token_service());
+}
+
+
+JavascriptSignalStrategy::JavascriptSignalStrategy() {
+}
+
+JavascriptSignalStrategy::~JavascriptSignalStrategy() {
+}
+
+void JavascriptSignalStrategy::Init(StatusObserver* observer) {
+ NOTIMPLEMENTED();
+}
+
+cricket::BasicPortAllocator* JavascriptSignalStrategy::port_allocator() {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+void JavascriptSignalStrategy::StartSession(
+ cricket::SessionManager* session_manager) {
+ NOTIMPLEMENTED();
+}
+
+void JavascriptSignalStrategy::EndSession() {
+ NOTIMPLEMENTED();
+}
+
+IqRequest* JavascriptSignalStrategy::CreateIqRequest() {
+ return new JavascriptIqRequest();
+}
+
+JingleClient::JingleClient(JingleThread* thread,
+ SignalStrategy* signal_strategy,
+ Callback* callback)
+ : thread_(thread),
+ state_(START),
+ initialized_(false),
+ closed_(false),
+ callback_(callback),
+ signal_strategy_(signal_strategy) {
+}
+
+JingleClient::~JingleClient() {
+ base::AutoLock auto_lock(state_lock_);
+ DCHECK(!initialized_ || closed_);
+}
+
+void JingleClient::Init() {
+ {
+ base::AutoLock auto_lock(state_lock_);
+ DCHECK(!initialized_ && !closed_);
+ initialized_ = true;
+ }
+
+ message_loop()->PostTask(
+ FROM_HERE, NewRunnableMethod(this, &JingleClient::DoInitialize));
+}
+
+void JingleClient::DoInitialize() {
+ DCHECK_EQ(message_loop(), MessageLoop::current());
+
+ signal_strategy_->Init(this);
+
+ session_manager_.reset(
+ new cricket::SessionManager(signal_strategy_->port_allocator()));
+
+ signal_strategy_->StartSession(session_manager_.get());
+}
+
void JingleClient::Close() {
Close(NULL);
}
@@ -121,14 +220,9 @@ void JingleClient::DoClose() {
DCHECK(closed_);
session_manager_.reset();
- port_allocator_.reset();
- network_manager_.reset();
-
- if (client_) {
- client_->Disconnect();
- // Client is deleted by TaskRunner.
- client_ = NULL;
- }
+ signal_strategy_->EndSession();
+ // TODO(ajwong): SignalStrategy should drop all resources at EndSession().
+ signal_strategy_ = NULL;
if (closed_task_.get()) {
closed_task_->Run();
@@ -137,12 +231,12 @@ void JingleClient::DoClose() {
}
std::string JingleClient::GetFullJid() {
- base::AutoLock auto_lock(full_jid_lock_);
+ base::AutoLock auto_lock(jid_lock_);
return full_jid_;
}
IqRequest* JingleClient::CreateIqRequest() {
- return new IqRequest(this);
+ return signal_strategy_->CreateIqRequest();
}
MessageLoop* JingleClient::message_loop() {
@@ -154,36 +248,7 @@ cricket::SessionManager* JingleClient::session_manager() {
return session_manager_.get();
}
-void JingleClient::OnConnectionStateChanged(buzz::XmppEngine::State state) {
- switch (state) {
- case buzz::XmppEngine::STATE_START:
- UpdateState(START);
- break;
- case buzz::XmppEngine::STATE_OPENING:
- UpdateState(CONNECTING);
- break;
- case buzz::XmppEngine::STATE_OPEN:
- SetFullJid(client_->jid().Str());
- UpdateState(CONNECTED);
- break;
- case buzz::XmppEngine::STATE_CLOSED:
- UpdateState(CLOSED);
- // Client is destroyed by the TaskRunner after the client is
- // closed. Reset the pointer so we don't try to use it later.
- client_ = NULL;
- break;
- default:
- NOTREACHED();
- break;
- }
-}
-
-void JingleClient::SetFullJid(const std::string& full_jid) {
- base::AutoLock auto_lock(full_jid_lock_);
- full_jid_ = full_jid;
-}
-
-void JingleClient::UpdateState(State new_state) {
+void JingleClient::OnStateChange(State new_state) {
if (new_state != state_) {
state_ = new_state;
{
@@ -196,11 +261,9 @@ void JingleClient::UpdateState(State new_state) {
}
}
-buzz::PreXmppAuth* JingleClient::CreatePreXmppAuth(
- const buzz::XmppClientSettings& settings) {
- buzz::Jid jid(settings.user(), settings.host(), buzz::STR_EMPTY);
- return new notifier::GaiaTokenPreXmppAuth(jid.Str(), settings.auth_cookie(),
- settings.token_service());
+void JingleClient::OnJidChange(const std::string& full_jid) {
+ base::AutoLock auto_lock(jid_lock_);
+ full_jid_ = full_jid;
}
} // namespace remoting
diff --git a/remoting/jingle_glue/jingle_client.h b/remoting/jingle_glue/jingle_client.h
index 173e90e..f60e029 100644
--- a/remoting/jingle_glue/jingle_client.h
+++ b/remoting/jingle_glue/jingle_client.h
@@ -7,6 +7,7 @@
#include <string>
+#include "base/gtest_prod_util.h"
#include "base/ref_counted.h"
#include "base/synchronization/lock.h"
#include "third_party/libjingle/source/talk/xmpp/xmppclient.h"
@@ -35,16 +36,90 @@ namespace remoting {
class IqRequest;
class JingleThread;
-class JingleClient : public base::RefCountedThreadSafe<JingleClient>,
- public sigslot::has_slots<> {
+// TODO(ajwong): The SignalStrategy stuff needs to be separated out to separate
+// files.
+class SignalStrategy {
public:
- enum State {
- START, // Initial state.
- CONNECTING,
- CONNECTED,
- CLOSED,
+ class StatusObserver {
+ public:
+ enum State {
+ START,
+ CONNECTING,
+ CONNECTED,
+ CLOSED,
+ };
+
+ // Called when state of the connection is changed.
+ virtual void OnStateChange(State state) = 0;
+ virtual void OnJidChange(const std::string& full_jid) = 0;
};
+ SignalStrategy() {}
+ virtual ~SignalStrategy() {}
+ virtual void Init(StatusObserver* observer) = 0;
+ virtual cricket::BasicPortAllocator* port_allocator() = 0;
+ virtual void StartSession(cricket::SessionManager* session_manager) = 0;
+ virtual void EndSession() = 0;
+ virtual IqRequest* CreateIqRequest() = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SignalStrategy);
+};
+
+class XmppSignalStrategy : public SignalStrategy, public sigslot::has_slots<> {
+ public:
+ XmppSignalStrategy(JingleThread* thread,
+ const std::string& username,
+ const std::string& auth_token,
+ const std::string& auth_token_service);
+ virtual ~XmppSignalStrategy();
+
+ virtual void Init(StatusObserver* observer);
+ virtual cricket::BasicPortAllocator* port_allocator();
+ virtual void StartSession(cricket::SessionManager* session_manager);
+ virtual void EndSession();
+ virtual IqRequest* CreateIqRequest();
+
+ private:
+ void OnConnectionStateChanged(buzz::XmppEngine::State state);
+ static buzz::PreXmppAuth* CreatePreXmppAuth(
+ const buzz::XmppClientSettings& settings);
+
+ JingleThread* thread_;
+
+ std::string username_;
+ std::string auth_token_;
+ std::string auth_token_service_;
+ buzz::XmppClient* xmpp_client_;
+ StatusObserver* observer_;
+ scoped_ptr<talk_base::NetworkManager> network_manager_;
+ scoped_ptr<cricket::BasicPortAllocator> port_allocator_;
+
+ private:
+ friend class JingleClientTest;
+
+ DISALLOW_COPY_AND_ASSIGN(XmppSignalStrategy);
+};
+
+class JavascriptSignalStrategy : public SignalStrategy {
+ public:
+ JavascriptSignalStrategy();
+ virtual ~JavascriptSignalStrategy();
+
+ virtual void Init(StatusObserver* observer);
+ virtual cricket::BasicPortAllocator* port_allocator();
+ virtual void StartSession(cricket::SessionManager* session_manager);
+ virtual void EndSession();
+ virtual IqRequest* CreateIqRequest();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(JavascriptSignalStrategy);
+};
+
+
+class JingleClient : public base::RefCountedThreadSafe<JingleClient>,
+ public SignalStrategy::StatusObserver {
+ public:
class Callback {
public:
virtual ~Callback() {}
@@ -53,17 +128,13 @@ class JingleClient : public base::RefCountedThreadSafe<JingleClient>,
virtual void OnStateChange(JingleClient* client, State state) = 0;
};
- // 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.
- explicit JingleClient(JingleThread* thread);
- virtual ~JingleClient();
+ JingleClient(JingleThread* thread, SignalStrategy* signal_strategy,
+ Callback* callback);
+ ~JingleClient();
// Starts the XMPP connection initialization. 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);
+ void Init();
// Closes XMPP connection and stops the thread. Must be called before the
// object is destroyed. If specified, |closed_task| is executed after the
@@ -77,64 +148,52 @@ class JingleClient : public base::RefCountedThreadSafe<JingleClient>,
// Creates new IqRequest for this client. Ownership for of the created object
// is transfered to the caller.
- virtual IqRequest* CreateIqRequest();
-
- // Current connection state of the client.
- State state() { return state_; }
-
- // Returns XmppClient object for the xmpp connection or NULL if not connected.
- buzz::XmppClient* xmpp_client() { return client_; }
-
- // Message loop used by this object to execute tasks.
- MessageLoop* message_loop();
+ IqRequest* CreateIqRequest();
// The session manager used by this client. Must be called from the
// jingle thread only. Returns NULL if the client is not active.
cricket::SessionManager* session_manager();
+ // Message loop used by this object to execute tasks.
+ MessageLoop* message_loop();
+
private:
friend class HeartbeatSenderTest;
friend class JingleClientTest;
- void OnConnectionStateChanged(buzz::XmppEngine::State state);
-
- void DoInitialize(const std::string& username,
- const std::string& auth_token,
- const std::string& auth_token_service);
-
- // Used by Close().
+ void DoInitialize();
void DoClose();
- void SetFullJid(const std::string& full_jid);
-
// Updates current state of the connection. Must be called only in
// the jingle thread.
void UpdateState(State new_state);
- buzz::PreXmppAuth* CreatePreXmppAuth(
- const buzz::XmppClientSettings& settings);
+ virtual void OnStateChange(State state);
+ virtual void OnJidChange(const std::string& full_jid);
// JingleThread used for the connection. Set in the constructor.
JingleThread* thread_;
- // Callback for this object. Callback must not be called if closed_ == true.
- Callback* callback_;
-
- // The XmppClient and its state and jid.
- buzz::XmppClient* client_;
- State state_;
- base::Lock full_jid_lock_;
- std::string full_jid_;
-
// Current state of the object.
// Must be locked when accessing initialized_ or closed_.
base::Lock state_lock_;
+ State state_;
bool initialized_;
bool closed_;
scoped_ptr<Task> closed_task_;
- scoped_ptr<talk_base::NetworkManager> network_manager_;
- scoped_ptr<cricket::BasicPortAllocator> port_allocator_;
+ // We need a separate lock for the jid since the |state_lock_| may be held
+ // over a callback which can end up having a double lock.
+ //
+ // TODO(ajwong): Can we avoid holding the |state_lock_| over a callback and
+ // remove this extra lock?
+ base::Lock jid_lock_;
+ std::string full_jid_;
+
+ // Callback for this object. Callback must not be called if closed_ == true.
+ Callback* callback_;
+
+ SignalStrategy* signal_strategy_;
scoped_ptr<cricket::SessionManager> session_manager_;
DISALLOW_COPY_AND_ASSIGN(JingleClient);
diff --git a/remoting/jingle_glue/jingle_client_unittest.cc b/remoting/jingle_glue/jingle_client_unittest.cc
index 807f061..3d9f574 100644
--- a/remoting/jingle_glue/jingle_client_unittest.cc
+++ b/remoting/jingle_glue/jingle_client_unittest.cc
@@ -29,22 +29,25 @@ class JingleClientTest : public testing::Test {
// A helper that calls OnConnectionStateChanged(). Need this because we want
// to call it on the jingle thread.
- static void ChangeState(JingleClient* client, buzz::XmppEngine::State state,
+ static void ChangeState(XmppSignalStrategy* strategy,
+ buzz::XmppEngine::State state,
base::WaitableEvent* done_event) {
- client->OnConnectionStateChanged(state);
+ strategy->OnConnectionStateChanged(state);
if (done_event)
done_event->Signal();
}
protected:
virtual void SetUp() {
- client_ = new JingleClient(&thread_);
+ signal_strategy_.reset(new XmppSignalStrategy(&thread_, "", "", ""));
+ client_ = new JingleClient(&thread_, signal_strategy_.get(), &callback_);
// Fake initialization
client_->initialized_ = true;
- client_->callback_ = &callback_;
+ signal_strategy_->observer_ = client_;
}
JingleThread thread_;
+ scoped_ptr<XmppSignalStrategy> signal_strategy_;
scoped_refptr<JingleClient> client_;
MockJingleClientCallback callback_;
};
@@ -57,7 +60,7 @@ TEST_F(JingleClientTest, OnStateChanged) {
base::WaitableEvent state_changed_event(true, false);
thread_.message_loop()->PostTask(FROM_HERE, NewRunnableFunction(
- &JingleClientTest::ChangeState, client_,
+ &JingleClientTest::ChangeState, signal_strategy_.get(),
buzz::XmppEngine::STATE_OPENING, &state_changed_event));
state_changed_event.Wait();
@@ -73,7 +76,7 @@ TEST_F(JingleClientTest, Close) {
client_->Close();
// Verify that the channel doesn't call callback anymore.
thread_.message_loop()->PostTask(FROM_HERE, NewRunnableFunction(
- &JingleClientTest::ChangeState, client_,
+ &JingleClientTest::ChangeState, signal_strategy_.get(),
buzz::XmppEngine::STATE_OPENING,
static_cast<base::WaitableEvent*>(NULL)));
thread_.Stop();