summaryrefslogtreecommitdiffstats
path: root/remoting/client
diff options
context:
space:
mode:
authorhclam@google.com <hclam@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-08 00:49:15 +0000
committerhclam@google.com <hclam@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-08 00:49:15 +0000
commitb852b07bce576b50aae75cbdc6ebf8c53d226c7f (patch)
tree4df04d0dc04157c7936dad0ae8d86d1c93cef56d /remoting/client
parent5aa4f8a5bf24c636bad09d8f653bc53b4a58e1ec (diff)
downloadchromium_src-b852b07bce576b50aae75cbdc6ebf8c53d226c7f.zip
chromium_src-b852b07bce576b50aae75cbdc6ebf8c53d226c7f.tar.gz
chromium_src-b852b07bce576b50aae75cbdc6ebf8c53d226c7f.tar.bz2
Replace libjingle's HttpPortAllocatorSession with Pepper's http client
HttpPortAllocatorSession uses libjingle's http client to establish relay connection. This will not work in the sanboxed case since it access OS level of network directly. This patch replaces the http client with URL loader in pepper. This goes through the standard URL fetching system for chrome to get around the sandbox problem. BUG=51198 TEST=Force libjingle to use relay and try it with this code. Review URL: http://codereview.chromium.org/6623048 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@77218 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting/client')
-rw-r--r--remoting/client/plugin/chromoting_instance.cc6
-rw-r--r--remoting/client/plugin/chromoting_scriptable_object.cc2
-rw-r--r--remoting/client/plugin/pepper_entrypoints.cc6
-rw-r--r--remoting/client/plugin/pepper_entrypoints.h1
-rw-r--r--remoting/client/plugin/pepper_port_allocator_session.cc420
-rw-r--r--remoting/client/plugin/pepper_port_allocator_session.h68
-rw-r--r--remoting/client/x11_client.cc2
7 files changed, 502 insertions, 3 deletions
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc
index bf5bea2..09dbc48 100644
--- a/remoting/client/plugin/chromoting_instance.cc
+++ b/remoting/client/plugin/chromoting_instance.cc
@@ -25,6 +25,7 @@
#include "remoting/client/rectangle_update_decoder.h"
#include "remoting/client/plugin/chromoting_scriptable_object.h"
#include "remoting/client/plugin/pepper_input_handler.h"
+#include "remoting/client/plugin/pepper_port_allocator_session.h"
#include "remoting/client/plugin/pepper_view.h"
#include "remoting/client/plugin/pepper_view_proxy.h"
#include "remoting/client/plugin/pepper_util.h"
@@ -79,6 +80,8 @@ bool ChromotingInstance::Init(uint32_t argc,
plugin_instance->delegate()->GetP2PSocketDispatcher();
IpcNetworkManager* network_manager = NULL;
IpcPacketSocketFactory* socket_factory = NULL;
+ PortAllocatorSessionFactory* session_factory =
+ CreatePepperPortAllocatorSessionFactory(this);
// If we don't have socket dispatcher for IPC (e.g. P2P API is
// disabled), then JingleClient will try to use physical sockets.
@@ -90,7 +93,8 @@ bool ChromotingInstance::Init(uint32_t argc,
// Create the chromoting objects.
host_connection_.reset(new protocol::ConnectionToHost(
- context_.jingle_thread(), network_manager, socket_factory));
+ context_.jingle_thread(), network_manager, socket_factory,
+ session_factory));
view_.reset(new PepperView(this, &context_));
view_proxy_ = new PepperViewProxy(this, view_.get());
rectangle_decoder_ = new RectangleUpdateDecoder(
diff --git a/remoting/client/plugin/chromoting_scriptable_object.cc b/remoting/client/plugin/chromoting_scriptable_object.cc
index 8d0e338..9a3e2c0 100644
--- a/remoting/client/plugin/chromoting_scriptable_object.cc
+++ b/remoting/client/plugin/chromoting_scriptable_object.cc
@@ -266,7 +266,7 @@ void ChromotingScriptableObject::SignalDesktopSizeChange() {
if (!exception.is_undefined()) {
LOG(WARNING) << "Exception when invoking JS callback"
- << exception.AsString();
+ << exception.DebugString();
}
}
diff --git a/remoting/client/plugin/pepper_entrypoints.cc b/remoting/client/plugin/pepper_entrypoints.cc
index a5e6142..21e0c84 100644
--- a/remoting/client/plugin/pepper_entrypoints.cc
+++ b/remoting/client/plugin/pepper_entrypoints.cc
@@ -59,4 +59,10 @@ const void* PPP_GetInterface(const char* interface_name) {
return pp::Module::Get()->GetPluginInterface(interface_name);
}
+const void* PPP_GetBrowserInterface(const char* interface_name) {
+ if (!pp::Module::Get())
+ return NULL;
+ return pp::Module::Get()->GetBrowserInterface(interface_name);
+}
+
} // namespace remoting
diff --git a/remoting/client/plugin/pepper_entrypoints.h b/remoting/client/plugin/pepper_entrypoints.h
index a9ec138..75229b3 100644
--- a/remoting/client/plugin/pepper_entrypoints.h
+++ b/remoting/client/plugin/pepper_entrypoints.h
@@ -14,6 +14,7 @@ int PPP_InitializeModule(PP_Module module_id,
PPB_GetInterface get_browser_interface);
void PPP_ShutdownModule();
const void* PPP_GetInterface(const char* interface_name);
+const void* PPP_GetBrowserInterface(const char* interface_name);
} // namespace remoting
diff --git a/remoting/client/plugin/pepper_port_allocator_session.cc b/remoting/client/plugin/pepper_port_allocator_session.cc
new file mode 100644
index 0000000..96489eb
--- /dev/null
+++ b/remoting/client/plugin/pepper_port_allocator_session.cc
@@ -0,0 +1,420 @@
+// 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.
+
+#include "remoting/client/plugin/pepper_port_allocator_session.h"
+
+#include <map>
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/synchronization/lock.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/trusted/ppb_url_loader_trusted.h"
+#include "ppapi/cpp/url_loader.h"
+#include "ppapi/cpp/url_request_info.h"
+#include "ppapi/cpp/url_response_info.h"
+#include "remoting/jingle_glue/http_port_allocator.h"
+#include "remoting/client/plugin/chromoting_instance.h"
+#include "remoting/client/plugin/pepper_entrypoints.h"
+#include "remoting/client/plugin/pepper_util.h"
+
+namespace {
+
+static const int kHostPort = 80;
+static const int kNumRetries = 5;
+static const std::string kCreateSessionURL = "/create_session";
+
+// Define a SessionFactory in the anonymouse namespace so we have a
+// shorter name.
+// TODO(hclam): Move this to a separate file.
+class SessionFactory : public remoting::PortAllocatorSessionFactory {
+ public:
+ SessionFactory(remoting::ChromotingInstance* instance,
+ MessageLoop* message_loop)
+ : instance_(instance),
+ jingle_message_loop_(message_loop) {
+ }
+
+ virtual cricket::PortAllocatorSession* CreateSession(
+ cricket::BasicPortAllocator* allocator,
+ const std::string& name,
+ const std::string& session_type,
+ const std::vector<talk_base::SocketAddress>& stun_hosts,
+ const std::vector<std::string>& relay_hosts,
+ const std::string& relay,
+ const std::string& agent) {
+ return new remoting::PepperPortAllocatorSession(
+ instance_, jingle_message_loop_, allocator, name, session_type,
+ stun_hosts, relay_hosts, relay, agent);
+ }
+
+ private:
+ remoting::ChromotingInstance* instance_;
+
+ // Message loop that jingle runs on.
+ MessageLoop* jingle_message_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(SessionFactory);
+};
+
+typedef Callback3<bool, int, const std::string&>::Type FetchCallback;
+
+// Parses the lines in the result of the HTTP request that are of the form
+// 'a=b' and returns them in a map.
+typedef std::map<std::string, std::string> StringMap;
+void ParseMap(const std::string& string, StringMap& map) {
+ size_t start_of_line = 0;
+ size_t end_of_line = 0;
+
+ for (;;) { // for each line
+ start_of_line = string.find_first_not_of("\r\n", end_of_line);
+ if (start_of_line == std::string::npos)
+ break;
+
+ end_of_line = string.find_first_of("\r\n", start_of_line);
+ if (end_of_line == std::string::npos) {
+ end_of_line = string.length();
+ }
+
+ size_t equals = string.find('=', start_of_line);
+ if ((equals >= end_of_line) || (equals == std::string::npos))
+ continue;
+
+ std::string key(string, start_of_line, equals - start_of_line);
+ std::string value(string, equals + 1, end_of_line - equals - 1);
+
+ TrimString(key, " \t\r\n", &key);
+ TrimString(value, " \t\r\n", &value);
+
+ if ((key.size() > 0) && (value.size() > 0))
+ map[key] = value;
+ }
+}
+
+} // namespace
+
+namespace remoting {
+
+// A URL Fetcher using Pepper.
+// TODO(hclam): Move this to a separate file.
+class PepperURLFetcher {
+ public:
+ PepperURLFetcher() : fetch_callback_(NULL) {
+ callback_factory_.Initialize(this);
+ }
+
+ void Start(const pp::Instance& instance,
+ pp::URLRequestInfo request,
+ FetchCallback* fetch_callback) {
+ loader_ = pp::URLLoader(instance);
+
+ // Grant access to external origins.
+ const struct PPB_URLLoaderTrusted* trusted_loader_interface =
+ reinterpret_cast<const PPB_URLLoaderTrusted*>(
+ PPP_GetBrowserInterface(PPB_URLLOADERTRUSTED_INTERFACE));
+ trusted_loader_interface->GrantUniversalAccess(
+ loader_.pp_resource());
+
+ fetch_callback_.reset(fetch_callback);
+
+ pp::CompletionCallback callback =
+ callback_factory_.NewCallback(&PepperURLFetcher::DidOpen);
+ int rv = loader_.Open(request, callback);
+ if (rv != PP_ERROR_WOULDBLOCK)
+ callback.Run(rv);
+ }
+
+ private:
+ void ReadMore() {
+ pp::CompletionCallback callback =
+ callback_factory_.NewCallback(&PepperURLFetcher::DidRead);
+ int rv = loader_.ReadResponseBody(buf_, sizeof(buf_), callback);
+ if (rv != PP_ERROR_WOULDBLOCK)
+ callback.Run(rv);
+ }
+
+ void DidOpen(int32_t result) {
+ if (result == PP_OK) {
+ ReadMore();
+ } else {
+ DidFinish(result);
+ }
+ }
+
+ void DidRead(int32_t result) {
+ if (result > 0) {
+ data_.append(buf_, result);
+ ReadMore();
+ } else {
+ DidFinish(result);
+ }
+ }
+
+ void DidFinish(int32_t result) {
+ if (fetch_callback_.get()) {
+ bool success = result == PP_OK;
+ int status_code = 0;
+ if (success)
+ status_code = loader_.GetResponseInfo().GetStatusCode();
+ fetch_callback_->Run(success, status_code, data_);
+ }
+ }
+
+ pp::CompletionCallbackFactory<PepperURLFetcher> callback_factory_;
+ pp::URLLoader loader_;
+ scoped_ptr<FetchCallback> fetch_callback_;
+ char buf_[4096];
+ std::string data_;
+};
+
+// A helper function to destruct |fetcher| on pepper thread.
+static void DeletePepperURLFetcher(PepperURLFetcher* fetcher) {
+ delete fetcher;
+}
+
+// A helper class to do HTTP request on the pepper thread and then delegate the
+// result to PepperPortAllocatorSession on jingle thread safely.
+class PepperCreateSessionTask
+ : public base::RefCountedThreadSafe<PepperCreateSessionTask> {
+ public:
+ PepperCreateSessionTask(
+ MessageLoop* jingle_message_loop,
+ PepperPortAllocatorSession* allocator_session,
+ ChromotingInstance* instance,
+ const std::string& host,
+ int port,
+ const std::string& relay_token,
+ const std::string& session_type,
+ const std::string& name)
+ : jingle_message_loop_(jingle_message_loop),
+ allocator_session_(allocator_session),
+ instance_(instance),
+ host_(host),
+ port_(port),
+ relay_token_(relay_token),
+ session_type_(session_type),
+ name_(name) {
+ }
+
+ // Start doing the request. The request will start on the pepper thread.
+ void Start() {
+ if (!CurrentlyOnPluginThread()) {
+ RunTaskOnPluginThread(
+ NewRunnableMethod(this, &PepperCreateSessionTask::Start));
+ return;
+ }
+
+ // Perform the request here.
+ std::string url = base::StringPrintf("http://%s:%d/create_session",
+ host_.c_str(), port_);
+ pp::URLRequestInfo request(instance_);
+ request.SetURL(url.c_str());
+ request.SetMethod("GET");
+ request.SetHeaders(base::StringPrintf(
+ "X-Talk-Google-Relay-Auth: %s\r\n"
+ "X-Google-Relay-Auth: %s\r\n"
+ "X-Session-Type: %s\r\n"
+ "X-Stream-Type: %s\r\n",
+ relay_token_.c_str(), relay_token_.c_str(), session_type_.c_str(),
+ name_.c_str()));
+
+ url_fetcher_.reset(new PepperURLFetcher());
+ url_fetcher_->Start(
+ *instance_, request,
+ NewCallback(this, &PepperCreateSessionTask::OnRequestDone));
+ }
+
+ // Detach this task. This class will not access PepperPortAllocatorSession
+ // anymore.
+ void Detach() {
+ // Set the pointers to zero.
+ {
+ base::AutoLock auto_lock(lock_);
+ jingle_message_loop_ = NULL;
+ allocator_session_ = NULL;
+ instance_ = NULL;
+ }
+
+ // IMPORTANT!
+ // Destroy PepperURLFetcher only on pepper thread.
+ RunTaskOnPluginThread(
+ NewRunnableFunction(&DeletePepperURLFetcher, url_fetcher_.release()));
+ }
+
+ private:
+ void OnRequestDone(bool success, int status_code,
+ const std::string& response) {
+ // IMPORTANT!
+ // This method is called on the pepper thread and we want the response to
+ // be delegated to the jingle thread. However jignle thread might have
+ // been destroyed and |allocator_session_| might be dangling too. So we
+ // put a lock here to access |jingle_message_loop_| and then do the
+ // remaining work on the jingle thread.
+ base::AutoLock auto_lock(lock_);
+ if (!jingle_message_loop_)
+ return;
+
+ jingle_message_loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &PepperCreateSessionTask::DelegateRequestDone,
+ success, status_code, response));
+ }
+
+ void DelegateRequestDone(bool success, int status_code,
+ const std::string& response) {
+ if (!allocator_session_)
+ return;
+ allocator_session_->OnRequestDone(success, status_code, response);
+ }
+
+ // Protects |jingle_message_loop_|.
+ base::Lock lock_;
+
+ MessageLoop* jingle_message_loop_;
+ PepperPortAllocatorSession* allocator_session_;
+ ChromotingInstance* instance_;
+ std::string host_;
+ int port_;
+ std::string relay_token_;
+ std::string session_type_;
+ std::string name_;
+
+ // Pepper resources for URL fetching.
+ scoped_ptr<PepperURLFetcher> url_fetcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(PepperCreateSessionTask);
+};
+
+PepperPortAllocatorSession::PepperPortAllocatorSession(
+ ChromotingInstance* instance,
+ MessageLoop* message_loop,
+ cricket::BasicPortAllocator* allocator,
+ const std::string &name,
+ const std::string& session_type,
+ const std::vector<talk_base::SocketAddress>& stun_hosts,
+ const std::vector<std::string>& relay_hosts,
+ const std::string& relay_token,
+ const std::string& user_agent)
+ : BasicPortAllocatorSession(allocator, name, session_type),
+ instance_(instance), jingle_message_loop_(message_loop),
+ relay_hosts_(relay_hosts), stun_hosts_(stun_hosts),
+ relay_token_(relay_token), agent_(user_agent), attempts_(0) {
+}
+
+PepperPortAllocatorSession::~PepperPortAllocatorSession() {
+ if (create_session_task_) {
+ create_session_task_->Detach();
+ create_session_task_ = NULL;
+ }
+}
+
+void PepperPortAllocatorSession::GetPortConfigurations() {
+ // Creating relay sessions can take time and is done asynchronously.
+ // Creating stun sessions could also take time and could be done aysnc also,
+ // but for now is done here and added to the initial config. Note any later
+ // configs will have unresolved stun ips and will be discarded by the
+ // AllocationSequence.
+ cricket::PortConfiguration* config =
+ new cricket::PortConfiguration(stun_hosts_[0], "", "", "");
+ ConfigReady(config);
+ TryCreateRelaySession();
+}
+
+void PepperPortAllocatorSession::TryCreateRelaySession() {
+ if (attempts_ == kNumRetries) {
+ LOG(ERROR) << "PepperPortAllocator: maximum number of requests reached; "
+ << "giving up on relay.";
+ return;
+ }
+
+ if (relay_hosts_.size() == 0) {
+ LOG(ERROR) << "PepperPortAllocator: no relay hosts configured.";
+ return;
+ }
+
+ // Choose the next host to try.
+ std::string host = relay_hosts_[attempts_ % relay_hosts_.size()];
+ attempts_++;
+ LOG(INFO) << "PepperPortAllocator: sending to relay host " << host;
+ if (relay_token_.empty()) {
+ LOG(WARNING) << "No relay auth token found.";
+ }
+
+ SendSessionRequest(host, kHostPort);
+}
+
+void PepperPortAllocatorSession::SendSessionRequest(const std::string& host,
+ int port) {
+ // Destroy the old PepperCreateSessionTask first.
+ if (create_session_task_) {
+ create_session_task_->Detach();
+ create_session_task_ = NULL;
+ }
+
+ // Construct a new one and start it. OnRequestDone() will be called when
+ // task has completed.
+ create_session_task_ = new PepperCreateSessionTask(
+ jingle_message_loop_, this, instance_, host, port, relay_token_,
+ session_type(), name());
+ create_session_task_->Start();
+}
+
+void PepperPortAllocatorSession::OnRequestDone(bool success,
+ int status_code,
+ const std::string& response) {
+ DCHECK_EQ(jingle_message_loop_, MessageLoop::current());
+
+ if (!success || status_code != 200) {
+ LOG(WARNING) << "PepperPortAllocatorSession: failed.";
+ TryCreateRelaySession();
+ return;
+ }
+
+ LOG(INFO) << "PepperPortAllocatorSession: request succeeded.";
+ ReceiveSessionResponse(response);
+}
+
+void PepperPortAllocatorSession::ReceiveSessionResponse(
+ const std::string& response) {
+ StringMap map;
+ ParseMap(response, map);
+
+ std::string username = map["username"];
+ std::string password = map["password"];
+ std::string magic_cookie = map["magic_cookie"];
+
+ std::string relay_ip = map["relay.ip"];
+ std::string relay_udp_port = map["relay.udp_port"];
+ std::string relay_tcp_port = map["relay.tcp_port"];
+ std::string relay_ssltcp_port = map["relay.ssltcp_port"];
+
+ cricket::PortConfiguration* config =
+ new cricket::PortConfiguration(stun_hosts_[0], username,
+ password, magic_cookie);
+
+ cricket::PortConfiguration::PortList ports;
+ if (!relay_udp_port.empty()) {
+ talk_base::SocketAddress address(relay_ip, atoi(relay_udp_port.c_str()));
+ ports.push_back(cricket::ProtocolAddress(address, cricket::PROTO_UDP));
+ }
+ if (!relay_tcp_port.empty()) {
+ talk_base::SocketAddress address(relay_ip, atoi(relay_tcp_port.c_str()));
+ ports.push_back(cricket::ProtocolAddress(address, cricket::PROTO_TCP));
+ }
+ if (!relay_ssltcp_port.empty()) {
+ talk_base::SocketAddress address(relay_ip, atoi(relay_ssltcp_port.c_str()));
+ ports.push_back(cricket::ProtocolAddress(address, cricket::PROTO_SSLTCP));
+ }
+ config->AddRelay(ports, 0.0f);
+ ConfigReady(config);
+}
+
+PortAllocatorSessionFactory* CreatePepperPortAllocatorSessionFactory(
+ ChromotingInstance* instance) {
+ return new SessionFactory(instance, MessageLoop::current());
+}
+
+} // namespace remoting
diff --git a/remoting/client/plugin/pepper_port_allocator_session.h b/remoting/client/plugin/pepper_port_allocator_session.h
new file mode 100644
index 0000000..fa30ebe
--- /dev/null
+++ b/remoting/client/plugin/pepper_port_allocator_session.h
@@ -0,0 +1,68 @@
+// 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.
+
+#ifndef REMOTING_CLIENT_PLUGIN_PEPPER_PORT_ALLOCATOR_SESSION_H_
+#define REMOTING_CLIENT_PLUGIN_PEPPER_PORT_ALLOCATOR_SESSION_H_
+
+#include "base/message_loop.h"
+#include "ppapi/cpp/completion_callback.h"
+#include "third_party/libjingle/source/talk/p2p/client/basicportallocator.h"
+
+namespace remoting {
+
+class ChromotingInstance;
+class PepperCreateSessionTask;
+class PepperURLFetcher;
+class PortAllocatorSessionFactory;
+
+class PepperPortAllocatorSession : public cricket::BasicPortAllocatorSession {
+ public:
+ PepperPortAllocatorSession(
+ ChromotingInstance* instance,
+ MessageLoop* message_loop,
+ cricket::BasicPortAllocator* allocator,
+ const std::string& name,
+ const std::string& session_type,
+ const std::vector<talk_base::SocketAddress>& stun_hosts,
+ const std::vector<std::string>& relay_hosts,
+ const std::string& relay,
+ const std::string& agent);
+ virtual ~PepperPortAllocatorSession();
+
+ const std::string& relay_token() const {
+ return relay_token_;
+ }
+
+ // Overrides the implementations in BasicPortAllocatorSession to use
+ // pepper's URLLoader as HTTP client.
+ virtual void SendSessionRequest(const std::string& host, int port);
+ virtual void ReceiveSessionResponse(const std::string& response);
+
+ void OnRequestDone(bool success, int status_code,
+ const std::string& response);
+
+ private:
+ virtual void GetPortConfigurations();
+ void TryCreateRelaySession();
+
+ ChromotingInstance* const instance_;
+ MessageLoop* const jingle_message_loop_;
+
+ std::vector<std::string> relay_hosts_;
+ std::vector<talk_base::SocketAddress> stun_hosts_;
+ std::string relay_token_;
+ std::string agent_;
+ int attempts_;
+
+ scoped_refptr<PepperCreateSessionTask> create_session_task_;
+
+ DISALLOW_COPY_AND_ASSIGN(PepperPortAllocatorSession);
+};
+
+PortAllocatorSessionFactory* CreatePepperPortAllocatorSessionFactory(
+ ChromotingInstance* instance);
+
+} // namespace remoting
+
+#endif // REMOTING_CLIENT_PLUGIN_PEPPER_PORT_ALLOCATOR_SESSION_H_
diff --git a/remoting/client/x11_client.cc b/remoting/client/x11_client.cc
index bed2e55..4fffa7b 100644
--- a/remoting/client/x11_client.cc
+++ b/remoting/client/x11_client.cc
@@ -33,7 +33,7 @@ int main(int argc, char** argv) {
MessageLoop ui_loop;
remoting::ClientContext context;
remoting::protocol::ConnectionToHost connection(context.jingle_thread(),
- NULL, NULL);
+ NULL, NULL, NULL);
remoting::X11View view;
scoped_refptr<remoting::RectangleUpdateDecoder> rectangle_decoder =
new remoting::RectangleUpdateDecoder(context.decode_message_loop(),