Revert "Update webrtc&libjingle 6774:6799."
[chromium-blink-merge.git] / content / renderer / p2p / port_allocator.cc
blob61cfefd4901a61f6d738e1e33e7de3c05548867b
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 : stun_server_port(0),
55 legacy_relay(true),
56 disable_tcp_transport(false) {
59 P2PPortAllocator::Config::~Config() {
62 P2PPortAllocator::Config::RelayServerConfig::RelayServerConfig()
63 : port(0) {
66 P2PPortAllocator::Config::RelayServerConfig::~RelayServerConfig() {
69 P2PPortAllocator::P2PPortAllocator(
70 blink::WebFrame* web_frame,
71 P2PSocketDispatcher* socket_dispatcher,
72 talk_base::NetworkManager* network_manager,
73 talk_base::PacketSocketFactory* socket_factory,
74 const Config& config)
75 : cricket::BasicPortAllocator(network_manager, socket_factory),
76 web_frame_(web_frame),
77 socket_dispatcher_(socket_dispatcher),
78 config_(config) {
79 uint32 flags = 0;
80 if (config_.disable_tcp_transport)
81 flags |= cricket::PORTALLOCATOR_DISABLE_TCP;
82 set_flags(flags);
83 set_allow_tcp_listen(false);
86 P2PPortAllocator::~P2PPortAllocator() {
89 cricket::PortAllocatorSession* P2PPortAllocator::CreateSessionInternal(
90 const std::string& content_name,
91 int component,
92 const std::string& ice_username_fragment,
93 const std::string& ice_password) {
94 return new P2PPortAllocatorSession(
95 this, content_name, component, ice_username_fragment, ice_password);
98 P2PPortAllocatorSession::P2PPortAllocatorSession(
99 P2PPortAllocator* allocator,
100 const std::string& content_name,
101 int component,
102 const std::string& ice_username_fragment,
103 const std::string& ice_password)
104 : cricket::BasicPortAllocatorSession(
105 allocator, content_name, component,
106 ice_username_fragment, ice_password),
107 allocator_(allocator),
108 relay_session_attempts_(0),
109 relay_udp_port_(0),
110 relay_tcp_port_(0),
111 relay_ssltcp_port_(0),
112 pending_relay_requests_(0) {
115 P2PPortAllocatorSession::~P2PPortAllocatorSession() {
118 void P2PPortAllocatorSession::didReceiveData(
119 WebURLLoader* loader, const char* data,
120 int data_length, int encoded_data_length) {
121 DCHECK_EQ(loader, relay_session_request_.get());
122 if (static_cast<int>(relay_session_response_.size()) + data_length >
123 kMaximumRelayResponseSize) {
124 LOG(ERROR) << "Response received from the server is too big.";
125 loader->cancel();
126 return;
128 relay_session_response_.append(data, data + data_length);
131 void P2PPortAllocatorSession::didFinishLoading(
132 WebURLLoader* loader, double finish_time,
133 int64_t total_encoded_data_length) {
134 ParseRelayResponse();
137 void P2PPortAllocatorSession::didFail(blink::WebURLLoader* loader,
138 const blink::WebURLError& error) {
139 DCHECK_EQ(loader, relay_session_request_.get());
140 DCHECK_NE(error.reason, 0);
142 LOG(ERROR) << "Relay session request failed.";
144 // Retry the request.
145 AllocateLegacyRelaySession();
148 void P2PPortAllocatorSession::GetPortConfigurations() {
149 if (allocator_->config_.legacy_relay) {
150 AllocateLegacyRelaySession();
152 AddConfig();
155 void P2PPortAllocatorSession::AllocateLegacyRelaySession() {
156 if (allocator_->config_.relays.empty())
157 return;
158 // If we are using legacy relay, we will have only one entry in relay server
159 // list.
160 P2PPortAllocator::Config::RelayServerConfig relay_config =
161 allocator_->config_.relays[0];
163 if (relay_session_attempts_ > kRelaySessionRetries)
164 return;
165 relay_session_attempts_++;
167 relay_session_response_.clear();
169 WebURLLoaderOptions options;
170 options.allowCredentials = false;
172 options.crossOriginRequestPolicy =
173 WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl;
175 relay_session_request_.reset(
176 allocator_->web_frame_->createAssociatedURLLoader(options));
177 if (!relay_session_request_) {
178 LOG(ERROR) << "Failed to create URL loader.";
179 return;
182 std::string url = "https://" + relay_config.server_address +
183 kCreateRelaySessionURL +
184 "?username=" + net::EscapeUrlEncodedData(username(), true) +
185 "&password=" + net::EscapeUrlEncodedData(password(), true);
187 WebURLRequest request;
188 request.initialize();
189 request.setURL(WebURL(GURL(url)));
190 request.setAllowStoredCredentials(false);
191 request.setCachePolicy(WebURLRequest::ReloadIgnoringCacheData);
192 request.setHTTPMethod("GET");
193 request.addHTTPHeaderField(
194 WebString::fromUTF8("X-Talk-Google-Relay-Auth"),
195 WebString::fromUTF8(relay_config.password));
196 request.addHTTPHeaderField(
197 WebString::fromUTF8("X-Google-Relay-Auth"),
198 WebString::fromUTF8(relay_config.username));
199 request.addHTTPHeaderField(WebString::fromUTF8("X-Stream-Type"),
200 WebString::fromUTF8("chromoting"));
202 relay_session_request_->loadAsynchronously(request, this);
205 void P2PPortAllocatorSession::ParseRelayResponse() {
206 std::vector<std::pair<std::string, std::string> > value_pairs;
207 if (!base::SplitStringIntoKeyValuePairs(relay_session_response_, '=', '\n',
208 &value_pairs)) {
209 LOG(ERROR) << "Received invalid response from relay server";
210 return;
213 relay_ip_.Clear();
214 relay_udp_port_ = 0;
215 relay_tcp_port_ = 0;
216 relay_ssltcp_port_ = 0;
218 for (std::vector<std::pair<std::string, std::string> >::iterator
219 it = value_pairs.begin();
220 it != value_pairs.end(); ++it) {
221 std::string key;
222 std::string value;
223 base::TrimWhitespaceASCII(it->first, base::TRIM_ALL, &key);
224 base::TrimWhitespaceASCII(it->second, base::TRIM_ALL, &value);
226 if (key == "username") {
227 if (value != username()) {
228 LOG(ERROR) << "When creating relay session received user name "
229 " that was different from the value specified in the query.";
230 return;
232 } else if (key == "password") {
233 if (value != password()) {
234 LOG(ERROR) << "When creating relay session received password "
235 "that was different from the value specified in the query.";
236 return;
238 } else if (key == "relay.ip") {
239 relay_ip_.SetIP(value);
240 if (relay_ip_.ip() == 0) {
241 LOG(ERROR) << "Received unresolved relay server address: " << value;
242 return;
244 } else if (key == "relay.udp_port") {
245 if (!ParsePortNumber(value, &relay_udp_port_))
246 return;
247 } else if (key == "relay.tcp_port") {
248 if (!ParsePortNumber(value, &relay_tcp_port_))
249 return;
250 } else if (key == "relay.ssltcp_port") {
251 if (!ParsePortNumber(value, &relay_ssltcp_port_))
252 return;
256 AddConfig();
259 void P2PPortAllocatorSession::AddConfig() {
260 const P2PPortAllocator::Config& config = allocator_->config_;
261 cricket::PortConfiguration* port_config = new cricket::PortConfiguration(
262 talk_base::SocketAddress(config.stun_server, config.stun_server_port),
263 std::string(), std::string());
265 for (size_t i = 0; i < config.relays.size(); ++i) {
266 cricket::RelayCredentials credentials(config.relays[i].username,
267 config.relays[i].password);
268 cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
269 cricket::ProtocolType protocol;
270 if (!cricket::StringToProto(config.relays[i].transport_type.c_str(),
271 &protocol)) {
272 DLOG(WARNING) << "Ignoring TURN server "
273 << config.relays[i].server_address << ". "
274 << "Reason= Incorrect "
275 << config.relays[i].transport_type
276 << " transport parameter.";
277 continue;
280 relay_server.ports.push_back(cricket::ProtocolAddress(
281 talk_base::SocketAddress(config.relays[i].server_address,
282 config.relays[i].port),
283 protocol,
284 config.relays[i].secure));
285 relay_server.credentials = credentials;
286 port_config->AddRelay(relay_server);
288 ConfigReady(port_config);
291 } // namespace content