candidate.cc (10617B)
1 /* 2 * Copyright 2017 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "api/candidate.h" 12 13 #include <algorithm> // IWYU pragma: keep 14 #include <cstdint> 15 #include <string> 16 17 #include "absl/strings/str_cat.h" 18 #include "absl/strings/string_view.h" 19 #include "p2p/base/p2p_constants.h" 20 #include "rtc_base/checks.h" 21 #include "rtc_base/crc32.h" 22 #include "rtc_base/crypto_random.h" 23 #include "rtc_base/ip_address.h" 24 #include "rtc_base/network_constants.h" 25 #include "rtc_base/socket_address.h" 26 #include "rtc_base/strings/string_builder.h" 27 28 using webrtc::IceCandidateType; 29 30 namespace webrtc { 31 absl::string_view IceCandidateTypeToString(IceCandidateType type) { 32 switch (type) { 33 case IceCandidateType::kHost: 34 return "host"; 35 case IceCandidateType::kSrflx: 36 return "srflx"; 37 case IceCandidateType::kPrflx: 38 return "prflx"; 39 case IceCandidateType::kRelay: 40 return "relay"; 41 } 42 } 43 } // namespace webrtc 44 45 namespace webrtc { 46 47 Candidate::Candidate() 48 : id_(CreateRandomString(8)), 49 component_(ICE_CANDIDATE_COMPONENT_DEFAULT), 50 priority_(0), 51 network_type_(ADAPTER_TYPE_UNKNOWN), 52 underlying_type_for_vpn_(ADAPTER_TYPE_UNKNOWN), 53 generation_(0), 54 network_id_(0), 55 network_cost_(0) {} 56 57 Candidate::Candidate(int component, 58 absl::string_view protocol, 59 const SocketAddress& address, 60 uint32_t priority, 61 absl::string_view username, 62 absl::string_view password, 63 IceCandidateType type, 64 uint32_t generation, 65 absl::string_view foundation, 66 uint16_t network_id /*= 0*/, 67 uint16_t network_cost /*= 0*/) 68 : id_(CreateRandomString(8)), 69 component_(component), 70 protocol_(protocol), 71 address_(address), 72 priority_(priority), 73 username_(username), 74 password_(password), 75 type_(type), 76 network_type_(ADAPTER_TYPE_UNKNOWN), 77 underlying_type_for_vpn_(ADAPTER_TYPE_UNKNOWN), 78 generation_(generation), 79 foundation_(foundation), 80 network_id_(network_id), 81 network_cost_(network_cost) {} 82 83 Candidate::Candidate(const Candidate&) = default; 84 85 Candidate::~Candidate() = default; 86 87 void Candidate::generate_id() { 88 id_ = CreateRandomString(8); 89 } 90 91 bool Candidate::is_local() const { 92 return type_ == IceCandidateType::kHost; 93 } 94 bool Candidate::is_stun() const { 95 return type_ == IceCandidateType::kSrflx; 96 } 97 bool Candidate::is_prflx() const { 98 return type_ == IceCandidateType::kPrflx; 99 } 100 bool Candidate::is_relay() const { 101 return type_ == IceCandidateType::kRelay; 102 } 103 104 absl::string_view Candidate::type_name() const { 105 return IceCandidateTypeToString(type_); 106 } 107 108 bool Candidate::IsEquivalent(const Candidate& c) const { 109 // We ignore the network name, since that is just debug information, and 110 // the priority and the network cost, since they should be the same if the 111 // rest are. 112 return (component_ == c.component_) && (protocol_ == c.protocol_) && 113 (address_ == c.address_) && (username_ == c.username_) && 114 (password_ == c.password_) && (type_ == c.type_) && 115 (generation_ == c.generation_) && (foundation_ == c.foundation_) && 116 (related_address_ == c.related_address_) && 117 (network_id_ == c.network_id_); 118 } 119 120 bool Candidate::MatchesForRemoval(const Candidate& c) const { 121 return component_ == c.component_ && protocol_ == c.protocol_ && 122 address_ == c.address_; 123 } 124 125 std::string Candidate::ToStringInternal(bool sensitive) const { 126 StringBuilder ost; 127 std::string address = 128 sensitive ? address_.ToSensitiveString() : address_.ToString(); 129 std::string related_address = sensitive ? related_address_.ToSensitiveString() 130 : related_address_.ToString(); 131 ost << "Cand[:" << foundation_ << ":" << component_ << ":" << protocol_ << ":" 132 << priority_ << ":" << address << ":" << type_name() << ":" 133 << related_address << ":" << username_ << ":" << password_ << ":" 134 << network_id_ << ":" << network_cost_ << ":" << generation_ << "]"; 135 return ost.Release(); 136 } 137 138 uint32_t Candidate::GetPriority(uint32_t type_preference, 139 int network_adapter_preference, 140 int relay_preference, 141 bool adjust_local_preference) const { 142 // RFC 5245 - 4.1.2.1. 143 // priority = (2^24)*(type preference) + 144 // (2^8)*(local preference) + 145 // (2^0)*(256 - component ID) 146 147 // `local_preference` length is 2 bytes, 0-65535 inclusive. 148 // In our implemenation we will partion local_preference into 149 // 0 1 150 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 151 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 152 // | NIC Pref | Addr Pref | 153 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 154 // NIC Type - Type of the network adapter e.g. 3G/Wifi/Wired. 155 // Addr Pref - Address preference value as per RFC 3484. 156 // local preference = (NIC Type << 8 | Addr_Pref) + relay preference. 157 // The relay preference is based on the number of TURN servers, the 158 // first TURN server gets the highest preference. 159 int addr_pref = IPAddressPrecedence(address_.ipaddr()); 160 int local_preference = 161 ((network_adapter_preference << 8) | addr_pref) + relay_preference; 162 163 // Ensure that the added relay preference will not result in a relay candidate 164 // whose STUN priority attribute has a higher priority than a server-reflexive 165 // candidate. 166 // The STUN priority attribute is calculated as 167 // (peer-reflexive type preference) << 24 | (priority & 0x00FFFFFF) 168 // as described in 169 // https://www.rfc-editor.org/rfc/rfc5245#section-7.1.2.1 170 // To satisfy that condition, add kMaxTurnServers to the local preference. 171 // This can not overflow the field width since the highest "NIC pref" 172 // assigned is kHighestNetworkPreference = 127 173 RTC_DCHECK_LT(local_preference + kMaxTurnServers, 0x10000); 174 if (adjust_local_preference && relay_protocol_.empty()) { 175 local_preference += kMaxTurnServers; 176 } 177 178 return (type_preference << 24) | (local_preference << 8) | (256 - component_); 179 } 180 181 bool Candidate::operator==(const Candidate& o) const { 182 return id_ == o.id_ && component_ == o.component_ && 183 protocol_ == o.protocol_ && relay_protocol_ == o.relay_protocol_ && 184 address_ == o.address_ && priority_ == o.priority_ && 185 username_ == o.username_ && password_ == o.password_ && 186 type_ == o.type_ && network_name_ == o.network_name_ && 187 network_type_ == o.network_type_ && generation_ == o.generation_ && 188 foundation_ == o.foundation_ && 189 related_address_ == o.related_address_ && tcptype_ == o.tcptype_ && 190 network_id_ == o.network_id_; 191 } 192 193 bool Candidate::operator!=(const Candidate& o) const { 194 return !(*this == o); 195 } 196 197 Candidate Candidate::ToSanitizedCopy(bool use_hostname_address, 198 bool filter_related_address) const { 199 return ToSanitizedCopy(use_hostname_address, filter_related_address, false); 200 } 201 202 Candidate Candidate::ToSanitizedCopy(bool use_hostname_address, 203 bool filter_related_address, 204 bool filter_ufrag) const { 205 Candidate copy(*this); 206 if (use_hostname_address) { 207 IPAddress ip; 208 if (address().hostname().empty()) { 209 // IP needs to be redacted, but no hostname available. 210 SocketAddress redacted_addr("redacted-ip.invalid", address().port()); 211 copy.set_address(redacted_addr); 212 } else if (IPFromString(address().hostname(), &ip)) { 213 // The hostname is an IP literal, and needs to be redacted too. 214 SocketAddress redacted_addr("redacted-literal.invalid", address().port()); 215 copy.set_address(redacted_addr); 216 } else { 217 SocketAddress hostname_only_addr(address().hostname(), address().port()); 218 copy.set_address(hostname_only_addr); 219 } 220 } 221 if (filter_related_address) { 222 copy.set_related_address( 223 EmptySocketAddressWithFamily(copy.address().family())); 224 } 225 if (filter_ufrag) { 226 copy.set_username(""); 227 } 228 229 return copy; 230 } 231 232 void Candidate::ComputeFoundation(const SocketAddress& base_address, 233 uint64_t tie_breaker) { 234 // https://www.rfc-editor.org/rfc/rfc5245#section-4.1.1.3 235 // The foundation is an identifier, scoped within a session. Two candidates 236 // MUST have the same foundation ID when all of the following are true: 237 // 238 // o they are of the same type. 239 // o their bases have the same IP address (the ports can be different). 240 // o for reflexive and relayed candidates, the STUN or TURN servers used to 241 // obtain them have the same IP address. 242 // o they were obtained using the same transport protocol (TCP, UDP, etc.). 243 // 244 // Similarly, two candidates MUST have different foundations if their 245 // types are different, their bases have different IP addresses, the STUN or 246 // TURN servers used to obtain them have different IP addresses, or their 247 // transport protocols are different. 248 249 StringBuilder sb; 250 sb << type_name() << base_address.ipaddr().ToString() << protocol_ 251 << relay_protocol_; 252 253 // https://www.rfc-editor.org/rfc/rfc5245#section-5.2 254 // [...] it is possible for both agents to mistakenly believe they are 255 // controlled or controlling. To resolve this, each agent MUST select a random 256 // number, called the tie-breaker, uniformly distributed between 0 and (2**64) 257 // - 1 (that is, a 64-bit positive integer). This number is used in 258 // connectivity checks to detect and repair this case [...] 259 sb << absl::StrCat(tie_breaker); 260 foundation_ = absl::StrCat(ComputeCrc32(sb.Release())); 261 } 262 263 void Candidate::ComputePrflxFoundation() { 264 RTC_DCHECK(is_prflx()); 265 RTC_DCHECK(!id_.empty()); 266 foundation_ = absl::StrCat(ComputeCrc32(id_)); 267 } 268 269 void Candidate::Assign(std::string& s, absl::string_view view) { 270 // Assigning via a temporary object, like s = std::string(view), results in 271 // binary size bloat. To avoid that, extract pointer and size from the 272 // string view, and use std::string::assign method. 273 s.assign(view.data(), view.size()); 274 } 275 276 } // namespace webrtc