diff options
author | ajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-07 17:19:17 +0000 |
---|---|---|
committer | ajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-07 17:19:17 +0000 |
commit | 2db531074be20594b38f882448fa918996cd2abc (patch) | |
tree | f7ee240697eefcb53896ede6a01d46266554d190 | |
parent | a2f2e479644f4073b00b66d5efc67789b12d1072 (diff) | |
download | chromium_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
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', ], |