summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-07 17:19:17 +0000
committerajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-07 17:19:17 +0000
commit2db531074be20594b38f882448fa918996cd2abc (patch)
treef7ee240697eefcb53896ede6a01d46266554d190
parenta2f2e479644f4073b00b66d5efc67789b12d1072 (diff)
downloadchromium_src-2db531074be20594b38f882448fa918996cd2abc.zip
chromium_src-2db531074be20594b38f882448fa918996cd2abc.tar.gz
chromium_src-2db531074be20594b38f882448fa918996cd2abc.tar.bz2
Wire up the codepath from Javascript into Jingle for IQ packets.
Flushes out XmppProxy, the thread-safe interface that matches up Pepper with Jingle and plumbs a ConnectSandboxed method through everything so that the connection type can be chosen at runtime. BUG=51198 TEST=Check that stanzas are sent/received from JS, and that xmpp still works. Review URL: http://codereview.chromium.org/6603036 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@77148 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--remoting/client/chromoting_client.cc21
-rw-r--r--remoting/client/chromoting_client.h4
-rw-r--r--remoting/client/plugin/chromoting_instance.cc55
-rw-r--r--remoting/client/plugin/chromoting_instance.h20
-rw-r--r--remoting/client/plugin/chromoting_scriptable_object.cc75
-rw-r--r--remoting/client/plugin/chromoting_scriptable_object.h47
-rw-r--r--remoting/client/plugin/pepper_util.cc4
-rw-r--r--remoting/client/plugin/pepper_util.h3
-rw-r--r--remoting/client/plugin/pepper_view.cc24
-rw-r--r--remoting/client/plugin/pepper_view_proxy.cc22
-rw-r--r--remoting/client/plugin/pepper_xmpp_proxy.cc61
-rw-r--r--remoting/client/plugin/pepper_xmpp_proxy.h45
-rw-r--r--remoting/jingle_glue/iq_request.cc242
-rw-r--r--remoting/jingle_glue/iq_request.h185
-rw-r--r--remoting/jingle_glue/jingle_client.cc104
-rw-r--r--remoting/jingle_glue/jingle_client.h35
-rw-r--r--remoting/jingle_glue/jingle_info_task.cc139
-rw-r--r--remoting/jingle_glue/jingle_info_task.h45
-rw-r--r--remoting/jingle_glue/xmpp_proxy.h57
-rw-r--r--remoting/protocol/connection_to_host.cc35
-rw-r--r--remoting/protocol/connection_to_host.h7
-rw-r--r--remoting/remoting.gyp5
22 files changed, 806 insertions, 429 deletions
diff --git a/remoting/client/chromoting_client.cc b/remoting/client/chromoting_client.cc
index f205d1e..aee6df4 100644
--- a/remoting/client/chromoting_client.cc
+++ b/remoting/client/chromoting_client.cc
@@ -52,6 +52,27 @@ void ChromotingClient::Start() {
}
}
+void ChromotingClient::StartSandboxed(scoped_refptr<XmppProxy> xmpp_proxy,
+ const std::string& your_jid,
+ const std::string& host_jid) {
+ // TODO(ajwong): Merge this with Start(), and just change behavior based on
+ // ClientConfig.
+ if (message_loop() != MessageLoop::current()) {
+ message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &ChromotingClient::StartSandboxed, xmpp_proxy,
+ your_jid, host_jid));
+ return;
+ }
+
+ connection_->ConnectSandboxed(xmpp_proxy, your_jid, host_jid, this, this,
+ this);
+
+ if (!view_->Initialize()) {
+ ClientDone();
+ }
+}
+
void ChromotingClient::Stop() {
if (message_loop() != MessageLoop::current()) {
message_loop()->PostTask(
diff --git a/remoting/client/chromoting_client.h b/remoting/client/chromoting_client.h
index b90dc41..83702db 100644
--- a/remoting/client/chromoting_client.h
+++ b/remoting/client/chromoting_client.h
@@ -16,6 +16,7 @@
#include "remoting/protocol/connection_to_host.h"
#include "remoting/protocol/input_stub.h"
#include "remoting/protocol/video_stub.h"
+#include "remoting/jingle_glue/xmpp_proxy.h"
class MessageLoop;
@@ -46,6 +47,9 @@ class ChromotingClient : public protocol::ConnectionToHost::HostEventCallback,
virtual ~ChromotingClient();
void Start();
+ void StartSandboxed(scoped_refptr<XmppProxy> xmpp_proxy,
+ const std::string& your_jid,
+ const std::string& host_jid);
void Stop();
void ClientDone();
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc
index 9c07782..e3ab6c4 100644
--- a/remoting/client/plugin/chromoting_instance.cc
+++ b/remoting/client/plugin/chromoting_instance.cc
@@ -27,6 +27,8 @@
#include "remoting/client/plugin/pepper_input_handler.h"
#include "remoting/client/plugin/pepper_view.h"
#include "remoting/client/plugin/pepper_view_proxy.h"
+#include "remoting/client/plugin/pepper_util.h"
+#include "remoting/client/plugin/pepper_xmpp_proxy.h"
#include "remoting/jingle_glue/jingle_thread.h"
#include "remoting/proto/auth.pb.h"
#include "remoting/protocol/connection_to_host.h"
@@ -44,7 +46,7 @@ const char* ChromotingInstance::kMimeType = "pepper-application/x-chromoting";
ChromotingInstance::ChromotingInstance(PP_Instance pp_instance)
: pp::Instance(pp_instance),
- pepper_main_loop_dont_post_to_me_(NULL) {
+ initialized_(false) {
}
ChromotingInstance::~ChromotingInstance() {
@@ -62,19 +64,9 @@ ChromotingInstance::~ChromotingInstance() {
bool ChromotingInstance::Init(uint32_t argc,
const char* argn[],
const char* argv[]) {
- CHECK(pepper_main_loop_dont_post_to_me_ == NULL);
-
- // Record the current thread. This function should only be invoked by the
- // plugin thread, so we capture the current message loop and assume it is
- // indeed the plugin thread.
- //
- // We're abusing the pepper API slightly here. We know we're running as an
- // internal plugin, and thus we are on the pepper main thread that uses a
- // message loop.
- //
- // TODO(ajwong): See if there is a method for querying what thread we're on
- // from inside the pepper API.
- pepper_main_loop_dont_post_to_me_ = MessageLoop::current();
+ CHECK(!initialized_);
+ initialized_ = true;
+
VLOG(1) << "Started ChromotingInstance::Init";
// Start all the threads.
@@ -133,6 +125,37 @@ void ChromotingInstance::Connect(const ClientConfig& config) {
QUALITY_UNKNOWN);
}
+void ChromotingInstance::ConnectSandboxed(const std::string& your_jid,
+ const std::string& host_jid) {
+ // TODO(ajwong): your_jid and host_jid should be moved into ClientConfig. In
+ // fact, this whole function should go away, and Connect() should just look at
+ // ClientConfig.
+ DCHECK(CurrentlyOnPluginThread());
+
+ LogDebugInfo("Attempting sandboxed connection");
+
+ // Setup the XMPP Proxy.
+ ChromotingScriptableObject* scriptable_object = GetScriptableObject();
+ scoped_refptr<PepperXmppProxy> xmpp_proxy =
+ new PepperXmppProxy(scriptable_object->AsWeakPtr(),
+ context_.jingle_thread()->message_loop());
+ scriptable_object->AttachXmppProxy(xmpp_proxy);
+
+ client_.reset(new ChromotingClient(ClientConfig(),
+ &context_,
+ host_connection_.get(),
+ view_proxy_,
+ rectangle_decoder_.get(),
+ input_handler_.get(),
+ NULL));
+
+ // Kick off the connection.
+ client_->StartSandboxed(xmpp_proxy, your_jid, host_jid);
+
+ GetScriptableObject()->SetConnectionInfo(STATUS_INITIALIZING,
+ QUALITY_UNKNOWN);
+}
+
void ChromotingInstance::Disconnect() {
DCHECK(CurrentlyOnPluginThread());
@@ -158,10 +181,6 @@ void ChromotingInstance::ViewChanged(const pp::Rect& position,
view_->Paint();
}
-bool ChromotingInstance::CurrentlyOnPluginThread() const {
- return pepper_main_loop_dont_post_to_me_ == MessageLoop::current();
-}
-
bool ChromotingInstance::HandleInputEvent(const PP_InputEvent& event) {
DCHECK(CurrentlyOnPluginThread());
diff --git a/remoting/client/plugin/chromoting_instance.h b/remoting/client/plugin/chromoting_instance.h
index 554760b..f552777 100644
--- a/remoting/client/plugin/chromoting_instance.h
+++ b/remoting/client/plugin/chromoting_instance.h
@@ -62,13 +62,13 @@ class ChromotingInstance : public pp::Instance {
virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
virtual void Connect(const ClientConfig& config);
+ virtual void ConnectSandboxed(const std::string& your_jid,
+ const std::string& host_jid);
virtual bool HandleInputEvent(const PP_InputEvent& event);
virtual void Disconnect();
virtual pp::Var GetInstanceObject();
virtual void ViewChanged(const pp::Rect& position, const pp::Rect& clip);
- virtual bool CurrentlyOnPluginThread() const;
-
// Convenience wrapper to get the ChromotingScriptableObject.
ChromotingScriptableObject* GetScriptableObject();
@@ -81,19 +81,13 @@ class ChromotingInstance : public pp::Instance {
private:
FRIEND_TEST_ALL_PREFIXES(ChromotingInstanceTest, TestCaseSetup);
- // Since we're an internal plugin, we can just grab the message loop during
- // init to figure out which thread we're on. This should only be used to
- // sanity check which thread we're executing on. Do not post task here!
- // Instead, use PPB_Core:CallOnMainThread() in the pepper api.
- //
- // TODO(ajwong): Think if there is a better way to safeguard this.
- MessageLoop* pepper_main_loop_dont_post_to_me_;
+ bool initialized_;
ClientContext context_;
scoped_ptr<protocol::ConnectionToHost> host_connection_;
scoped_ptr<PepperView> view_;
- // PepperViewProxy is refcounted and used to interface between shromoting
+ // PepperViewProxy is refcounted and used to interface between chromoting
// objects and PepperView and perform thread switching. It wraps around
// |view_| and receives method calls on chromoting threads. These method
// calls are then delegates on the pepper thread. During destruction of
@@ -105,6 +99,12 @@ class ChromotingInstance : public pp::Instance {
scoped_ptr<InputHandler> input_handler_;
scoped_ptr<ChromotingClient> client_;
+ // XmppProxy is a refcounted interface used to perform thread-switching and
+ // detaching between objects whose lifetimes are controlled by pepper, and
+ // jingle_glue objects. This is used when if we start a sandboxed jingle
+ // connection.
+ scoped_refptr<PepperXmppProxy> xmpp_proxy_;
+
// JavaScript interface to control this instance.
// This wraps a ChromotingScriptableObject in a pp::Var.
pp::Var instance_object_;
diff --git a/remoting/client/plugin/chromoting_scriptable_object.cc b/remoting/client/plugin/chromoting_scriptable_object.cc
index d1b7eec..8d0e338 100644
--- a/remoting/client/plugin/chromoting_scriptable_object.cc
+++ b/remoting/client/plugin/chromoting_scriptable_object.cc
@@ -15,15 +15,20 @@ using pp::Var;
namespace remoting {
+namespace {
+
const char kConnectionInfoUpdate[] = "connectionInfoUpdate";
const char kDebugInfo[] = "debugInfo";
const char kDesktopHeight[] = "desktopHeight";
const char kDesktopWidth[] = "desktopWidth";
const char kDesktopSizeUpdate[] = "desktopSizeUpdate";
const char kLoginChallenge[] = "loginChallenge";
+const char kSendIq[] = "sendIq";
const char kQualityAttribute[] = "quality";
const char kStatusAttribute[] = "status";
+} // namespace
+
ChromotingScriptableObject::ChromotingScriptableObject(
ChromotingInstance* instance)
: instance_(instance) {
@@ -60,12 +65,16 @@ void ChromotingScriptableObject::Init() {
AddAttribute(kDebugInfo, Var());
AddAttribute(kDesktopSizeUpdate, Var());
AddAttribute(kLoginChallenge, Var());
+ AddAttribute(kSendIq, Var());
AddAttribute(kDesktopWidth, Var(0));
AddAttribute(kDesktopHeight, Var(0));
AddMethod("connect", &ChromotingScriptableObject::DoConnect);
+ AddMethod("connectSandboxed",
+ &ChromotingScriptableObject::DoConnectSandboxed);
AddMethod("disconnect", &ChromotingScriptableObject::DoDisconnect);
AddMethod("submitLoginInfo", &ChromotingScriptableObject::DoSubmitLogin);
+ AddMethod("onIq", &ChromotingScriptableObject::DoOnIq);
}
bool ChromotingScriptableObject::HasProperty(const Var& name, Var* exception) {
@@ -146,6 +155,7 @@ void ChromotingScriptableObject::SetProperty(const Var& name,
property_name != kDebugInfo &&
property_name != kDesktopSizeUpdate &&
property_name != kLoginChallenge &&
+ property_name != kSendIq &&
property_name != kDesktopWidth &&
property_name != kDesktopHeight) {
*exception =
@@ -236,7 +246,7 @@ void ChromotingScriptableObject::SignalConnectionInfoChange() {
// Var() means call the object directly as a function rather than calling
// a method in the object.
- cb.Call(Var(), 0, NULL, &exception);
+ cb.Call(Var(), &exception);
if (!exception.is_undefined())
LogDebugInfo(
@@ -266,23 +276,26 @@ void ChromotingScriptableObject::SignalLoginChallenge() {
// Var() means call the object directly as a function rather than calling
// a method in the object.
- cb.Call(Var(), 0, NULL, &exception);
+ cb.Call(Var(), &exception);
if (!exception.is_undefined())
LogDebugInfo("Exception when invoking loginChallenge JS callback.");
}
-void ChromotingScriptableObject::AttachXmppProxy(XmppProxy* xmpp_proxy) {
+void ChromotingScriptableObject::AttachXmppProxy(PepperXmppProxy* xmpp_proxy) {
xmpp_proxy_ = xmpp_proxy;
}
-void ChromotingScriptableObject::SendIq(const std::string& iq_request_xml) {
- // TODO(ajwong): Do something smart here.
- NOTIMPLEMENTED();
-}
+void ChromotingScriptableObject::SendIq(const std::string& message_xml) {
+ Var exception;
+ Var cb = GetProperty(Var(kSendIq), &exception);
-void ChromotingScriptableObject::ReceiveIq(const std::string& iq_response_xml) {
- xmpp_proxy_->ReceiveIq(iq_response_xml);
+ // Var() means call the object directly as a function rather than calling
+ // a method in the object.
+ cb.Call(Var(), Var(message_xml), &exception);
+
+ if (!exception.is_undefined())
+ LogDebugInfo("Exception when invoking loginChallenge JS callback.");
}
Var ChromotingScriptableObject::DoConnect(const std::vector<Var>& args,
@@ -318,6 +331,33 @@ Var ChromotingScriptableObject::DoConnect(const std::vector<Var>& args,
return Var();
}
+Var ChromotingScriptableObject::DoConnectSandboxed(
+ const std::vector<Var>& args, Var* exception) {
+ if (args.size() != 2) {
+ *exception = Var("Usage: connectSandboxed(your_jid, host_jid)");
+ return Var();
+ }
+
+ std::string your_jid;
+ if (!args[0].is_string()) {
+ *exception = Var("your_jid must be a string.");
+ return Var();
+ }
+ your_jid = args[0].AsString();
+
+ std::string host_jid;
+ if (!args[1].is_string()) {
+ *exception = Var("host_jid must be a string.");
+ return Var();
+ }
+ host_jid = args[1].AsString();
+
+ VLOG(1) << "your_jid: " << your_jid << " and host_jid: " << host_jid;
+ instance_->ConnectSandboxed(your_jid, host_jid);
+
+ return Var();
+}
+
Var ChromotingScriptableObject::DoDisconnect(const std::vector<Var>& args,
Var* exception) {
LogDebugInfo("Disconnecting from host.");
@@ -350,4 +390,21 @@ Var ChromotingScriptableObject::DoSubmitLogin(const std::vector<Var>& args,
return Var();
}
+Var ChromotingScriptableObject::DoOnIq(const std::vector<Var>& args,
+ Var* exception) {
+ if (args.size() != 1) {
+ *exception = Var("Usage: onIq(response_xml)");
+ return Var();
+ }
+
+ if (!args[0].is_string()) {
+ *exception = Var("response_xml must be a string.");
+ return Var();
+ }
+
+ xmpp_proxy_->OnIq(args[0].AsString());
+
+ return Var();
+}
+
} // namespace remoting
diff --git a/remoting/client/plugin/chromoting_scriptable_object.h b/remoting/client/plugin/chromoting_scriptable_object.h
index 9ebc8fa..fcaee61 100644
--- a/remoting/client/plugin/chromoting_scriptable_object.h
+++ b/remoting/client/plugin/chromoting_scriptable_object.h
@@ -11,9 +11,6 @@
// readonly attribute int desktopWidth;
// readonly attribute int desktopHeight;
//
-// // Debug info.
-// readonly attribute string debugInfo;
-//
// // Connection status.
// readonly attribute unsigned short status;
// // Constants for connection status.
@@ -37,7 +34,16 @@
//
// // JS callback function to call when there is new debug info to display
// // in the client UI.
-// attribute Function debugInfoUpdate;
+// attribute Function debugInfo;
+//
+// // JS callback function to send an XMPP IQ stanza for performing the
+// // signaling in a jingle connection. The callback function should be
+// // of type void(string request_xml).
+// attribute Function sendIq;
+//
+// // Method for receiving an XMPP IQ stanza in response to a previous
+// // sendIq() invocation. Other packets will be silently dropped.
+// void onIq(string response_xml);
//
// // This function is called when login information for the host machine is
// // needed.
@@ -50,8 +56,13 @@
// // later case |connection_status| is changed to STATUS_FAILED.
// attribute Function loginChallenge;
//
-// // Methods on the object.
+// // Methods for establishing a Chromoting connection.
+// //
+// // Either use connect() or connectSandboxed(), not both. If using
+// // connectSandboxed(), sendIq must be set, and responses to calls on
+// // sendIq must be piped back into onIq().
// void connect(string username, string host_jid, string auth_token);
+// void connectSandboxed();
// void disconnect();
//
// // Method for submitting login information.
@@ -73,9 +84,7 @@
namespace remoting {
class ChromotingInstance;
-class XmppProxy;
-
-extern const char kStatusAttribute[];
+class PepperXmppProxy;
enum ConnectionStatus {
STATUS_UNKNOWN = 0,
@@ -86,8 +95,6 @@ enum ConnectionStatus {
STATUS_FAILED,
};
-extern const char kQualityAttribute[];
-
enum ConnectionQuality {
QUALITY_UNKNOWN = 0,
QUALITY_GOOD,
@@ -123,11 +130,13 @@ class ChromotingScriptableObject
// This should be called to signal JS code to provide login information.
void SignalLoginChallenge();
- // Handles a Request/Response for a Javascript IQ stanza used to initiate a
- // jingle connection.
- void AttachXmppProxy(XmppProxy* xmpp_proxy);
- void SendIq(const std::string& iq_request_xml);
- void ReceiveIq(const std::string& iq_response_xml);
+ // Attaches the XmppProxy used for issuing and receivng IQ stanzas for
+ // initiaing a jingle connection from within the sandbox.
+ void AttachXmppProxy(PepperXmppProxy* xmpp_proxy);
+
+ // Sends an IQ stanza, serialized as an xml string, into Javascript for
+ // handling.
+ void SendIq(const std::string& request_xml);
private:
typedef std::map<std::string, int> PropertyNameMap;
@@ -164,14 +173,20 @@ class ChromotingScriptableObject
void SignalDesktopSizeChange();
pp::Var DoConnect(const std::vector<pp::Var>& args, pp::Var* exception);
+ pp::Var DoConnectSandboxed(const std::vector<pp::Var>& args,
+ pp::Var* exception);
pp::Var DoDisconnect(const std::vector<pp::Var>& args, pp::Var* exception);
// This method is called by JS to provide login information.
pp::Var DoSubmitLogin(const std::vector<pp::Var>& args, pp::Var* exception);
+ // This method is caleld by Javascript to provide responses to sendIq()
+ // requests when establishing a sandboxed Chromoting connection.
+ pp::Var DoOnIq(const std::vector<pp::Var>& args, pp::Var* exception);
+
PropertyNameMap property_names_;
std::vector<PropertyDescriptor> properties_;
- scoped_refptr<XmppProxy> xmpp_proxy_;
+ scoped_refptr<PepperXmppProxy> xmpp_proxy_;
ChromotingInstance* instance_;
};
diff --git a/remoting/client/plugin/pepper_util.cc b/remoting/client/plugin/pepper_util.cc
index ff0c0f5..4a01c2d 100644
--- a/remoting/client/plugin/pepper_util.cc
+++ b/remoting/client/plugin/pepper_util.cc
@@ -28,4 +28,8 @@ void RunTaskOnPluginThread(Task* task) {
);
}
+bool CurrentlyOnPluginThread() {
+ return pp::Module::Get()->core()->IsMainThread();
+}
+
} // namespace remoting
diff --git a/remoting/client/plugin/pepper_util.h b/remoting/client/plugin/pepper_util.h
index 1201689..6014824 100644
--- a/remoting/client/plugin/pepper_util.h
+++ b/remoting/client/plugin/pepper_util.h
@@ -27,6 +27,9 @@ pp::CompletionCallback TaskToCompletionCallback(Task* task);
// |task|.
void RunTaskOnPluginThread(Task* task);
+// Returns true if the current thread is the plugin main thread.
+bool CurrentlyOnPluginThread();
+
} // namespace remoting
#endif // REMOTING_CLIENT_PLUGIN_PLUGIN_UTIL_H_
diff --git a/remoting/client/plugin/pepper_view.cc b/remoting/client/plugin/pepper_view.cc
index 6bc4508..510bde6 100644
--- a/remoting/client/plugin/pepper_view.cc
+++ b/remoting/client/plugin/pepper_view.cc
@@ -35,13 +35,13 @@ bool PepperView::Initialize() {
}
void PepperView::TearDown() {
- DCHECK(instance_->CurrentlyOnPluginThread());
+ DCHECK(CurrentlyOnPluginThread());
task_factory_.RevokeAll();
}
void PepperView::Paint() {
- DCHECK(instance_->CurrentlyOnPluginThread());
+ DCHECK(CurrentlyOnPluginThread());
TraceContext::tracer()->PrintString("Start Paint.");
// TODO(ajwong): We're assuming the native format is BGRA_PREMUL below. This
@@ -77,7 +77,7 @@ void PepperView::Paint() {
}
void PepperView::PaintFrame(media::VideoFrame* frame, UpdatedRects* rects) {
- DCHECK(instance_->CurrentlyOnPluginThread());
+ DCHECK(CurrentlyOnPluginThread());
TraceContext::tracer()->PrintString("Start Paint Frame.");
@@ -124,20 +124,20 @@ void PepperView::PaintFrame(media::VideoFrame* frame, UpdatedRects* rects) {
}
void PepperView::SetSolidFill(uint32 color) {
- DCHECK(instance_->CurrentlyOnPluginThread());
+ DCHECK(CurrentlyOnPluginThread());
is_static_fill_ = true;
static_fill_color_ = color;
}
void PepperView::UnsetSolidFill() {
- DCHECK(instance_->CurrentlyOnPluginThread());
+ DCHECK(CurrentlyOnPluginThread());
is_static_fill_ = false;
}
void PepperView::SetConnectionState(ConnectionState state) {
- DCHECK(instance_->CurrentlyOnPluginThread());
+ DCHECK(CurrentlyOnPluginThread());
// TODO(hclam): Re-consider the way we communicate with Javascript.
ChromotingScriptableObject* scriptable_obj = instance_->GetScriptableObject();
@@ -165,7 +165,7 @@ void PepperView::SetConnectionState(ConnectionState state) {
}
void PepperView::UpdateLoginStatus(bool success, const std::string& info) {
- DCHECK(instance_->CurrentlyOnPluginThread());
+ DCHECK(CurrentlyOnPluginThread());
// TODO(hclam): Re-consider the way we communicate with Javascript.
ChromotingScriptableObject* scriptable_obj = instance_->GetScriptableObject();
@@ -176,7 +176,7 @@ void PepperView::UpdateLoginStatus(bool success, const std::string& info) {
}
void PepperView::SetViewport(int x, int y, int width, int height) {
- DCHECK(instance_->CurrentlyOnPluginThread());
+ DCHECK(CurrentlyOnPluginThread());
if ((width == viewport_width_) && (height == viewport_height_))
return;
@@ -202,7 +202,7 @@ void PepperView::AllocateFrame(media::VideoFrame::Format format,
base::TimeDelta duration,
scoped_refptr<media::VideoFrame>* frame_out,
Task* done) {
- DCHECK(instance_->CurrentlyOnPluginThread());
+ DCHECK(CurrentlyOnPluginThread());
// TODO(ajwong): Implement this to be backed by an pp::ImageData rather than
// generic memory.
@@ -218,7 +218,7 @@ void PepperView::AllocateFrame(media::VideoFrame::Format format,
}
void PepperView::ReleaseFrame(media::VideoFrame* frame) {
- DCHECK(instance_->CurrentlyOnPluginThread());
+ DCHECK(CurrentlyOnPluginThread());
if (frame) {
LOG(WARNING) << "Frame released.";
@@ -229,7 +229,7 @@ void PepperView::ReleaseFrame(media::VideoFrame* frame) {
void PepperView::OnPartialFrameOutput(media::VideoFrame* frame,
UpdatedRects* rects,
Task* done) {
- DCHECK(instance_->CurrentlyOnPluginThread());
+ DCHECK(CurrentlyOnPluginThread());
TraceContext::tracer()->PrintString("Calling PaintFrame");
// TODO(ajwong): Clean up this API to be async so we don't need to use a
@@ -240,7 +240,7 @@ void PepperView::OnPartialFrameOutput(media::VideoFrame* frame,
}
void PepperView::OnPaintDone() {
- DCHECK(instance_->CurrentlyOnPluginThread());
+ DCHECK(CurrentlyOnPluginThread());
// TODO(ajwong):Probably should set some variable to allow repaints to
// actually paint.
diff --git a/remoting/client/plugin/pepper_view_proxy.cc b/remoting/client/plugin/pepper_view_proxy.cc
index ce675f2..e01ee9f 100644
--- a/remoting/client/plugin/pepper_view_proxy.cc
+++ b/remoting/client/plugin/pepper_view_proxy.cc
@@ -28,7 +28,7 @@ bool PepperViewProxy::Initialize() {
}
void PepperViewProxy::TearDown() {
- if (instance_ && !instance_->CurrentlyOnPluginThread()) {
+ if (instance_ && !CurrentlyOnPluginThread()) {
RunTaskOnPluginThread(NewTracedMethod(this, &PepperViewProxy::TearDown));
return;
}
@@ -38,7 +38,7 @@ void PepperViewProxy::TearDown() {
}
void PepperViewProxy::Paint() {
- if (instance_ && !instance_->CurrentlyOnPluginThread()) {
+ if (instance_ && !CurrentlyOnPluginThread()) {
RunTaskOnPluginThread(NewTracedMethod(this, &PepperViewProxy::Paint));
return;
}
@@ -48,7 +48,7 @@ void PepperViewProxy::Paint() {
}
void PepperViewProxy::SetSolidFill(uint32 color) {
- if (instance_ && !instance_->CurrentlyOnPluginThread()) {
+ if (instance_ && !CurrentlyOnPluginThread()) {
RunTaskOnPluginThread(
NewTracedMethod(this, &PepperViewProxy::SetSolidFill, color));
return;
@@ -59,7 +59,7 @@ void PepperViewProxy::SetSolidFill(uint32 color) {
}
void PepperViewProxy::UnsetSolidFill() {
- if (instance_ && !instance_->CurrentlyOnPluginThread()) {
+ if (instance_ && !CurrentlyOnPluginThread()) {
RunTaskOnPluginThread(
NewTracedMethod(this, &PepperViewProxy::UnsetSolidFill));
return;
@@ -70,7 +70,7 @@ void PepperViewProxy::UnsetSolidFill() {
}
void PepperViewProxy::SetConnectionState(ConnectionState state) {
- if (instance_ && !instance_->CurrentlyOnPluginThread()) {
+ if (instance_ && !CurrentlyOnPluginThread()) {
RunTaskOnPluginThread(
NewRunnableMethod(this, &PepperViewProxy::SetConnectionState, state));
return;
@@ -81,7 +81,7 @@ void PepperViewProxy::SetConnectionState(ConnectionState state) {
}
void PepperViewProxy::UpdateLoginStatus(bool success, const std::string& info) {
- if (instance_ && !instance_->CurrentlyOnPluginThread()) {
+ if (instance_ && !CurrentlyOnPluginThread()) {
RunTaskOnPluginThread(NewTracedMethod(this,
&PepperViewProxy::UpdateLoginStatus,
success, info));
@@ -93,7 +93,7 @@ void PepperViewProxy::UpdateLoginStatus(bool success, const std::string& info) {
}
void PepperViewProxy::SetViewport(int x, int y, int width, int height) {
- if (instance_ && !instance_->CurrentlyOnPluginThread()) {
+ if (instance_ && !CurrentlyOnPluginThread()) {
RunTaskOnPluginThread(NewTracedMethod(this, &PepperViewProxy::SetViewport,
x, y, width, height));
return;
@@ -111,7 +111,7 @@ void PepperViewProxy::AllocateFrame(
base::TimeDelta duration,
scoped_refptr<media::VideoFrame>* frame_out,
Task* done) {
- if (instance_ && !instance_->CurrentlyOnPluginThread()) {
+ if (instance_ && !CurrentlyOnPluginThread()) {
RunTaskOnPluginThread(
NewTracedMethod(this, &PepperViewProxy::AllocateFrame, format, width,
height, timestamp, duration, frame_out, done));
@@ -125,7 +125,7 @@ void PepperViewProxy::AllocateFrame(
}
void PepperViewProxy::ReleaseFrame(media::VideoFrame* frame) {
- if (instance_ && !instance_->CurrentlyOnPluginThread()) {
+ if (instance_ && !CurrentlyOnPluginThread()) {
RunTaskOnPluginThread(
NewTracedMethod(this, &PepperViewProxy::ReleaseFrame,
make_scoped_refptr(frame)));
@@ -139,7 +139,7 @@ void PepperViewProxy::ReleaseFrame(media::VideoFrame* frame) {
void PepperViewProxy::OnPartialFrameOutput(media::VideoFrame* frame,
UpdatedRects* rects,
Task* done) {
- if (instance_ && !instance_->CurrentlyOnPluginThread()) {
+ if (instance_ && !CurrentlyOnPluginThread()) {
RunTaskOnPluginThread(
NewTracedMethod(this, &PepperViewProxy::OnPartialFrameOutput,
make_scoped_refptr(frame), rects, done));
@@ -151,7 +151,7 @@ void PepperViewProxy::OnPartialFrameOutput(media::VideoFrame* frame,
}
void PepperViewProxy::Detach() {
- DCHECK(instance_->CurrentlyOnPluginThread());
+ DCHECK(CurrentlyOnPluginThread());
instance_ = NULL;
view_ = NULL;
}
diff --git a/remoting/client/plugin/pepper_xmpp_proxy.cc b/remoting/client/plugin/pepper_xmpp_proxy.cc
index 7e4c26c..cfdb842 100644
--- a/remoting/client/plugin/pepper_xmpp_proxy.cc
+++ b/remoting/client/plugin/pepper_xmpp_proxy.cc
@@ -2,55 +2,58 @@
// 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/client/plugin/chromoting_scriptable_object.h"
+#include "remoting/client/plugin/pepper_util.h"
#include "remoting/client/plugin/pepper_xmpp_proxy.h"
namespace remoting {
-PepperXmppProxy::PepperXmppProxy(MessageLoop* jingle_message_loop,
- MessageLoop* pepper_message_loop)
- : jingle_message_loop_(jingle_message_loop),
- pepper_message_loop_(pepper_message_loop) {
+PepperXmppProxy::PepperXmppProxy(
+ base::WeakPtr<ChromotingScriptableObject> scriptable_object,
+ MessageLoop* callback_message_loop)
+ : scriptable_object_(scriptable_object),
+ callback_message_loop_(callback_message_loop) {
+ CHECK(CurrentlyOnPluginThread());
+}
+
+PepperXmppProxy::~PepperXmppProxy() {
}
-void PepperXmppProxy::AttachScriptableObject(
- ChromotingScriptableObject* scriptable_object,
- Task* done) {
- DCHECK_EQ(jingle_message_loop_, MessageLoop::Current());
- scriptable_object_ = scriptable_object;
- scriptable_object_->AttachXmppProxy(this);
+void PepperXmppProxy::AttachCallback(base::WeakPtr<ResponseCallback> callback) {
+ CHECK_EQ(callback_message_loop_, MessageLoop::current());
+ callback_ = callback;
}
-void PepperXmppProxy::AttachJavascriptIqRequest(
- JavascriptIqRequest* javascript_iq_request) {
- DCHECK_EQ(pepper_message_loop_, MessageLoop::Current());
- javascript_iq_request_ = javascript_iq_request;
+void PepperXmppProxy::DetachCallback() {
+ callback_.reset();
}
-void PepperXmppProxy::SendIq(const std::string& iq_request_xml) {
- if (MessageLoop::Current() != pepper_message_loop_) {
- pepper_message_loop_->PostTask(
- NewRunnableMethod(this,
- &PepperXmppProxy::SendIq,
- iq_request_xml));
+void PepperXmppProxy::SendIq(const std::string& request_xml) {
+ if (!CurrentlyOnPluginThread()) {
+ RunTaskOnPluginThread(NewRunnableMethod(this,
+ &PepperXmppProxy::SendIq,
+ request_xml));
return;
}
if (scriptable_object_) {
- scriptable_object_->SendIq(iq_request_xml, this);
+ scriptable_object_->SendIq(request_xml);
}
}
-void PepperXmppProxy::ReceiveIq(const std::string& iq_response_xml) {
- if (MessageLoop::Current() != jingle_message_loop_) {
- jingle_message_loop_->PostTask(
- NewRunnableMethod(this,
- &PepperXmppProxy::ReceiveIq,
- iq_response_xml));
+void PepperXmppProxy::OnIq(const std::string& response_xml) {
+ if (MessageLoop::current() != callback_message_loop_) {
+ callback_message_loop_->PostTask(
+ FROM_HERE,NewRunnableMethod(this,
+ &PepperXmppProxy::OnIq,
+ response_xml));
return;
}
- if (javascript_iq_request_) {
- javascript_iq_request_->handleIqResponse(iq_response_xml);
+ if (callback_) {
+ callback_->OnIq(response_xml);
}
}
diff --git a/remoting/client/plugin/pepper_xmpp_proxy.h b/remoting/client/plugin/pepper_xmpp_proxy.h
index c03bb30..4d4d6f3 100644
--- a/remoting/client/plugin/pepper_xmpp_proxy.h
+++ b/remoting/client/plugin/pepper_xmpp_proxy.h
@@ -6,35 +6,42 @@
#define REMOTING_CLIENT_PLUGIN_PEPPER_XMPP_PROXY_H_
#include "base/weak_ptr.h"
-#include "remoting/jingle_glue/iq_request.h"
+#include "remoting/jingle_glue/xmpp_proxy.h"
namespace remoting {
+class ChromotingScriptableObject;
+
class PepperXmppProxy : public XmppProxy {
public:
- PepperXmppProxy(MessageLoop* jingle_message_loop,
- MessageLoop* pepper_message_loop);
-
- // Must be run on pepper thread.
- virtual void AttachScriptableObject(
- ChromotingScriptableObject* scriptable_object);
-
- // Must be run on jingle thread.
- virtual void AttachJavascriptIqRequest(
- JavascriptIqRequest* javascript_iq_request);
-
- virtual void SendIq(const std::string& iq_request_xml);
- virtual void ReceiveIq(const std::string& iq_response_xml);
+ PepperXmppProxy(
+ base::WeakPtr<ChromotingScriptableObject> scriptable_object,
+ MessageLoop* callback_message_loop);
+
+ // Registered the callback class with this object.
+ //
+ // - This method has subtle thread semantics! -
+ //
+ // It must be called on the callback thread itself. The weak pointer also
+ // must be constructed on the callback thread. That means, you cannot just
+ // create a WeakPtr on, say the pepper thread, and then pass execution of
+ // this function callback with the weak pointer bound as a parameter. That
+ // will fail because the WeakPtr will have been created on the wrong thread.
+ virtual void AttachCallback(base::WeakPtr<ResponseCallback> callback);
+ virtual void DetachCallback();
+
+ virtual void SendIq(const std::string& request_xml);
+ virtual void OnIq(const std::string& response_xml);
private:
~PepperXmppProxy();
- MessageLoop* jingle_message_loop_;
- MessageLoop* pepper_message_loop_;
-
base::WeakPtr<ChromotingScriptableObject> scriptable_object_;
- base::WeakPtr<JavascriptIqRequest> javascript_iq_request_;
- std::string iq_response_xml_;
+
+ MessageLoop* callback_message_loop_;
+
+ // Must only be access on callback_message_loop_.
+ base::WeakPtr<ResponseCallback> callback_;
DISALLOW_COPY_AND_ASSIGN(PepperXmppProxy);
};
diff --git a/remoting/jingle_glue/iq_request.cc b/remoting/jingle_glue/iq_request.cc
index 8a456f0..e434be5 100644
--- a/remoting/jingle_glue/iq_request.cc
+++ b/remoting/jingle_glue/iq_request.cc
@@ -7,6 +7,8 @@
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
+#include "base/string_number_conversions.h"
+#include "third_party/libjingle/source/talk/p2p/base/sessionmanager.h"
#include "third_party/libjingle/source/talk/xmpp/constants.h"
#include "third_party/libjingle/source/talk/xmpp/xmppclient.h"
@@ -48,7 +50,6 @@ void XmppIqRequest::SendIq(const std::string& type,
Unregister();
DCHECK_GT(type.length(), 0U);
- DCHECK_GT(addressee.length(), 0U);
scoped_ptr<buzz::XmlElement> stanza(MakeIqStanza(type, addressee, iq_body,
xmpp_client_->NextId()));
@@ -71,37 +72,258 @@ void XmppIqRequest::Unregister() {
}
void XmppIqRequest::IqResponse(buzz::XmppIqCookie cookie,
- const buzz::XmlElement* stanza) {
+ const buzz::XmlElement* stanza) {
if (callback_.get() != NULL) {
callback_->Run(stanza);
}
}
-JavascriptIqRequest::JavascriptIqRequest() {
+JavascriptIqRegistry::JavascriptIqRegistry()
+ : current_id_(0),
+ default_handler_(NULL) {
+}
+
+JavascriptIqRegistry::~JavascriptIqRegistry() {
+}
+
+void JavascriptIqRegistry::RemoveAllRequests(JavascriptIqRequest* request) {
+ IqRequestMap::iterator it = requests_.begin();
+ while (it != requests_.end()) {
+ IqRequestMap::iterator cur = it;
+ ++it;
+ if (cur->second == request) {
+ requests_.erase(cur);
+ }
+ }
+}
+
+void JavascriptIqRegistry::SetDefaultHandler(JavascriptIqRequest* new_handler) {
+ // Should only allow a new handler if |default_handler_| is NULL.
+ CHECK(default_handler_ == NULL || !new_handler);
+ default_handler_ = new_handler;
+}
+
+void JavascriptIqRegistry::OnIq(const std::string& response_xml) {
+ // TODO(ajwong): Can we cleanup this dispatch at all? The send is from
+ // JavascriptIqRequest but the return is in JavascriptIqRegistry.
+ scoped_ptr<buzz::XmlElement> stanza(buzz::XmlElement::ForStr(response_xml));
+
+ if (!stanza.get()) {
+ LOG(WARNING) << "Malformed XML received" << response_xml;
+ return;
+ }
+
+ LOG(ERROR) << "IQ Received: " << stanza->Str();
+ if (stanza->Name() != buzz::QN_IQ) {
+ LOG(WARNING) << "Received unexpected non-IQ packet" << stanza->Str();
+ return;
+ }
+
+ if (!stanza->HasAttr(buzz::QN_ID)) {
+ LOG(WARNING) << "IQ packet missing id" << stanza->Str();
+ return;
+ }
+
+ const std::string& id = stanza->Attr(buzz::QN_ID);
+
+ IqRequestMap::iterator it = requests_.find(id);
+ if (it == requests_.end()) {
+ if (!default_handler_) {
+ VLOG(1) << "Dropping IQ packet with no request id: " << stanza->Str();
+ } else {
+ if (default_handler_->callback_.get()) {
+ default_handler_->callback_->Run(stanza.get());
+ } else {
+ VLOG(1) << "default handler has no callback, so dropping: "
+ << stanza->Str();
+ }
+ }
+ } else {
+ // TODO(ajwong): We should look at the logic inside libjingle's
+ // XmppTask::MatchResponseIq() and make sure we're fully in sync.
+ // They check more fields and conditions than us.
+
+ // TODO(ajwong): This logic is weird. We add to the register in
+ // JavascriptIqRequest::SendIq(), but remove in
+ // JavascriptIqRegistry::OnIq(). We should try to keep the
+ // registration/deregistration in one spot.
+ if (it->second->callback_.get()) {
+ it->second->callback_->Run(stanza.get());
+ } else {
+ VLOG(1) << "No callback, so dropping: " << stanza->Str();
+ }
+ requests_.erase(it);
+ }
+}
+
+std::string JavascriptIqRegistry::RegisterRequest(
+ JavascriptIqRequest* request) {
+ ++current_id_;
+ std::string id_as_string = base::IntToString(current_id_);
+
+ requests_[id_as_string] = request;
+ return id_as_string;
+}
+
+JavascriptIqRequest::JavascriptIqRequest(JavascriptIqRegistry* registry,
+ scoped_refptr<XmppProxy> xmpp_proxy)
+ : xmpp_proxy_(xmpp_proxy),
+ registry_(registry),
+ is_default_handler_(false) {
}
JavascriptIqRequest::~JavascriptIqRequest() {
+ registry_->RemoveAllRequests(this);
+ if (is_default_handler_) {
+ registry_->SetDefaultHandler(NULL);
+ }
}
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"));
+ MakeIqStanza(type, addressee, iq_body,
+ registry_->RegisterRequest(this)));
+
+ xmpp_proxy_->SendIq(stanza->Str());
+}
+void JavascriptIqRequest::SendRawIq(buzz::XmlElement* stanza) {
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::BecomeDefaultHandler() {
+ is_default_handler_ = true;
+ registry_->SetDefaultHandler(this);
}
void JavascriptIqRequest::set_callback(ReplyCallback* callback) {
callback_.reset(callback);
}
+JingleInfoRequest::JingleInfoRequest(IqRequest* request)
+ : request_(request) {
+ request_->set_callback(NewCallback(this, &JingleInfoRequest::OnResponse));
+}
+
+JingleInfoRequest::~JingleInfoRequest() {
+}
+
+void JingleInfoRequest::Run(Task* done) {
+ done_cb_.reset(done);
+ request_->SendIq(buzz::STR_GET, buzz::STR_EMPTY,
+ new buzz::XmlElement(buzz::QN_JINGLE_INFO_QUERY, true));
+}
+
+void JingleInfoRequest::SetCallback(OnJingleInfoCallback* callback) {
+ on_jingle_info_cb_.reset(callback);
+}
+
+void JingleInfoRequest::DetachCallback() {
+ on_jingle_info_cb_.reset();
+}
+
+void JingleInfoRequest::OnResponse(const buzz::XmlElement* stanza) {
+ std::vector<std::string> relay_hosts;
+ std::vector<talk_base::SocketAddress> stun_hosts;
+ std::string relay_token;
+
+ const buzz::XmlElement* query =
+ stanza->FirstNamed(buzz::QN_JINGLE_INFO_QUERY);
+ if (query == NULL) {
+ LOG(WARNING) << "No Jingle info found in Jingle Info query response."
+ << stanza->Str();
+ return;
+ }
+
+ const buzz::XmlElement* stun = query->FirstNamed(buzz::QN_JINGLE_INFO_STUN);
+ if (stun) {
+ for (const buzz::XmlElement* server =
+ stun->FirstNamed(buzz::QN_JINGLE_INFO_SERVER);
+ server != NULL;
+ server = server->NextNamed(buzz::QN_JINGLE_INFO_SERVER)) {
+ std::string host = server->Attr(buzz::QN_JINGLE_INFO_HOST);
+ std::string port_str = server->Attr(buzz::QN_JINGLE_INFO_UDP);
+ if (host != buzz::STR_EMPTY && host != buzz::STR_EMPTY) {
+ int port;
+ if (!base::StringToInt(port_str, &port)) {
+ LOG(WARNING) << "Unable to parse port in stanza" << stanza->Str();
+ } else {
+ stun_hosts.push_back(talk_base::SocketAddress(host, port));
+ }
+ }
+ }
+ }
+
+ const buzz::XmlElement* relay = query->FirstNamed(buzz::QN_JINGLE_INFO_RELAY);
+ if (relay) {
+ relay_token = relay->TextNamed(buzz::QN_JINGLE_INFO_TOKEN);
+ for (const buzz::XmlElement* server =
+ relay->FirstNamed(buzz::QN_JINGLE_INFO_SERVER);
+ server != NULL;
+ server = server->NextNamed(buzz::QN_JINGLE_INFO_SERVER)) {
+ std::string host = server->Attr(buzz::QN_JINGLE_INFO_HOST);
+ if (host != buzz::STR_EMPTY) {
+ relay_hosts.push_back(host);
+ }
+ }
+ }
+
+ if (on_jingle_info_cb_.get()) {
+ on_jingle_info_cb_->Run(relay_token, relay_hosts, stun_hosts);
+ } else {
+ LOG(INFO) << "Iq reply parsed with no callback. Dropping" << stanza->Str();
+ }
+
+ DetachCallback();
+ done_cb_->Run();
+}
+
+SessionStartRequest::SessionStartRequest(
+ JavascriptIqRequest* request,
+ cricket::SessionManager* session_manager)
+ : request_(request),
+ session_manager_(session_manager) {
+ request_->set_callback(NewCallback(this, &SessionStartRequest::OnResponse));
+}
+
+SessionStartRequest::~SessionStartRequest() {
+}
+
+void SessionStartRequest::Run() {
+ session_manager_->SignalOutgoingMessage.connect(
+ this, &SessionStartRequest::OnOutgoingMessage);
+
+ // TODO(ajwong): Why are we connecting SessionManager to itself?
+ session_manager_->SignalRequestSignaling.connect(
+ session_manager_, &cricket::SessionManager::OnSignalingReady);
+ request_->BecomeDefaultHandler();
+}
+
+void SessionStartRequest::OnResponse(const buzz::XmlElement* response) {
+ // TODO(ajwong): Techncially, when SessionManager sends IQ packets, it
+ // actually expects a response in SessionSendTask(). However, if you look in
+ // SessionManager::OnIncomingResponse(), it does nothing with the response.
+ // Also, if no response is found, we are supposed to call
+ // SessionManager::OnFailedSend().
+ //
+ // However, for right now, we just ignore those, and only propogate
+ // messages outside of the request/reply framework to
+ // SessionManager::OnIncomingMessage.
+
+ if (session_manager_->IsSessionMessage(response)) {
+ session_manager_->OnIncomingMessage(response);
+ }
+}
+
+void SessionStartRequest::OnOutgoingMessage(
+ cricket::SessionManager* session_manager,
+ const buzz::XmlElement* stanza) {
+ // TODO(ajwong): Are we just supposed to not use |session_manager|?
+ DCHECK_EQ(session_manager, session_manager_);
+ scoped_ptr<buzz::XmlElement> stanza_copy(new buzz::XmlElement(*stanza));
+ request_->SendRawIq(stanza_copy.get());
+}
+
} // namespace remoting
diff --git a/remoting/jingle_glue/iq_request.h b/remoting/jingle_glue/iq_request.h
index 9017ea2..dcb142d 100644
--- a/remoting/jingle_glue/iq_request.h
+++ b/remoting/jingle_glue/iq_request.h
@@ -5,53 +5,39 @@
#ifndef REMOTING_JINGLE_GLUE_IQ_REQUEST_H_
#define REMOTING_JINGLE_GLUE_IQ_REQUEST_H_
+#include <map>
#include <string>
+#include <vector>
#include "base/callback.h"
#include "base/gtest_prod_util.h"
#include "base/weak_ptr.h"
+#include "remoting/jingle_glue/xmpp_proxy.h"
+#include "third_party/libjingle/source/talk/base/sigslot.h"
#include "third_party/libjingle/source/talk/xmpp/xmppengine.h"
class MessageLoop;
+class Task;
namespace buzz {
class XmppClient;
} // namespace buzz
-namespace remoting {
-
-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;
+namespace cricket {
+class SessionManager;
+} // namespace cricket
- // Must be run on jingle thread.
- virtual void AttachJavascriptIqRequest(
- JavascriptIqRequest* javascript_iq_request) = 0;
+namespace talk_base {
+class SocketAddress;
+} // namespace talk_base
- 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);
-};
+namespace remoting {
// 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,
// after that it forwards incoming reply stanza to the callback set with
-// 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.
+// set_callback(). If each call to SendIq() will yield one invocation of the
+// callback with the response.
class IqRequest {
public:
typedef Callback1<const buzz::XmlElement*>::Type ReplyCallback;
@@ -81,24 +67,83 @@ class IqRequest {
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> {
+class JavascriptIqRequest;
+
+class JavascriptIqRegistry : public XmppProxy::ResponseCallback {
public:
- JavascriptIqRequest();
+ JavascriptIqRegistry();
+ virtual ~JavascriptIqRegistry();
+
+ // Dispatches the response to the IqRequest callback immediately.
+ //
+ // Does not take ownership of stanza.
+ void DispatchResponse(buzz::XmlElement* stanza);
+
+ // Registers |request|, returning the request ID used.
+ std::string RegisterRequest(JavascriptIqRequest* request);
+
+ // Removes all entries in the registry that refer to |request|. Useful when
+ // |request| is about to be destructed.
+ void RemoveAllRequests(JavascriptIqRequest* request);
+
+ void SetDefaultHandler(JavascriptIqRequest* default_request);
+
+ private:
+ typedef std::map<std::string, JavascriptIqRequest*> IqRequestMap;
+
+ // XmppProxy::ResponseCallback interface.
+ virtual void OnIq(const std::string& response_xml);
+
+ IqRequestMap requests_;
+ int current_id_;
+ JavascriptIqRequest* default_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(JavascriptIqRegistry);
+};
+
+// This call must only be used on the thread it was created on.
+class JavascriptIqRequest : public IqRequest {
+ public:
+ JavascriptIqRequest(JavascriptIqRegistry* registry,
+ scoped_refptr<XmppProxy> xmpp_proxy);
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);
+ // Similar to SendIq(), but has 3 major differences:
+ //
+ // (1) It does absoluately no error checking. Caller is responsible for
+ // validity.
+ // (2) It doesn't add an Iq envelope. Caller is again responsible.
+ // (3) BecomeDefaultHandler() must have been called.
+ //
+ // TODO(ajwong): We need to rationalize the semantics of these two APIs.
+ // SendRawIq() is a hack for SessionStartRequest which uses a different memory
+ // management convention.
+ void SendRawIq(buzz::XmlElement* stanza);
+
+ // This function is a hack to support SessionStartRequest. It registers the
+ // current JavascriptIqRequest instance to be the single passthrough filter
+ // for the associated JavascriptIqRegistry. What this means is that any IQ
+ // packet that does not match a previous respone packet will be funneled
+ // through to this JavascriptIqRegistry instance (basically a default
+ // handler). It also means that the registry will not be tracking any of the
+ // packets sent from this JavascriptIqRegistry instance.
+ //
+ // TODO(ajwong): We need to take a high-level look at IqRequest to understand
+ // how to make this API cleaner.
+ virtual void BecomeDefaultHandler();
virtual void set_callback(ReplyCallback* callback);
private:
+ friend class JavascriptIqRegistry;
+
scoped_ptr<ReplyCallback> callback_;
scoped_refptr<XmppProxy> xmpp_proxy_;
+ JavascriptIqRegistry* registry_;
+ bool is_default_handler_;
FRIEND_TEST_ALL_PREFIXES(IqRequestTest, MakeIqStanza);
};
@@ -131,6 +176,78 @@ class XmppIqRequest : public IqRequest, private buzz::XmppIqHandler {
scoped_ptr<ReplyCallback> callback_;
};
+// JingleInfoRequest handles making an IQ request to the Google talk network for
+// discovering stun/relay information for use in establishing a Jingle
+// connection.
+//
+// Clients should instantiate this class, and set a callback to receive the
+// configuration information. The query will be made when Run() is called. The
+// query is finisehd when the |done| task given to Run() is invokved.
+//
+// This class is not threadsafe and should be used on the same thread it is
+// created on.
+//
+// TODO(ajwong): Move to another file.
+// TODO(ajwong): Add support for a timeout.
+class JingleInfoRequest {
+ public:
+ // Callback to receive the Jingle configuration settings. The argumetns are
+ // passed by pointer so the receive may call swap on them. The receiver does
+ // NOT own the arguments, which are guaranteed only to be alive for the
+ // duration of the callback.
+ typedef Callback3<const std::string&, const std::vector<std::string>&,
+ const std::vector<talk_base::SocketAddress>&>::Type
+ OnJingleInfoCallback;
+
+ explicit JingleInfoRequest(IqRequest* request);
+ ~JingleInfoRequest();
+
+ void Run(Task* done);
+ void SetCallback(OnJingleInfoCallback* callback);
+ void DetachCallback();
+
+ private:
+ void OnResponse(const buzz::XmlElement* stanza);
+
+ scoped_ptr<IqRequest> request_;
+ scoped_ptr<OnJingleInfoCallback> on_jingle_info_cb_;
+ scoped_ptr<Task> done_cb_;
+
+ DISALLOW_COPY_AND_ASSIGN(JingleInfoRequest);
+};
+
+// This class handles proxying the Jingle establishment messages between the
+// client and the server when proxying XMPP through Javascript.
+//
+// The |request| object is used to send and receive IQ stanzas from the XMPP
+// network. The |session_manager| controls sending and receiving of stanzas
+// after Run() is invoked.
+//
+// This class is not threadsafe, and should only be used on the thread it is
+// created on.
+//
+// TODO(ajwong): Move into its own file, and rename to something better since
+// this is not actually a Request. Maybe SessionEstablishmentConnector.
+class SessionStartRequest : public sigslot::has_slots<> {
+ public:
+ SessionStartRequest(JavascriptIqRequest* request,
+ cricket::SessionManager* session_manager);
+ ~SessionStartRequest();
+
+ void Run();
+
+ private:
+ void OnResponse(const buzz::XmlElement* stanza);
+
+ void OnOutgoingMessage(cricket::SessionManager* manager,
+ const buzz::XmlElement* stanza);
+
+ scoped_ptr<JavascriptIqRequest> request_;
+ cricket::SessionManager* session_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(SessionStartRequest);
+};
+
} // namespace remoting
#endif // REMOTING_JINGLE_GLUE_IQ_REQUEST_H_
diff --git a/remoting/jingle_glue/jingle_client.cc b/remoting/jingle_glue/jingle_client.cc
index 3f89340..764497c 100644
--- a/remoting/jingle_glue/jingle_client.cc
+++ b/remoting/jingle_glue/jingle_client.cc
@@ -6,10 +6,10 @@
#include "base/logging.h"
#include "base/message_loop.h"
+#include "base/string_util.h"
#include "jingle/notifier/communicator/gaia_token_pre_xmpp_auth.h"
#include "remoting/jingle_glue/http_port_allocator.h"
#include "remoting/jingle_glue/iq_request.h"
-#include "remoting/jingle_glue/jingle_info_task.h"
#include "remoting/jingle_glue/jingle_thread.h"
#include "remoting/jingle_glue/xmpp_socket_adapter.h"
#include "third_party/libjingle/source/talk/base/asyncsocket.h"
@@ -37,8 +37,7 @@ XmppSignalStrategy::XmppSignalStrategy(JingleThread* jingle_thread,
auth_token_(auth_token),
auth_token_service_(auth_token_service),
xmpp_client_(NULL),
- observer_(NULL),
- port_allocator_(NULL) {
+ observer_(NULL) {
}
XmppSignalStrategy::~XmppSignalStrategy() {
@@ -67,20 +66,6 @@ void XmppSignalStrategy::Init(StatusObserver* observer) {
xmpp_client_->Start();
}
-void XmppSignalStrategy::ConfigureAllocator(
- cricket::HttpPortAllocator* port_allocator, Task* done) {
- // TODO(ajwong): There are 2 races on destruction here. First, port_allocator
- // by be destroyed before the OnJingleInfo is run. Second,
- // XmppSignalStrategy itself may be destroyed. Fix later.
- port_allocator_ = port_allocator;
- allocator_config_cb_.reset(done);
-
- JingleInfoTask* jit = new JingleInfoTask(xmpp_client_);
- jit->SignalJingleInfo.connect(this, &XmppSignalStrategy::OnJingleInfo);
- jit->Start();
- jit->RefreshJingleInfoNow();
-}
-
void XmppSignalStrategy::StartSession(
cricket::SessionManager* session_manager) {
cricket::SessionManagerTask* receiver =
@@ -126,23 +111,6 @@ void XmppSignalStrategy::OnConnectionStateChanged(
}
}
-void XmppSignalStrategy::OnJingleInfo(
- const std::string& token,
- const std::vector<std::string>& relay_hosts,
- const std::vector<talk_base::SocketAddress>& stun_hosts) {
- // TODO(ajwong): Log that we found the stun/turn servers.
- if (port_allocator_) {
- port_allocator_->SetRelayToken(token);
- port_allocator_->SetStunHosts(stun_hosts);
- port_allocator_->SetRelayHosts(relay_hosts);
- }
-
- if (allocator_config_cb_.get()) {
- allocator_config_cb_->Run();
- allocator_config_cb_.reset();
- }
-}
-
buzz::PreXmppAuth* XmppSignalStrategy::CreatePreXmppAuth(
const buzz::XmppClientSettings& settings) {
buzz::Jid jid(settings.user(), settings.host(), buzz::STR_EMPTY);
@@ -151,34 +119,47 @@ buzz::PreXmppAuth* XmppSignalStrategy::CreatePreXmppAuth(
}
-JavascriptSignalStrategy::JavascriptSignalStrategy() {
+JavascriptSignalStrategy::JavascriptSignalStrategy(const std::string& your_jid)
+ : your_jid_(your_jid) {
}
JavascriptSignalStrategy::~JavascriptSignalStrategy() {
}
void JavascriptSignalStrategy::Init(StatusObserver* observer) {
- NOTIMPLEMENTED();
-}
-
-void JavascriptSignalStrategy::ConfigureAllocator(
- cricket::HttpPortAllocator* port_allocator, Task* done) {
- NOTIMPLEMENTED();
- done->Run();
- delete done;
+ // Blast through each state since for a JavascriptSignalStrategy, we're
+ // already connected.
+ //
+ // TODO(ajwong): Clarify the status API contract to see if we have to actually
+ // walk through each state.
+ observer->OnStateChange(StatusObserver::START);
+ observer->OnStateChange(StatusObserver::CONNECTING);
+ observer->OnJidChange(your_jid_);
+ observer->OnStateChange(StatusObserver::CONNECTED);
}
void JavascriptSignalStrategy::StartSession(
cricket::SessionManager* session_manager) {
- NOTIMPLEMENTED();
+ session_start_request_.reset(
+ new SessionStartRequest(CreateIqRequest(), session_manager));
+ session_start_request_->Run();
}
void JavascriptSignalStrategy::EndSession() {
- NOTIMPLEMENTED();
+ if (xmpp_proxy_) {
+ xmpp_proxy_->DetachCallback();
+ }
+ xmpp_proxy_ = NULL;
+}
+
+void JavascriptSignalStrategy::AttachXmppProxy(
+ scoped_refptr<XmppProxy> xmpp_proxy) {
+ xmpp_proxy_ = xmpp_proxy;
+ xmpp_proxy_->AttachCallback(iq_registry_.AsWeakPtr());
}
-IqRequest* JavascriptSignalStrategy::CreateIqRequest() {
- return new JavascriptIqRequest();
+JavascriptIqRequest* JavascriptSignalStrategy::CreateIqRequest() {
+ return new JavascriptIqRequest(&iq_registry_, xmpp_proxy_);
}
JingleClient::JingleClient(JingleThread* thread,
@@ -246,8 +227,12 @@ void JingleClient::DoInitialize() {
// other fields of JingleClient initialized first, otherwise the state-change
// may occur and callback into class before we're done initializing.
signal_strategy_->Init(this);
- signal_strategy_->ConfigureAllocator(
- port_allocator_.get(),
+
+ jingle_info_request_.reset(
+ new JingleInfoRequest(signal_strategy_->CreateIqRequest()));
+ jingle_info_request_->SetCallback(
+ NewCallback(this, &JingleClient::OnJingleInfo));
+ jingle_info_request_->Run(
NewRunnableMethod(this, &JingleClient::DoStartSession));
}
@@ -346,4 +331,25 @@ void JingleClient::OnJidChange(const std::string& full_jid) {
full_jid_ = full_jid;
}
+void JingleClient::OnJingleInfo(
+ const std::string& token,
+ const std::vector<std::string>& relay_hosts,
+ const std::vector<talk_base::SocketAddress>& stun_hosts) {
+ if (port_allocator_.get()) {
+ // TODO(ajwong): Avoid string processing if log-level is low.
+ std::string stun_servers;
+ for (size_t i = 0; i < stun_hosts.size(); ++i) {
+ stun_servers += stun_hosts[i].ToString() + "; ";
+ }
+ LOG(INFO) << "Configuring with relay token: " << token
+ << ", relays: " << JoinString(relay_hosts, ';')
+ << ", stun: " << stun_servers;
+ port_allocator_->SetRelayToken(token);
+ port_allocator_->SetStunHosts(stun_hosts);
+ port_allocator_->SetRelayHosts(relay_hosts);
+ } else {
+ LOG(INFO) << "Jingle info found but no port allocator.";
+ }
+}
+
} // namespace remoting
diff --git a/remoting/jingle_glue/jingle_client.h b/remoting/jingle_glue/jingle_client.h
index 0557465..b24a67f 100644
--- a/remoting/jingle_glue/jingle_client.h
+++ b/remoting/jingle_glue/jingle_client.h
@@ -10,6 +10,8 @@
#include "base/gtest_prod_util.h"
#include "base/ref_counted.h"
#include "base/synchronization/lock.h"
+#include "remoting/jingle_glue/iq_request.h"
+#include "remoting/jingle_glue/xmpp_proxy.h"
#include "third_party/libjingle/source/talk/xmpp/xmppclient.h"
class MessageLoop;
@@ -38,8 +40,8 @@ class Session;
namespace remoting {
-class IqRequest;
class JingleThread;
+class XmppProxy;
// TODO(ajwong): The SignalStrategy stuff needs to be separated out to separate
// files.
@@ -62,8 +64,6 @@ class SignalStrategy {
SignalStrategy() {}
virtual ~SignalStrategy() {}
virtual void Init(StatusObserver* observer) = 0;
- virtual void ConfigureAllocator(
- cricket::HttpPortAllocator* port_allocator, Task* done) = 0;
virtual void StartSession(cricket::SessionManager* session_manager) = 0;
virtual void EndSession() = 0;
virtual IqRequest* CreateIqRequest() = 0;
@@ -81,8 +81,6 @@ class XmppSignalStrategy : public SignalStrategy, public sigslot::has_slots<> {
virtual ~XmppSignalStrategy();
virtual void Init(StatusObserver* observer);
- virtual void ConfigureAllocator(
- cricket::HttpPortAllocator* port_allocator, Task* done);
virtual void StartSession(cricket::SessionManager* session_manager);
virtual void EndSession();
virtual IqRequest* CreateIqRequest();
@@ -91,9 +89,6 @@ class XmppSignalStrategy : public SignalStrategy, public sigslot::has_slots<> {
friend class JingleClientTest;
void OnConnectionStateChanged(buzz::XmppEngine::State state);
- void OnJingleInfo(const std::string& token,
- const std::vector<std::string>& relay_hosts,
- const std::vector<talk_base::SocketAddress>& stun_hosts);
static buzz::PreXmppAuth* CreatePreXmppAuth(
const buzz::XmppClientSettings& settings);
@@ -105,30 +100,30 @@ class XmppSignalStrategy : public SignalStrategy, public sigslot::has_slots<> {
buzz::XmppClient* xmpp_client_;
StatusObserver* observer_;
- cricket::HttpPortAllocator* port_allocator_;
- scoped_ptr<Task> allocator_config_cb_;
-
DISALLOW_COPY_AND_ASSIGN(XmppSignalStrategy);
};
// TODO(hclam): Javascript implementation of this interface shouldn't be here.
class JavascriptSignalStrategy : public SignalStrategy {
public:
- JavascriptSignalStrategy();
+ explicit JavascriptSignalStrategy(const std::string& your_jid);
virtual ~JavascriptSignalStrategy();
virtual void Init(StatusObserver* observer);
- virtual void ConfigureAllocator(
- cricket::HttpPortAllocator* port_allocator, Task* done);
virtual void StartSession(cricket::SessionManager* session_manager);
virtual void EndSession();
- virtual IqRequest* CreateIqRequest();
+ virtual void AttachXmppProxy(scoped_refptr<XmppProxy> xmpp_proxy);
+ virtual JavascriptIqRequest* CreateIqRequest();
private:
+ std::string your_jid_;
+ scoped_refptr<XmppProxy> xmpp_proxy_;
+ JavascriptIqRegistry iq_registry_;
+ scoped_ptr<SessionStartRequest> session_start_request_;
+
DISALLOW_COPY_AND_ASSIGN(JavascriptSignalStrategy);
};
-
class JingleClient : public base::RefCountedThreadSafe<JingleClient>,
public SignalStrategy::StatusObserver {
public:
@@ -190,8 +185,14 @@ class JingleClient : public base::RefCountedThreadSafe<JingleClient>,
// the jingle thread.
void UpdateState(State new_state);
+ // Virtual for mocking in a unittest.
+ //
+ // TODO(ajwong): Private virtual functions are odd. Can we remove this?
virtual void OnStateChange(State state);
virtual void OnJidChange(const std::string& full_jid);
+ void OnJingleInfo(const std::string& token,
+ const std::vector<std::string>& relay_hosts,
+ const std::vector<talk_base::SocketAddress>& stun_hosts);
// JingleThread used for the connection. Set in the constructor.
JingleThread* thread_;
@@ -224,6 +225,8 @@ class JingleClient : public base::RefCountedThreadSafe<JingleClient>,
scoped_ptr<cricket::HttpPortAllocator> port_allocator_;
scoped_ptr<cricket::SessionManager> session_manager_;
+ scoped_ptr<JingleInfoRequest> jingle_info_request_;
+
DISALLOW_COPY_AND_ASSIGN(JingleClient);
};
diff --git a/remoting/jingle_glue/jingle_info_task.cc b/remoting/jingle_glue/jingle_info_task.cc
deleted file mode 100644
index 309caf0..0000000
--- a/remoting/jingle_glue/jingle_info_task.cc
+++ /dev/null
@@ -1,139 +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/jingle_glue/jingle_info_task.h"
-
-#include "base/scoped_ptr.h"
-#include "third_party/libjingle/source/talk/base/socketaddress.h"
-#include "third_party/libjingle/source/talk/xmpp/constants.h"
-#include "third_party/libjingle/source/talk/xmpp/xmppclient.h"
-
-namespace remoting {
-
-// This code is a copy of googleclient/talk/app/jingleinfotask.cc .
-
-class JingleInfoTask::JingleInfoGetTask : public XmppTask {
- public:
- explicit JingleInfoGetTask(talk_base::TaskParent* parent)
- : XmppTask(parent, buzz::XmppEngine::HL_SINGLE),
- done_(false) {
- }
-
- virtual int ProcessStart() {
- // Set jingle info query IQ stanza.
- scoped_ptr<buzz::XmlElement> get_iq(
- MakeIq(buzz::STR_GET, buzz::JID_EMPTY, task_id()));
- get_iq->AddElement(new buzz::XmlElement(buzz::QN_JINGLE_INFO_QUERY, true));
- if (SendStanza(get_iq.get()) != buzz::XMPP_RETURN_OK) {
- return STATE_ERROR;
- }
- return STATE_RESPONSE;
- }
-
- virtual int ProcessResponse() {
- if (done_) {
- return STATE_DONE;
- }
- return STATE_BLOCKED;
- }
-
- protected:
- virtual bool HandleStanza(const buzz::XmlElement* stanza) {
- if (!MatchResponseIq(stanza, buzz::JID_EMPTY, task_id())) {
- return false;
- }
-
- if (stanza->Attr(buzz::QN_TYPE) != buzz::STR_RESULT) {
- return false;
- }
-
- // Queue the stanza with the parent so these don't get handled out of order.
- JingleInfoTask* parent = static_cast<JingleInfoTask*>(GetParent());
- parent->QueueStanza(stanza);
-
- // Wake ourselves so we can go into the done state.
- done_ = true;
- Wake();
- return true;
- }
-
- bool done_;
-};
-
-
-JingleInfoTask::JingleInfoTask(talk_base::TaskParent* parent)
- : XmppTask(parent, buzz::XmppEngine::HL_TYPE) {
-}
-
-JingleInfoTask::~JingleInfoTask() {}
-
-void JingleInfoTask::RefreshJingleInfoNow() {
- JingleInfoGetTask* get_task = new JingleInfoGetTask(this);
- get_task->Start();
-}
-
-bool JingleInfoTask::HandleStanza(const buzz::XmlElement* stanza) {
- if (!MatchRequestIq(stanza, "set", buzz::QN_JINGLE_INFO_QUERY)) {
- return false;
- }
-
- // Only respect relay push from the server.
- buzz::Jid from(stanza->Attr(buzz::QN_FROM));
- if (from != buzz::JID_EMPTY &&
- !from.BareEquals(GetClient()->jid()) &&
- from != buzz::Jid(GetClient()->jid().domain())) {
- return false;
- }
-
- QueueStanza(stanza);
- return true;
-}
-
-int JingleInfoTask::ProcessStart() {
- std::vector<std::string> relay_hosts;
- std::vector<talk_base::SocketAddress> stun_hosts;
- std::string relay_token;
- const buzz::XmlElement* stanza = NextStanza();
- if (stanza == NULL) {
- return STATE_BLOCKED;
- }
- const buzz::XmlElement* query =
- stanza->FirstNamed(buzz::QN_JINGLE_INFO_QUERY);
- if (query == NULL) {
- return STATE_START;
- }
- const buzz::XmlElement* stun = query->FirstNamed(buzz::QN_JINGLE_INFO_STUN);
- if (stun) {
- for (const buzz::XmlElement* server =
- stun->FirstNamed(buzz::QN_JINGLE_INFO_SERVER);
- server != NULL;
- server = server->NextNamed(buzz::QN_JINGLE_INFO_SERVER)) {
- std::string host = server->Attr(buzz::QN_JINGLE_INFO_HOST);
- std::string port = server->Attr(buzz::QN_JINGLE_INFO_UDP);
- if (host != buzz::STR_EMPTY && host != buzz::STR_EMPTY) {
- // TODO(sergeyu): Avoid atoi() here.
- stun_hosts.push_back(
- talk_base::SocketAddress(host, atoi(port.c_str())));
- }
- }
- }
-
- const buzz::XmlElement* relay = query->FirstNamed(buzz::QN_JINGLE_INFO_RELAY);
- if (relay) {
- relay_token = relay->TextNamed(buzz::QN_JINGLE_INFO_TOKEN);
- for (const buzz::XmlElement* server =
- relay->FirstNamed(buzz::QN_JINGLE_INFO_SERVER);
- server != NULL;
- server = server->NextNamed(buzz::QN_JINGLE_INFO_SERVER)) {
- std::string host = server->Attr(buzz::QN_JINGLE_INFO_HOST);
- if (host != buzz::STR_EMPTY) {
- relay_hosts.push_back(host);
- }
- }
- }
- SignalJingleInfo(relay_token, relay_hosts, stun_hosts);
- return STATE_START;
-}
-
-} // namespace remoting
diff --git a/remoting/jingle_glue/jingle_info_task.h b/remoting/jingle_glue/jingle_info_task.h
deleted file mode 100644
index cfd8a5e..0000000
--- a/remoting/jingle_glue/jingle_info_task.h
+++ /dev/null
@@ -1,45 +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.
-
-#ifndef REMOTING_JINGLE_GLUE_JINGLE_INFO_TASK_H_
-#define REMOTING_JINGLE_GLUE_JINGLE_INFO_TASK_H_
-
-#include <vector>
-#include <string>
-
-#include "third_party/libjingle/source/talk/base/sigslot.h"
-#include "third_party/libjingle/source/talk/p2p/client/httpportallocator.h"
-#include "third_party/libjingle/source/talk/xmpp/xmppengine.h"
-#include "third_party/libjingle/source/talk/xmpp/xmpptask.h"
-
-namespace remoting {
-
-// JingleInfoTask is used to discover addresses of jingle servers.
-// See http://code.google.com/apis/talk/jep_extensions/jingleinfo.html
-// for more details about the protocol.
-//
-// This is a copy of googleclient/talk/app/jingleinfotask.h .
-class JingleInfoTask : public buzz::XmppTask {
- public:
- explicit JingleInfoTask(talk_base::TaskParent* parent);
- virtual ~JingleInfoTask();
-
- virtual int ProcessStart();
- void RefreshJingleInfoNow();
-
- sigslot::signal3<const std::string&,
- const std::vector<std::string>&,
- const std::vector<talk_base::SocketAddress>&>
- SignalJingleInfo;
-
- protected:
- class JingleInfoGetTask;
- friend class JingleInfoGetTask;
-
- virtual bool HandleStanza(const buzz::XmlElement* stanza);
-};
-
-} // namespace remoting
-
-#endif // REMOTING_JINGLE_GLUE_JINGLE_INFO_TASK_H_
diff --git a/remoting/jingle_glue/xmpp_proxy.h b/remoting/jingle_glue/xmpp_proxy.h
new file mode 100644
index 0000000..a2380fc
--- /dev/null
+++ b/remoting/jingle_glue/xmpp_proxy.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2011 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.
+
+// The XmppProxy is a shim interface that allows a class from layers above
+// the protocol to insert custom logic for dispatching the XMPP requests
+// necessary for creating a jingle connection.
+//
+// The primary motivator for this is to allow libjingle to be sandboxed in the
+// client by proxying the XMPP requests up through javascript into a
+// javascript-based XMPP connection back into the GoogleTalk network. It's
+// essentially a clean hack.
+
+#ifndef REMOTING_JINGLE_GLUE_XMPP_PROXY_H_
+#define REMOTING_JINGLE_GLUE_XMPP_PROXY_H_
+
+#include <string>
+
+#include "base/ref_counted.h"
+#include "base/weak_ptr.h"
+
+class MessageLoop;
+
+namespace remoting {
+
+class XmppProxy : public base::RefCountedThreadSafe<XmppProxy> {
+ public:
+ XmppProxy() {}
+
+ class ResponseCallback : public base::SupportsWeakPtr<ResponseCallback> {
+ public:
+ ResponseCallback() {}
+ virtual ~ResponseCallback() {}
+ virtual void OnIq(const std::string& response_xml) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ResponseCallback);
+ };
+
+ // These two must be called on the callback's message_loop. Callback will
+ // always been run on the callback_loop.
+ virtual void AttachCallback(base::WeakPtr<ResponseCallback> callback) = 0;
+ virtual void DetachCallback() = 0;
+
+ virtual void SendIq(const std::string& iq_request_xml) = 0;
+
+ protected:
+ friend class base::RefCountedThreadSafe<XmppProxy>;
+ virtual ~XmppProxy() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(XmppProxy);
+};
+
+} // namespace remoting
+
+#endif // REMOTING_JINGLE_GLUE_XMPP_PROXY_H_
diff --git a/remoting/protocol/connection_to_host.cc b/remoting/protocol/connection_to_host.cc
index 2ef3a22..cf65520 100644
--- a/remoting/protocol/connection_to_host.cc
+++ b/remoting/protocol/connection_to_host.cc
@@ -59,17 +59,32 @@ void ConnectionToHost::Connect(const std::string& username,
video_stub_ = video_stub;
// Initialize |jingle_client_|.
- if (1 == 0) {
- signal_strategy_.reset(new JavascriptSignalStrategy());
- } else {
- signal_strategy_.reset(
- new XmppSignalStrategy(thread_, username, auth_token,
- kChromotingTokenServiceName));
- }
+ signal_strategy_.reset(
+ new XmppSignalStrategy(thread_, username, auth_token,
+ kChromotingTokenServiceName));
+ jingle_client_ = new JingleClient(thread_, signal_strategy_.get(), this);
+ jingle_client_->Init();
- jingle_client_ = new JingleClient(thread_, signal_strategy_.get(),
- network_manager_.release(),
- socket_factory_.release(), this);
+ // Save jid of the host. The actual connection is created later after
+ // |jingle_client_| is connected.
+ host_jid_ = host_jid;
+}
+
+void ConnectionToHost::ConnectSandboxed(scoped_refptr<XmppProxy> xmpp_proxy,
+ const std::string& your_jid,
+ const std::string& host_jid,
+ HostEventCallback* event_callback,
+ ClientStub* client_stub,
+ VideoStub* video_stub) {
+ event_callback_ = event_callback;
+ client_stub_ = client_stub;
+ video_stub_ = video_stub;
+
+ // Initialize |jingle_client_|.
+ JavascriptSignalStrategy* strategy = new JavascriptSignalStrategy(your_jid);
+ strategy->AttachXmppProxy(xmpp_proxy);
+ signal_strategy_.reset(strategy);
+ jingle_client_ = new JingleClient(thread_, signal_strategy_.get(), this);
jingle_client_->Init();
// Save jid of the host. The actual connection is created later after
diff --git a/remoting/protocol/connection_to_host.h b/remoting/protocol/connection_to_host.h
index 3962c32..da91be9 100644
--- a/remoting/protocol/connection_to_host.h
+++ b/remoting/protocol/connection_to_host.h
@@ -24,6 +24,7 @@ class MessageLoop;
namespace remoting {
class JingleThread;
+class XmppProxy;
class VideoPacket;
namespace protocol {
@@ -66,6 +67,12 @@ class ConnectionToHost : public JingleClient::Callback {
HostEventCallback* event_callback,
ClientStub* client_stub,
VideoStub* video_stub);
+ virtual void ConnectSandboxed(scoped_refptr<XmppProxy> xmpp_proxy,
+ const std::string& your_jid,
+ const std::string& host_jid,
+ HostEventCallback* event_callback,
+ ClientStub* client_stub,
+ VideoStub* video_stub);
virtual void Disconnect();
virtual const SessionConfig* config();
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index f651a9c..eb6fe57 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -97,6 +97,8 @@
'client/plugin/pepper_view_proxy.h',
'client/plugin/pepper_util.cc',
'client/plugin/pepper_util.h',
+ 'client/plugin/pepper_xmpp_proxy.cc',
+ 'client/plugin/pepper_xmpp_proxy.h',
'../media/base/yuv_convert.cc',
'../media/base/yuv_convert.h',
'../media/base/yuv_row.h',
@@ -350,8 +352,6 @@
'jingle_glue/iq_request.h',
'jingle_glue/jingle_client.cc',
'jingle_glue/jingle_client.h',
- 'jingle_glue/jingle_info_task.cc',
- 'jingle_glue/jingle_info_task.h',
'jingle_glue/jingle_thread.cc',
'jingle_glue/jingle_thread.h',
'jingle_glue/stream_socket_adapter.cc',
@@ -362,6 +362,7 @@
'jingle_glue/ssl_socket_adapter.h',
'jingle_glue/utils.cc',
'jingle_glue/utils.h',
+ 'jingle_glue/xmpp_proxy.h',
'jingle_glue/xmpp_socket_adapter.cc',
'jingle_glue/xmpp_socket_adapter.h',
],