Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / renderer / p2p / port_allocator.cc
blob53a71e2b8047675cd4813c550d22ee5c00c0ef95
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 "content/renderer/p2p/port_allocator.h"
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_split.h"
11 #include "base/strings/string_util.h"
12 #include "content/public/common/content_switches.h"
13 #include "net/base/escape.h"
14 #include "net/base/ip_endpoint.h"
15 #include "third_party/WebKit/public/platform/WebURLError.h"
16 #include "third_party/WebKit/public/platform/WebURLLoader.h"
17 #include "third_party/WebKit/public/platform/WebURLRequest.h"
18 #include "third_party/WebKit/public/platform/WebURLResponse.h"
19 #include "third_party/WebKit/public/web/WebFrame.h"
20 #include "third_party/WebKit/public/web/WebURLLoaderOptions.h"
22 using blink::WebString;
23 using blink::WebURL;
24 using blink::WebURLLoader;
25 using blink::WebURLLoaderOptions;
26 using blink::WebURLRequest;
27 using blink::WebURLResponse;
29 namespace content {
31 namespace {
33 // URL used to create a relay session.
34 const char kCreateRelaySessionURL[] = "/create_session";
36 // Number of times we will try to request relay session.
37 const int kRelaySessionRetries = 3;
39 // Manimum relay server size we would try to parse.
40 const int kMaximumRelayResponseSize = 102400;
42 bool ParsePortNumber(
43 const std::string& string, int* value) {
44 if (!base::StringToInt(string, value) || *value <= 0 || *value >= 65536) {
45 LOG(ERROR) << "Received invalid port number from relay server: " << string;
46 return false;
48 return true;
51 } // namespace
53 P2PPortAllocator::Config::Config()
54 : legacy_relay(true),
55 disable_tcp_transport(false) {
58 P2PPortAllocator::Config::~Config() {
61 P2PPortAllocator::Config::RelayServerConfig::RelayServerConfig()
62 : port(0) {
65 P2PPortAllocator::Config::RelayServerConfig::~RelayServerConfig() {
68 P2PPortAllocator::P2PPortAllocator(
69 blink::WebFrame* web_frame,
70 P2PSocketDispatcher* socket_dispatcher,
71 rtc::NetworkManager* network_manager,
72 rtc::PacketSocketFactory* socket_factory,
73 const Config& config)
74 : cricket::BasicPortAllocator(network_manager, socket_factory),
75 web_frame_(web_frame),
76 socket_dispatcher_(socket_dispatcher),
77 config_(config) {
78 uint32 flags = 0;
79 if (config_.disable_tcp_transport)
80 flags |= cricket::PORTALLOCATOR_DISABLE_TCP;
81 set_flags(flags);
82 set_allow_tcp_listen(false);
85 P2PPortAllocator::~P2PPortAllocator() {
88 cricket::PortAllocatorSession* P2PPortAllocator::CreateSessionInternal(
89 const std::string& content_name,
90 int component,
91 const std::string& ice_username_fragment,
92 const std::string& ice_password) {
93 return new P2PPortAllocatorSession(
94 this, content_name, component, ice_username_fragment, ice_password);
97 P2PPortAllocatorSession::P2PPortAllocatorSession(
98 P2PPortAllocator* allocator,
99 const std::string& content_name,
100 int component,
101 const std::string& ice_username_fragment,
102 const std::string& ice_password)
103 : cricket::BasicPortAllocatorSession(
104 allocator, content_name, component,
105 ice_username_fragment, ice_password),
106 allocator_(allocator),
107 relay_session_attempts_(0),
108 relay_udp_port_(0),
109 relay_tcp_port_(0),
110 relay_ssltcp_port_(0),
111 pending_relay_requests_(0) {
114 P2PPortAllocatorSession::~P2PPortAllocatorSession() {
117 void P2PPortAllocatorSession::didReceiveData(
118 WebURLLoader* loader, const char* data,
119 int data_length, int encoded_data_length) {
120 DCHECK_EQ(loader, relay_session_request_.get());
121 if (static_cast<int>(relay_session_response_.size()) + data_length >
122 kMaximumRelayResponseSize) {
123 LOG(ERROR) << "Response received from the server is too big.";
124 loader->cancel();
125 return;
127 relay_session_response_.append(data, data + data_length);
130 void P2PPortAllocatorSession::didFinishLoading(
131 WebURLLoader* loader, double finish_time,
132 int64_t total_encoded_data_length) {
133 ParseRelayResponse();
136 void P2PPortAllocatorSession::didFail(blink::WebURLLoader* loader,
137 const blink::WebURLError& error) {
138 DCHECK_EQ(loader, relay_session_request_.get());
139 DCHECK_NE(error.reason, 0);
141 LOG(ERROR) << "Relay session request failed.";
143 // Retry the request.
144 AllocateLegacyRelaySession();
147 void P2PPortAllocatorSession::GetPortConfigurations() {
148 if (allocator_->config_.legacy_relay) {
149 AllocateLegacyRelaySession();
151 AddConfig();
154 void P2PPortAllocatorSession::AllocateLegacyRelaySession() {
155 if (allocator_->config_.relays.empty())
156 return;
157 // If we are using legacy relay, we will have only one entry in relay server
158 // list.
159 P2PPortAllocator::Config::RelayServerConfig relay_config =
160 allocator_->config_.relays[0];
162 if (relay_session_attempts_ > kRelaySessionRetries)
163 return;
164 relay_session_attempts_++;
166 relay_session_response_.clear();
168 WebURLLoaderOptions options;
169 options.allowCredentials = false;
171 options.crossOriginRequestPolicy =
172 WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl;
174 relay_session_request_.reset(
175 allocator_->web_frame_->createAssociatedURLLoader(options));
176 if (!relay_session_request_) {
177 LOG(ERROR) << "Failed to create URL loader.";
178 return;
181 std::string url = "https://" + relay_config.server_address +
182 kCreateRelaySessionURL +
183 "?username=" + net::EscapeUrlEncodedData(username(), true) +
184 "&password=" + net::EscapeUrlEncodedData(password(), true);
186 WebURLRequest request;
187 request.initialize();
188 request.setURL(WebURL(GURL(url)));
189 request.setAllowStoredCredentials(false);
190 request.setCachePolicy(WebURLRequest::ReloadIgnoringCacheData);
191 request.setHTTPMethod("GET");
192 request.addHTTPHeaderField(
193 WebString::fromUTF8("X-Talk-Google-Relay-Auth"),
194 WebString::fromUTF8(relay_config.password));
195 request.addHTTPHeaderField(
196 WebString::fromUTF8("X-Google-Relay-Auth"),
197 WebString::fromUTF8(relay_config.username));
198 request.addHTTPHeaderField(WebString::fromUTF8("X-Stream-Type"),
199 WebString::fromUTF8("chromoting"));
201 relay_session_request_->loadAsynchronously(request, this);
204 void P2PPortAllocatorSession::ParseRelayResponse() {
205 std::vector<std::pair<std::string, std::string> > value_pairs;
206 if (!base::SplitStringIntoKeyValuePairs(relay_session_response_, '=', '\n',
207 &value_pairs)) {
208 LOG(ERROR) << "Received invalid response from relay server";
209 return;
212 relay_ip_.Clear();
213 relay_udp_port_ = 0;
214 relay_tcp_port_ = 0;
215 relay_ssltcp_port_ = 0;
217 for (std::vector<std::pair<std::string, std::string> >::iterator
218 it = value_pairs.begin();
219 it != value_pairs.end(); ++it) {
220 std::string key;
221 std::string value;
222 base::TrimWhitespaceASCII(it->first, base::TRIM_ALL, &key);
223 base::TrimWhitespaceASCII(it->second, base::TRIM_ALL, &value);
225 if (key == "username") {
226 if (value != username()) {
227 LOG(ERROR) << "When creating relay session received user name "
228 " that was different from the value specified in the query.";
229 return;
231 } else if (key == "password") {
232 if (value != password()) {
233 LOG(ERROR) << "When creating relay session received password "
234 "that was different from the value specified in the query.";
235 return;
237 } else if (key == "relay.ip") {
238 relay_ip_.SetIP(value);
239 if (relay_ip_.ip() == 0) {
240 LOG(ERROR) << "Received unresolved relay server address: " << value;
241 return;
243 } else if (key == "relay.udp_port") {
244 if (!ParsePortNumber(value, &relay_udp_port_))
245 return;
246 } else if (key == "relay.tcp_port") {
247 if (!ParsePortNumber(value, &relay_tcp_port_))
248 return;
249 } else if (key == "relay.ssltcp_port") {
250 if (!ParsePortNumber(value, &relay_ssltcp_port_))
251 return;
255 AddConfig();
258 void P2PPortAllocatorSession::AddConfig() {
259 const P2PPortAllocator::Config& config = allocator_->config_;
260 cricket::PortConfiguration* port_config = new cricket::PortConfiguration(
261 config.stun_servers, std::string(), std::string());
263 for (size_t i = 0; i < config.relays.size(); ++i) {
264 cricket::RelayCredentials credentials(config.relays[i].username,
265 config.relays[i].password);
266 cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
267 cricket::ProtocolType protocol;
268 if (!cricket::StringToProto(config.relays[i].transport_type.c_str(),
269 &protocol)) {
270 DLOG(WARNING) << "Ignoring TURN server "
271 << config.relays[i].server_address << ". "
272 << "Reason= Incorrect "
273 << config.relays[i].transport_type
274 << " transport parameter.";
275 continue;
278 relay_server.ports.push_back(cricket::ProtocolAddress(
279 rtc::SocketAddress(config.relays[i].server_address,
280 config.relays[i].port),
281 protocol,
282 config.relays[i].secure));
283 relay_server.credentials = credentials;
284 port_config->AddRelay(relay_server);
286 ConfigReady(port_config);
289 } // namespace content