| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 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. | |
| 4 | |
| 5 #include "remoting/protocol/port_allocator_base.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <map> | |
| 9 | |
| 10 #include "base/bind.h" | |
| 11 #include "base/logging.h" | |
| 12 #include "base/strings/string_number_conversions.h" | |
| 13 #include "base/strings/string_split.h" | |
| 14 #include "net/base/escape.h" | |
| 15 #include "remoting/protocol/network_settings.h" | |
| 16 #include "remoting/protocol/transport_context.h" | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 typedef std::map<std::string, std::string> StringMap; | |
| 21 | |
| 22 // Parses the lines in the result of the HTTP request that are of the form | |
| 23 // 'a=b' and returns them in a map. | |
| 24 StringMap ParseMap(const std::string& string) { | |
| 25 StringMap map; | |
| 26 base::StringPairs pairs; | |
| 27 base::SplitStringIntoKeyValuePairs(string, '=', '\n', &pairs); | |
| 28 | |
| 29 for (auto& pair : pairs) { | |
| 30 map[pair.first] = pair.second; | |
| 31 } | |
| 32 return map; | |
| 33 } | |
| 34 | |
| 35 } // namespace | |
| 36 | |
| 37 namespace remoting { | |
| 38 namespace protocol { | |
| 39 | |
| 40 const int PortAllocatorBase::kNumRetries = 5; | |
| 41 | |
| 42 PortAllocatorBase::PortAllocatorBase( | |
| 43 scoped_ptr<rtc::NetworkManager> network_manager, | |
| 44 scoped_ptr<rtc::PacketSocketFactory> socket_factory, | |
| 45 scoped_refptr<TransportContext> transport_context) | |
| 46 : BasicPortAllocator(network_manager.get(), socket_factory.get()), | |
| 47 network_manager_(std::move(network_manager)), | |
| 48 socket_factory_(std::move(socket_factory)), | |
| 49 transport_context_(transport_context) { | |
| 50 // We always use PseudoTcp to provide a reliable channel. It provides poor | |
| 51 // performance when combined with TCP-based transport, so we have to disable | |
| 52 // TCP ports. ENABLE_SHARED_UFRAG flag is specified so that the same username | |
| 53 // fragment is shared between all candidates. | |
| 54 int flags = cricket::PORTALLOCATOR_DISABLE_TCP | | |
| 55 cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG | | |
| 56 cricket::PORTALLOCATOR_ENABLE_IPV6; | |
| 57 | |
| 58 NetworkSettings network_settings = transport_context_->network_settings(); | |
| 59 | |
| 60 if (!(network_settings.flags & NetworkSettings::NAT_TRAVERSAL_STUN)) | |
| 61 flags |= cricket::PORTALLOCATOR_DISABLE_STUN; | |
| 62 | |
| 63 if (!(network_settings.flags & NetworkSettings::NAT_TRAVERSAL_RELAY)) | |
| 64 flags |= cricket::PORTALLOCATOR_DISABLE_RELAY; | |
| 65 | |
| 66 set_flags(flags); | |
| 67 SetPortRange(network_settings.port_range.min_port, | |
| 68 network_settings.port_range.max_port); | |
| 69 } | |
| 70 | |
| 71 PortAllocatorBase::~PortAllocatorBase() {} | |
| 72 | |
| 73 PortAllocatorSessionBase::PortAllocatorSessionBase( | |
| 74 PortAllocatorBase* allocator, | |
| 75 const std::string& content_name, | |
| 76 int component, | |
| 77 const std::string& ice_ufrag, | |
| 78 const std::string& ice_pwd) | |
| 79 : BasicPortAllocatorSession(allocator, | |
| 80 content_name, | |
| 81 component, | |
| 82 ice_ufrag, | |
| 83 ice_pwd), | |
| 84 transport_context_(allocator->transport_context()), | |
| 85 weak_factory_(this) {} | |
| 86 | |
| 87 PortAllocatorSessionBase::~PortAllocatorSessionBase() {} | |
| 88 | |
| 89 void PortAllocatorSessionBase::GetPortConfigurations() { | |
| 90 transport_context_->GetJingleInfo(base::Bind( | |
| 91 &PortAllocatorSessionBase::OnJingleInfo, weak_factory_.GetWeakPtr())); | |
| 92 } | |
| 93 | |
| 94 void PortAllocatorSessionBase::OnJingleInfo( | |
| 95 std::vector<rtc::SocketAddress> stun_hosts, | |
| 96 std::vector<std::string> relay_hosts, | |
| 97 std::string relay_token) { | |
| 98 stun_hosts_ = stun_hosts; | |
| 99 relay_hosts_ = relay_hosts; | |
| 100 relay_token_ = relay_token; | |
| 101 | |
| 102 // Creating relay sessions can take time and is done asynchronously. | |
| 103 // Creating stun sessions could also take time and could be done aysnc also, | |
| 104 // but for now is done here and added to the initial config. Note any later | |
| 105 // configs will have unresolved stun ips and will be discarded by the | |
| 106 // AllocationSequence. | |
| 107 cricket::ServerAddresses hosts; | |
| 108 for (const auto& host : stun_hosts_) { | |
| 109 hosts.insert(host); | |
| 110 } | |
| 111 | |
| 112 cricket::PortConfiguration* config = | |
| 113 new cricket::PortConfiguration(hosts, username(), password()); | |
| 114 ConfigReady(config); | |
| 115 TryCreateRelaySession(); | |
| 116 } | |
| 117 | |
| 118 void PortAllocatorSessionBase::TryCreateRelaySession() { | |
| 119 if (flags() & cricket::PORTALLOCATOR_DISABLE_RELAY) | |
| 120 return; | |
| 121 | |
| 122 if (attempts_ == PortAllocatorBase::kNumRetries) { | |
| 123 LOG(ERROR) << "PortAllocator: maximum number of requests reached; " | |
| 124 << "giving up on relay."; | |
| 125 return; | |
| 126 } | |
| 127 | |
| 128 if (relay_hosts_.empty()) { | |
| 129 LOG(ERROR) << "PortAllocator: no relay hosts configured."; | |
| 130 return; | |
| 131 } | |
| 132 | |
| 133 if (relay_token_.empty()){ | |
| 134 LOG(WARNING) << "No relay auth token found."; | |
| 135 return; | |
| 136 } | |
| 137 | |
| 138 // Choose the next host to try. | |
| 139 std::string host = relay_hosts_[attempts_ % relay_hosts_.size()]; | |
| 140 attempts_++; | |
| 141 SendSessionRequest(host); | |
| 142 } | |
| 143 | |
| 144 std::string PortAllocatorSessionBase::GetSessionRequestUrl() { | |
| 145 ASSERT(!username().empty()); | |
| 146 ASSERT(!password().empty()); | |
| 147 return "/create_session?username=" + | |
| 148 net::EscapeUrlEncodedData(username(), false) + "&password=" + | |
| 149 net::EscapeUrlEncodedData(password(), false); | |
| 150 } | |
| 151 | |
| 152 void PortAllocatorSessionBase::ReceiveSessionResponse( | |
| 153 const std::string& response) { | |
| 154 StringMap map = ParseMap(response); | |
| 155 | |
| 156 if (!username().empty() && map["username"] != username()) { | |
| 157 LOG(WARNING) << "Received unexpected username value from relay server."; | |
| 158 } | |
| 159 if (!password().empty() && map["password"] != password()) { | |
| 160 LOG(WARNING) << "Received unexpected password value from relay server."; | |
| 161 } | |
| 162 | |
| 163 cricket::ServerAddresses hosts; | |
| 164 for (const auto& host : stun_hosts_) { | |
| 165 hosts.insert(host); | |
| 166 } | |
| 167 | |
| 168 cricket::PortConfiguration* config = | |
| 169 new cricket::PortConfiguration(hosts, map["username"], map["password"]); | |
| 170 | |
| 171 std::string relay_ip = map["relay.ip"]; | |
| 172 std::string relay_port = map["relay.udp_port"]; | |
| 173 unsigned relay_port_int; | |
| 174 | |
| 175 if (!relay_ip.empty() && !relay_port.empty() && | |
| 176 base::StringToUint(relay_port, &relay_port_int)) { | |
| 177 cricket::RelayServerConfig relay_config(cricket::RELAY_GTURN); | |
| 178 rtc::SocketAddress address(relay_ip, relay_port_int); | |
| 179 relay_config.ports.push_back( | |
| 180 cricket::ProtocolAddress(address, cricket::PROTO_UDP)); | |
| 181 config->AddRelay(relay_config); | |
| 182 } | |
| 183 | |
| 184 ConfigReady(config); | |
| 185 } | |
| 186 | |
| 187 } // namespace protocol | |
| 188 } // namespace remoting | |
| OLD | NEW |