Update parsing of dumpsys batterystats
[chromium-blink-merge.git] / remoting / client / plugin / pepper_port_allocator.cc
blobe0d0b4037f2c7c1db1247cebe07f39101549955f
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/strings/string_number_conversions.h"
9 #include "net/base/net_util.h"
10 #include "ppapi/c/pp_errors.h"
11 #include "ppapi/cpp/host_resolver.h"
12 #include "ppapi/cpp/net_address.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 "ppapi/utility/completion_callback_factory.h"
17 #include "remoting/client/plugin/pepper_network_manager.h"
18 #include "remoting/client/plugin/pepper_packet_socket_factory.h"
19 #include "remoting/client/plugin/pepper_util.h"
21 namespace remoting {
23 namespace {
25 // Read buffer we allocate per read when reading response from
26 // URLLoader. Normally the response from URL loader is smaller than 1kB.
27 const int kReadSize = 1024;
29 class PepperPortAllocatorSession
30 : public cricket::HttpPortAllocatorSessionBase {
31 public:
32 PepperPortAllocatorSession(
33 cricket::HttpPortAllocatorBase* allocator,
34 const std::string& content_name,
35 int component,
36 const std::string& ice_username_fragment,
37 const std::string& ice_password,
38 const std::vector<talk_base::SocketAddress>& stun_hosts,
39 const std::vector<std::string>& relay_hosts,
40 const std::string& relay_token,
41 const pp::InstanceHandle& instance);
42 virtual ~PepperPortAllocatorSession();
44 // cricket::HttpPortAllocatorBase overrides.
45 virtual void ConfigReady(cricket::PortConfiguration* config) OVERRIDE;
46 virtual void GetPortConfigurations() OVERRIDE;
47 virtual void SendSessionRequest(const std::string& host, int port) OVERRIDE;
49 private:
50 void ResolveStunServerAddress();
51 void OnStunAddressResolved(int32_t result);
53 void OnUrlOpened(int32_t result);
54 void ReadResponseBody();
55 void OnResponseBodyRead(int32_t result);
57 pp::InstanceHandle instance_;
59 pp::HostResolver stun_address_resolver_;
60 talk_base::SocketAddress stun_address_;
61 int stun_port_;
63 scoped_ptr<pp::URLLoader> relay_url_loader_;
64 std::vector<char> relay_response_body_;
65 bool relay_response_received_;
67 pp::CompletionCallbackFactory<PepperPortAllocatorSession> callback_factory_;
69 DISALLOW_COPY_AND_ASSIGN(PepperPortAllocatorSession);
72 PepperPortAllocatorSession::PepperPortAllocatorSession(
73 cricket::HttpPortAllocatorBase* allocator,
74 const std::string& content_name,
75 int component,
76 const std::string& ice_username_fragment,
77 const std::string& ice_password,
78 const std::vector<talk_base::SocketAddress>& stun_hosts,
79 const std::vector<std::string>& relay_hosts,
80 const std::string& relay_token,
81 const pp::InstanceHandle& instance)
82 : HttpPortAllocatorSessionBase(allocator,
83 content_name,
84 component,
85 ice_username_fragment,
86 ice_password,
87 stun_hosts,
88 relay_hosts,
89 relay_token,
90 std::string()),
91 instance_(instance),
92 stun_address_resolver_(instance_),
93 stun_port_(0),
94 relay_response_received_(false),
95 callback_factory_(this) {
96 if (stun_hosts.size() > 0) {
97 stun_address_ = stun_hosts[0];
101 PepperPortAllocatorSession::~PepperPortAllocatorSession() {
104 void PepperPortAllocatorSession::ConfigReady(
105 cricket::PortConfiguration* config) {
106 if (config->stun_address.IsUnresolved()) {
107 // Make sure that the address that we pass to ConfigReady() is
108 // always resolved.
109 if (stun_address_.IsUnresolved()) {
110 config->stun_address.Clear();
111 } else {
112 config->stun_address = stun_address_;
116 // Filter out non-UDP relay ports, so that we don't try using TCP.
117 for (cricket::PortConfiguration::RelayList::iterator relay =
118 config->relays.begin(); relay != config->relays.end(); ++relay) {
119 cricket::PortList filtered_ports;
120 for (cricket::PortList::iterator port =
121 relay->ports.begin(); port != relay->ports.end(); ++port) {
122 if (port->proto == cricket::PROTO_UDP) {
123 filtered_ports.push_back(*port);
126 relay->ports = filtered_ports;
128 cricket::BasicPortAllocatorSession::ConfigReady(config);
131 void PepperPortAllocatorSession::GetPortConfigurations() {
132 // Add an empty configuration synchronously, so a local connection
133 // can be started immediately.
134 ConfigReady(new cricket::PortConfiguration(
135 talk_base::SocketAddress(), std::string(), std::string()));
137 ResolveStunServerAddress();
138 TryCreateRelaySession();
141 void PepperPortAllocatorSession::ResolveStunServerAddress() {
142 if (stun_address_.IsNil()) {
143 return;
146 if (!stun_address_.IsUnresolved()) {
147 return;
150 std::string hostname = stun_address_.hostname();
151 uint16 port = stun_address_.port();
153 PP_HostResolver_Hint hint;
154 hint.flags = 0;
155 hint.family = PP_NETADDRESS_FAMILY_IPV4;
156 pp::CompletionCallback callback = callback_factory_.NewCallback(
157 &PepperPortAllocatorSession::OnStunAddressResolved);
158 int result = stun_address_resolver_.Resolve(hostname.c_str(),
159 port,
160 hint,
161 callback);
162 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
165 void PepperPortAllocatorSession::OnStunAddressResolved(int32_t result) {
166 if (result < 0) {
167 LOG(ERROR) << "Failed to resolve stun address "
168 << stun_address_.hostname() << ": " << result;
169 return;
172 if (!stun_address_resolver_.GetNetAddressCount()) {
173 LOG(WARNING) << "Received 0 addresses for stun server "
174 << stun_address_.hostname();
175 return;
178 pp::NetAddress address = stun_address_resolver_.GetNetAddress(0);
179 if (address.is_null()) {
180 LOG(ERROR) << "Failed to get address for STUN server "
181 << stun_address_.hostname();
182 return;
185 PpNetAddressToSocketAddress(address, &stun_address_);
186 DCHECK(!stun_address_.IsUnresolved());
188 if (relay_response_received_) {
189 // If we've finished reading the response, then resubmit it to
190 // HttpPortAllocatorSessionBase. This is necessary because STUN
191 // and Relay parameters are stored together in PortConfiguration
192 // and ReceiveSessionResponse() doesn't save relay session
193 // configuration for the case we resolve STUN address later. This
194 // method invokes overriden ConfigReady() which then submits
195 // resolved |stun_address_|.
197 // TODO(sergeyu): Refactor HttpPortAllocatorSessionBase to fix this.
198 ReceiveSessionResponse(std::string(relay_response_body_.begin(),
199 relay_response_body_.end()));
200 } else {
201 ConfigReady(new cricket::PortConfiguration(
202 stun_address_, std::string(), std::string()));
206 void PepperPortAllocatorSession::SendSessionRequest(
207 const std::string& host,
208 int port) {
209 relay_url_loader_.reset(new pp::URLLoader(instance_));
210 pp::URLRequestInfo request_info(instance_);
211 std::string url = "https://" + host + ":" + base::IntToString(port) +
212 GetSessionRequestUrl() + "&sn=1";
213 request_info.SetURL(url);
214 request_info.SetMethod("GET");
215 std::stringstream headers;
216 headers << "X-Talk-Google-Relay-Auth: " << relay_token() << "\n\r";
217 headers << "X-Google-Relay-Auth: " << relay_token() << "\n\r";
218 headers << "X-Stream-Type: " << "chromoting" << "\n\r";
219 request_info.SetHeaders(headers.str());
221 pp::CompletionCallback callback =
222 callback_factory_.NewCallback(&PepperPortAllocatorSession::OnUrlOpened);
223 int result = relay_url_loader_->Open(request_info, callback);
224 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
227 void PepperPortAllocatorSession::OnUrlOpened(int32_t result) {
228 if (result == PP_ERROR_ABORTED) {
229 return;
232 if (result < 0) {
233 LOG(WARNING) << "URLLoader failed: " << result;
234 // Retry creating session.
235 TryCreateRelaySession();
236 return;
239 pp::URLResponseInfo response = relay_url_loader_->GetResponseInfo();
240 DCHECK(!response.is_null());
241 if (response.GetStatusCode() != 200) {
242 LOG(WARNING) << "Received HTTP status code " << response.GetStatusCode();
243 // Retry creating session.
244 TryCreateRelaySession();
245 return;
248 relay_response_body_.clear();
249 ReadResponseBody();
252 void PepperPortAllocatorSession::ReadResponseBody() {
253 int pos = relay_response_body_.size();
254 relay_response_body_.resize(pos + kReadSize);
255 pp::CompletionCallback callback = callback_factory_.NewCallback(
256 &PepperPortAllocatorSession::OnResponseBodyRead);
257 int result = relay_url_loader_->ReadResponseBody(&relay_response_body_[pos],
258 kReadSize,
259 callback);
260 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
263 void PepperPortAllocatorSession::OnResponseBodyRead(int32_t result) {
264 if (result == PP_ERROR_ABORTED) {
265 return;
268 if (result < 0) {
269 LOG(WARNING) << "Failed to read HTTP response body when "
270 "creating relay session: " << result;
271 // Retry creating session.
272 TryCreateRelaySession();
273 return;
276 // Resize the buffer in case we've read less than was requested.
277 CHECK_LE(result, kReadSize);
278 CHECK_GE(static_cast<int>(relay_response_body_.size()), kReadSize);
279 relay_response_body_.resize(relay_response_body_.size() - kReadSize + result);
281 if (result == 0) {
282 relay_response_received_ = true;
283 ReceiveSessionResponse(std::string(relay_response_body_.begin(),
284 relay_response_body_.end()));
285 return;
288 ReadResponseBody();
291 } // namespace
293 // static
294 scoped_ptr<PepperPortAllocator> PepperPortAllocator::Create(
295 const pp::InstanceHandle& instance) {
296 scoped_ptr<talk_base::NetworkManager> network_manager(
297 new PepperNetworkManager(instance));
298 scoped_ptr<talk_base::PacketSocketFactory> socket_factory(
299 new PepperPacketSocketFactory(instance));
300 scoped_ptr<PepperPortAllocator> result(new PepperPortAllocator(
301 instance, network_manager.Pass(), socket_factory.Pass()));
302 return result.Pass();
305 PepperPortAllocator::PepperPortAllocator(
306 const pp::InstanceHandle& instance,
307 scoped_ptr<talk_base::NetworkManager> network_manager,
308 scoped_ptr<talk_base::PacketSocketFactory> socket_factory)
309 : HttpPortAllocatorBase(network_manager.get(),
310 socket_factory.get(),
311 std::string()),
312 instance_(instance),
313 network_manager_(network_manager.Pass()),
314 socket_factory_(socket_factory.Pass()) {
315 // TCP transport is disabled becase PseudoTCP works poorly over
316 // it. ENABLE_SHARED_UFRAG flag is specified so that the same
317 // username fragment is shared between all candidates for this
318 // channel.
319 set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
320 cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG|
321 cricket::PORTALLOCATOR_ENABLE_IPV6);
324 PepperPortAllocator::~PepperPortAllocator() {
327 cricket::PortAllocatorSession* PepperPortAllocator::CreateSessionInternal(
328 const std::string& content_name,
329 int component,
330 const std::string& ice_username_fragment,
331 const std::string& ice_password) {
332 return new PepperPortAllocatorSession(
333 this, content_name, component, ice_username_fragment, ice_password,
334 stun_hosts(), relay_hosts(), relay_token(), instance_);
337 } // namespace remoting