Revert 168224 - Update V8 to version 3.15.4.
[chromium-blink-merge.git] / remoting / client / plugin / pepper_port_allocator.cc
blob62a5822e9a1e4fa90cdeb390a991bd959e0fd686
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "remoting/client/plugin/pepper_port_allocator.h"
7 #include "base/bind.h"
8 #include "base/string_number_conversions.h"
9 #include "net/base/net_util.h"
10 #include "ppapi/c/pp_errors.h"
11 #include "ppapi/cpp/completion_callback.h"
12 #include "ppapi/cpp/private/host_resolver_private.h"
13 #include "ppapi/cpp/url_loader.h"
14 #include "ppapi/cpp/url_request_info.h"
15 #include "ppapi/cpp/url_response_info.h"
16 #include "remoting/client/plugin/pepper_network_manager.h"
17 #include "remoting/client/plugin/pepper_packet_socket_factory.h"
18 #include "remoting/client/plugin/pepper_util.h"
20 namespace remoting {
22 namespace {
24 // URL used to create a relay session.
25 const char kCreateRelaySessionURL[] = "/create_session";
27 // Read buffer we allocate per read when reading response from
28 // URLLoader. Normally the response from URL loader is smaller than 1kB.
29 const int kReadSize = 1024;
31 class PepperPortAllocatorSession
32 : public cricket::HttpPortAllocatorSessionBase {
33 public:
34 PepperPortAllocatorSession(
35 cricket::HttpPortAllocatorBase* allocator,
36 const std::string& content_name,
37 int component,
38 const std::string& ice_username_fragment,
39 const std::string& ice_password,
40 const std::vector<talk_base::SocketAddress>& stun_hosts,
41 const std::vector<std::string>& relay_hosts,
42 const std::string& relay_token,
43 const pp::InstanceHandle& instance);
44 virtual ~PepperPortAllocatorSession();
46 // cricket::HttpPortAllocatorBase overrides.
47 virtual void ConfigReady(cricket::PortConfiguration* config) OVERRIDE;
48 virtual void GetPortConfigurations() OVERRIDE;
49 virtual void SendSessionRequest(const std::string& host, int port) OVERRIDE;
51 private:
52 void ResolveStunServerAddress();
53 void OnStunAddressResolved(int32_t result);
55 void OnUrlOpened(int32_t result);
56 void ReadResponseBody();
57 void OnResponseBodyRead(int32_t result);
59 pp::InstanceHandle instance_;
61 pp::HostResolverPrivate stun_address_resolver_;
62 talk_base::SocketAddress stun_address_;
63 int stun_port_;
65 scoped_ptr<pp::URLLoader> relay_url_loader_;
66 std::vector<char> relay_response_body_;
67 bool relay_response_received_;
69 // Used to safely cancel completion callbacks from PPAPI calls.
70 base::WeakPtrFactory<PepperPortAllocatorSession> weak_factory_;
72 DISALLOW_COPY_AND_ASSIGN(PepperPortAllocatorSession);
75 PepperPortAllocatorSession::PepperPortAllocatorSession(
76 cricket::HttpPortAllocatorBase* allocator,
77 const std::string& content_name,
78 int component,
79 const std::string& ice_username_fragment,
80 const std::string& ice_password,
81 const std::vector<talk_base::SocketAddress>& stun_hosts,
82 const std::vector<std::string>& relay_hosts,
83 const std::string& relay_token,
84 const pp::InstanceHandle& instance)
85 : HttpPortAllocatorSessionBase(
86 allocator, content_name, component, ice_username_fragment, ice_password,
87 stun_hosts, relay_hosts, relay_token, ""),
88 instance_(instance),
89 stun_address_resolver_(instance_),
90 stun_port_(0),
91 relay_response_received_(false),
92 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
93 if (stun_hosts.size() > 0) {
94 stun_address_ = stun_hosts[0];
98 PepperPortAllocatorSession::~PepperPortAllocatorSession() {
101 void PepperPortAllocatorSession::ConfigReady(
102 cricket::PortConfiguration* config) {
103 if (config->stun_address.IsUnresolved()) {
104 // Make sure that the address that we pass to ConfigReady() is
105 // always resolved.
106 if (stun_address_.IsUnresolved()) {
107 config->stun_address.Clear();
108 } else {
109 config->stun_address = stun_address_;
113 // Filter out non-UDP relay ports, so that we don't try using TCP.
114 for (cricket::PortConfiguration::RelayList::iterator relay =
115 config->relays.begin(); relay != config->relays.end(); ++relay) {
116 cricket::PortList filtered_ports;
117 for (cricket::PortList::iterator port =
118 relay->ports.begin(); port != relay->ports.end(); ++port) {
119 if (port->proto == cricket::PROTO_UDP) {
120 filtered_ports.push_back(*port);
123 relay->ports = filtered_ports;
125 cricket::BasicPortAllocatorSession::ConfigReady(config);
128 void PepperPortAllocatorSession::GetPortConfigurations() {
129 // Add an empty configuration synchronously, so a local connection
130 // can be started immediately.
131 ConfigReady(new cricket::PortConfiguration(
132 talk_base::SocketAddress(), "", ""));
134 ResolveStunServerAddress();
135 TryCreateRelaySession();
138 void PepperPortAllocatorSession::ResolveStunServerAddress() {
139 if (stun_address_.IsNil()) {
140 return;
143 if (!stun_address_.IsUnresolved()) {
144 return;
147 std::string hostname = stun_address_.hostname();
148 uint16 port = stun_address_.port();
150 PP_HostResolver_Private_Hint hint;
151 hint.flags = 0;
152 hint.family = PP_NETADDRESSFAMILY_IPV4;
153 int result = stun_address_resolver_.Resolve(
154 hostname, port, hint,
155 PpCompletionCallback(base::Bind(
156 &PepperPortAllocatorSession::OnStunAddressResolved,
157 weak_factory_.GetWeakPtr())));
159 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
162 void PepperPortAllocatorSession::OnStunAddressResolved(int32_t result) {
163 if (result < 0) {
164 LOG(ERROR) << "Failed to resolve stun address "
165 << stun_address_.hostname() << ": " << result;
166 return;
169 if (!stun_address_resolver_.GetSize()) {
170 LOG(WARNING) << "Received 0 addresses for stun server "
171 << stun_address_.hostname();
172 return;
175 PP_NetAddress_Private address;
176 if (!stun_address_resolver_.GetNetAddress(0, &address) ||
177 !PpAddressToSocketAddress(address, &stun_address_)) {
178 LOG(ERROR) << "Failed to get address for STUN server "
179 << stun_address_.hostname();
180 return;
183 DCHECK(!stun_address_.IsUnresolved());
185 if (relay_response_received_) {
186 // If we've finished reading the response, then resubmit it to
187 // HttpPortAllocatorSessionBase. This is necessary because STUN
188 // and Relay parameters are stored together in PortConfiguration
189 // and ReceiveSessionResponse() doesn't save relay session
190 // configuration for the case we resolve STUN address later. This
191 // method invokes overriden ConfigReady() which then submits
192 // resolved |stun_address_|.
194 // TODO(sergeyu): Refactor HttpPortAllocatorSessionBase to fix this.
195 ReceiveSessionResponse(std::string(relay_response_body_.begin(),
196 relay_response_body_.end()));
197 } else {
198 ConfigReady(new cricket::PortConfiguration(stun_address_, "", ""));
202 void PepperPortAllocatorSession::SendSessionRequest(
203 const std::string& host,
204 int port) {
205 relay_url_loader_.reset(new pp::URLLoader(instance_));
206 pp::URLRequestInfo request_info(instance_);
207 std::string url = "https://" + host + ":" + base::IntToString(port) +
208 GetSessionRequestUrl() + "&sn=1";
209 request_info.SetURL(url);
210 request_info.SetMethod("GET");
211 std::stringstream headers;
212 headers << "X-Talk-Google-Relay-Auth: " << relay_token() << "\n\r";
213 headers << "X-Google-Relay-Auth: " << relay_token() << "\n\r";
214 headers << "X-Stream-Type: " << "chromoting" << "\n\r";
215 request_info.SetHeaders(headers.str());
217 int result = relay_url_loader_->Open(
218 request_info, PpCompletionCallback(base::Bind(
219 &PepperPortAllocatorSession::OnUrlOpened,
220 weak_factory_.GetWeakPtr())));
222 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
225 void PepperPortAllocatorSession::OnUrlOpened(int32_t result) {
226 if (result == PP_ERROR_ABORTED) {
227 return;
230 if (result < 0) {
231 LOG(WARNING) << "URLLoader failed: " << result;
232 // Retry creating session.
233 TryCreateRelaySession();
234 return;
237 pp::URLResponseInfo response = relay_url_loader_->GetResponseInfo();
238 DCHECK(!response.is_null());
239 if (response.GetStatusCode() != 200) {
240 LOG(WARNING) << "Received HTTP status code " << response.GetStatusCode();
241 // Retry creating session.
242 TryCreateRelaySession();
243 return;
246 relay_response_body_.clear();
247 ReadResponseBody();
250 void PepperPortAllocatorSession::ReadResponseBody() {
251 int pos = relay_response_body_.size();
252 relay_response_body_.resize(pos + kReadSize);
253 int result = relay_url_loader_->ReadResponseBody(
254 &relay_response_body_[pos], kReadSize,
255 PpCompletionCallback(base::Bind(
256 &PepperPortAllocatorSession::OnResponseBodyRead,
257 weak_factory_.GetWeakPtr())));
258 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
261 void PepperPortAllocatorSession::OnResponseBodyRead(int32_t result) {
262 if (result == PP_ERROR_ABORTED) {
263 return;
266 if (result < 0) {
267 LOG(WARNING) << "Failed to read HTTP response body when "
268 "creating relay session: " << result;
269 // Retry creating session.
270 TryCreateRelaySession();
271 return;
274 // Resize the buffer in case we've read less than was requested.
275 CHECK_LE(result, kReadSize);
276 CHECK_GE(static_cast<int>(relay_response_body_.size()), kReadSize);
277 relay_response_body_.resize(relay_response_body_.size() - kReadSize + result);
279 if (result == 0) {
280 relay_response_received_ = true;
281 ReceiveSessionResponse(std::string(relay_response_body_.begin(),
282 relay_response_body_.end()));
283 return;
286 ReadResponseBody();
289 } // namespace
291 // static
292 scoped_ptr<PepperPortAllocator> PepperPortAllocator::Create(
293 const pp::InstanceHandle& instance) {
294 scoped_ptr<talk_base::NetworkManager> network_manager(
295 new PepperNetworkManager(instance));
296 scoped_ptr<talk_base::PacketSocketFactory> socket_factory(
297 new PepperPacketSocketFactory(instance));
298 scoped_ptr<PepperPortAllocator> result(new PepperPortAllocator(
299 instance, network_manager.Pass(), socket_factory.Pass()));
300 return result.Pass();
303 PepperPortAllocator::PepperPortAllocator(
304 const pp::InstanceHandle& instance,
305 scoped_ptr<talk_base::NetworkManager> network_manager,
306 scoped_ptr<talk_base::PacketSocketFactory> socket_factory)
307 : HttpPortAllocatorBase(network_manager.get(), socket_factory.get(), ""),
308 instance_(instance),
309 network_manager_(network_manager.Pass()),
310 socket_factory_(socket_factory.Pass()) {
311 // TCP transport is disabled becase PseudoTCP works poorly over
312 // it. ENABLE_SHARED_UFRAG flag is specified so that the same
313 // username fragment is shared between all candidates for this
314 // channel.
315 set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
316 cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG);
319 PepperPortAllocator::~PepperPortAllocator() {
322 cricket::PortAllocatorSession* PepperPortAllocator::CreateSessionInternal(
323 const std::string& content_name,
324 int component,
325 const std::string& ice_username_fragment,
326 const std::string& ice_password) {
327 return new PepperPortAllocatorSession(
328 this, content_name, component, ice_username_fragment, ice_password,
329 stun_hosts(), relay_hosts(), relay_token(), instance_);
332 } // namespace remoting