| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright 2012 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include "webrtc/pc/peerconnection.h" | 11 #include "webrtc/pc/peerconnection.h" |
| 12 | 12 |
| 13 #include <algorithm> | 13 #include <algorithm> |
| 14 #include <cctype> // for isdigit | |
| 15 #include <utility> | 14 #include <utility> |
| 16 #include <vector> | 15 #include <vector> |
| 17 | 16 |
| 18 #include "webrtc/api/jsepicecandidate.h" | 17 #include "webrtc/api/jsepicecandidate.h" |
| 19 #include "webrtc/api/jsepsessiondescription.h" | 18 #include "webrtc/api/jsepsessiondescription.h" |
| 20 #include "webrtc/api/mediaconstraintsinterface.h" | 19 #include "webrtc/api/mediaconstraintsinterface.h" |
| 21 #include "webrtc/api/mediastreamproxy.h" | 20 #include "webrtc/api/mediastreamproxy.h" |
| 22 #include "webrtc/api/mediastreamtrackproxy.h" | 21 #include "webrtc/api/mediastreamtrackproxy.h" |
| 23 #include "webrtc/base/arraysize.h" | |
| 24 #include "webrtc/base/bind.h" | 22 #include "webrtc/base/bind.h" |
| 25 #include "webrtc/base/checks.h" | 23 #include "webrtc/base/checks.h" |
| 26 #include "webrtc/base/logging.h" | 24 #include "webrtc/base/logging.h" |
| 27 #include "webrtc/base/stringencode.h" | 25 #include "webrtc/base/stringencode.h" |
| 28 #include "webrtc/base/stringutils.h" | 26 #include "webrtc/base/stringutils.h" |
| 29 #include "webrtc/base/trace_event.h" | 27 #include "webrtc/base/trace_event.h" |
| 30 #include "webrtc/call/call.h" | 28 #include "webrtc/call/call.h" |
| 31 #include "webrtc/logging/rtc_event_log/rtc_event_log.h" | 29 #include "webrtc/logging/rtc_event_log/rtc_event_log.h" |
| 32 #include "webrtc/media/sctp/sctptransport.h" | 30 #include "webrtc/media/sctp/sctptransport.h" |
| 33 #include "webrtc/pc/audiotrack.h" | 31 #include "webrtc/pc/audiotrack.h" |
| (...skipping 21 matching lines...) Expand all Loading... |
| 55 using webrtc::RtpSenderInternal; | 53 using webrtc::RtpSenderInternal; |
| 56 using webrtc::RtpSenderInterface; | 54 using webrtc::RtpSenderInterface; |
| 57 using webrtc::RtpSenderProxy; | 55 using webrtc::RtpSenderProxy; |
| 58 using webrtc::RtpSenderProxyWithInternal; | 56 using webrtc::RtpSenderProxyWithInternal; |
| 59 using webrtc::StreamCollection; | 57 using webrtc::StreamCollection; |
| 60 | 58 |
| 61 static const char kDefaultStreamLabel[] = "default"; | 59 static const char kDefaultStreamLabel[] = "default"; |
| 62 static const char kDefaultAudioTrackLabel[] = "defaulta0"; | 60 static const char kDefaultAudioTrackLabel[] = "defaulta0"; |
| 63 static const char kDefaultVideoTrackLabel[] = "defaultv0"; | 61 static const char kDefaultVideoTrackLabel[] = "defaultv0"; |
| 64 | 62 |
| 65 // The min number of tokens must present in Turn host uri. | |
| 66 // e.g. user@turn.example.org | |
| 67 static const size_t kTurnHostTokensNum = 2; | |
| 68 // Number of tokens must be preset when TURN uri has transport param. | |
| 69 static const size_t kTurnTransportTokensNum = 2; | |
| 70 // The default stun port. | |
| 71 static const int kDefaultStunPort = 3478; | |
| 72 static const int kDefaultStunTlsPort = 5349; | |
| 73 static const char kTransport[] = "transport"; | |
| 74 | |
| 75 // NOTE: Must be in the same order as the ServiceType enum. | |
| 76 static const char* kValidIceServiceTypes[] = {"stun", "stuns", "turn", "turns"}; | |
| 77 | |
| 78 // The length of RTCP CNAMEs. | 63 // The length of RTCP CNAMEs. |
| 79 static const int kRtcpCnameLength = 16; | 64 static const int kRtcpCnameLength = 16; |
| 80 | 65 |
| 81 // NOTE: A loop below assumes that the first value of this enum is 0 and all | |
| 82 // other values are incremental. | |
| 83 enum ServiceType { | |
| 84 STUN = 0, // Indicates a STUN server. | |
| 85 STUNS, // Indicates a STUN server used with a TLS session. | |
| 86 TURN, // Indicates a TURN server | |
| 87 TURNS, // Indicates a TURN server used with a TLS session. | |
| 88 INVALID, // Unknown. | |
| 89 }; | |
| 90 static_assert(INVALID == arraysize(kValidIceServiceTypes), | |
| 91 "kValidIceServiceTypes must have as many strings as ServiceType " | |
| 92 "has values."); | |
| 93 | |
| 94 enum { | 66 enum { |
| 95 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0, | 67 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0, |
| 96 MSG_SET_SESSIONDESCRIPTION_FAILED, | 68 MSG_SET_SESSIONDESCRIPTION_FAILED, |
| 97 MSG_CREATE_SESSIONDESCRIPTION_FAILED, | 69 MSG_CREATE_SESSIONDESCRIPTION_FAILED, |
| 98 MSG_GETSTATS, | 70 MSG_GETSTATS, |
| 99 MSG_FREE_DATACHANNELS, | 71 MSG_FREE_DATACHANNELS, |
| 100 }; | 72 }; |
| 101 | 73 |
| 102 struct SetSessionDescriptionMsg : public rtc::MessageData { | 74 struct SetSessionDescriptionMsg : public rtc::MessageData { |
| 103 explicit SetSessionDescriptionMsg( | 75 explicit SetSessionDescriptionMsg( |
| (...skipping 16 matching lines...) Expand all Loading... |
| 120 | 92 |
| 121 struct GetStatsMsg : public rtc::MessageData { | 93 struct GetStatsMsg : public rtc::MessageData { |
| 122 GetStatsMsg(webrtc::StatsObserver* observer, | 94 GetStatsMsg(webrtc::StatsObserver* observer, |
| 123 webrtc::MediaStreamTrackInterface* track) | 95 webrtc::MediaStreamTrackInterface* track) |
| 124 : observer(observer), track(track) { | 96 : observer(observer), track(track) { |
| 125 } | 97 } |
| 126 rtc::scoped_refptr<webrtc::StatsObserver> observer; | 98 rtc::scoped_refptr<webrtc::StatsObserver> observer; |
| 127 rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track; | 99 rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track; |
| 128 }; | 100 }; |
| 129 | 101 |
| 130 // |in_str| should be of format | |
| 131 // stunURI = scheme ":" stun-host [ ":" stun-port ] | |
| 132 // scheme = "stun" / "stuns" | |
| 133 // stun-host = IP-literal / IPv4address / reg-name | |
| 134 // stun-port = *DIGIT | |
| 135 // | |
| 136 // draft-petithuguenin-behave-turn-uris-01 | |
| 137 // turnURI = scheme ":" turn-host [ ":" turn-port ] | |
| 138 // turn-host = username@IP-literal / IPv4address / reg-name | |
| 139 bool GetServiceTypeAndHostnameFromUri(const std::string& in_str, | |
| 140 ServiceType* service_type, | |
| 141 std::string* hostname) { | |
| 142 const std::string::size_type colonpos = in_str.find(':'); | |
| 143 if (colonpos == std::string::npos) { | |
| 144 LOG(LS_WARNING) << "Missing ':' in ICE URI: " << in_str; | |
| 145 return false; | |
| 146 } | |
| 147 if ((colonpos + 1) == in_str.length()) { | |
| 148 LOG(LS_WARNING) << "Empty hostname in ICE URI: " << in_str; | |
| 149 return false; | |
| 150 } | |
| 151 *service_type = INVALID; | |
| 152 for (size_t i = 0; i < arraysize(kValidIceServiceTypes); ++i) { | |
| 153 if (in_str.compare(0, colonpos, kValidIceServiceTypes[i]) == 0) { | |
| 154 *service_type = static_cast<ServiceType>(i); | |
| 155 break; | |
| 156 } | |
| 157 } | |
| 158 if (*service_type == INVALID) { | |
| 159 return false; | |
| 160 } | |
| 161 *hostname = in_str.substr(colonpos + 1, std::string::npos); | |
| 162 return true; | |
| 163 } | |
| 164 | |
| 165 bool ParsePort(const std::string& in_str, int* port) { | |
| 166 // Make sure port only contains digits. FromString doesn't check this. | |
| 167 for (const char& c : in_str) { | |
| 168 if (!std::isdigit(c)) { | |
| 169 return false; | |
| 170 } | |
| 171 } | |
| 172 return rtc::FromString(in_str, port); | |
| 173 } | |
| 174 | |
| 175 // This method parses IPv6 and IPv4 literal strings, along with hostnames in | |
| 176 // standard hostname:port format. | |
| 177 // Consider following formats as correct. | |
| 178 // |hostname:port|, |[IPV6 address]:port|, |IPv4 address|:port, | |
| 179 // |hostname|, |[IPv6 address]|, |IPv4 address|. | |
| 180 bool ParseHostnameAndPortFromString(const std::string& in_str, | |
| 181 std::string* host, | |
| 182 int* port) { | |
| 183 RTC_DCHECK(host->empty()); | |
| 184 if (in_str.at(0) == '[') { | |
| 185 std::string::size_type closebracket = in_str.rfind(']'); | |
| 186 if (closebracket != std::string::npos) { | |
| 187 std::string::size_type colonpos = in_str.find(':', closebracket); | |
| 188 if (std::string::npos != colonpos) { | |
| 189 if (!ParsePort(in_str.substr(closebracket + 2, std::string::npos), | |
| 190 port)) { | |
| 191 return false; | |
| 192 } | |
| 193 } | |
| 194 *host = in_str.substr(1, closebracket - 1); | |
| 195 } else { | |
| 196 return false; | |
| 197 } | |
| 198 } else { | |
| 199 std::string::size_type colonpos = in_str.find(':'); | |
| 200 if (std::string::npos != colonpos) { | |
| 201 if (!ParsePort(in_str.substr(colonpos + 1, std::string::npos), port)) { | |
| 202 return false; | |
| 203 } | |
| 204 *host = in_str.substr(0, colonpos); | |
| 205 } else { | |
| 206 *host = in_str; | |
| 207 } | |
| 208 } | |
| 209 return !host->empty(); | |
| 210 } | |
| 211 | |
| 212 // Adds a STUN or TURN server to the appropriate list, | |
| 213 // by parsing |url| and using the username/password in |server|. | |
| 214 RTCErrorType ParseIceServerUrl( | |
| 215 const PeerConnectionInterface::IceServer& server, | |
| 216 const std::string& url, | |
| 217 cricket::ServerAddresses* stun_servers, | |
| 218 std::vector<cricket::RelayServerConfig>* turn_servers) { | |
| 219 // draft-nandakumar-rtcweb-stun-uri-01 | |
| 220 // stunURI = scheme ":" stun-host [ ":" stun-port ] | |
| 221 // scheme = "stun" / "stuns" | |
| 222 // stun-host = IP-literal / IPv4address / reg-name | |
| 223 // stun-port = *DIGIT | |
| 224 | |
| 225 // draft-petithuguenin-behave-turn-uris-01 | |
| 226 // turnURI = scheme ":" turn-host [ ":" turn-port ] | |
| 227 // [ "?transport=" transport ] | |
| 228 // scheme = "turn" / "turns" | |
| 229 // transport = "udp" / "tcp" / transport-ext | |
| 230 // transport-ext = 1*unreserved | |
| 231 // turn-host = IP-literal / IPv4address / reg-name | |
| 232 // turn-port = *DIGIT | |
| 233 RTC_DCHECK(stun_servers != nullptr); | |
| 234 RTC_DCHECK(turn_servers != nullptr); | |
| 235 std::vector<std::string> tokens; | |
| 236 cricket::ProtocolType turn_transport_type = cricket::PROTO_UDP; | |
| 237 RTC_DCHECK(!url.empty()); | |
| 238 rtc::tokenize_with_empty_tokens(url, '?', &tokens); | |
| 239 std::string uri_without_transport = tokens[0]; | |
| 240 // Let's look into transport= param, if it exists. | |
| 241 if (tokens.size() == kTurnTransportTokensNum) { // ?transport= is present. | |
| 242 std::string uri_transport_param = tokens[1]; | |
| 243 rtc::tokenize_with_empty_tokens(uri_transport_param, '=', &tokens); | |
| 244 if (tokens[0] != kTransport) { | |
| 245 LOG(LS_WARNING) << "Invalid transport parameter key."; | |
| 246 return RTCErrorType::SYNTAX_ERROR; | |
| 247 } | |
| 248 if (tokens.size() < 2) { | |
| 249 LOG(LS_WARNING) << "Transport parameter missing value."; | |
| 250 return RTCErrorType::SYNTAX_ERROR; | |
| 251 } | |
| 252 if (!cricket::StringToProto(tokens[1].c_str(), &turn_transport_type) || | |
| 253 (turn_transport_type != cricket::PROTO_UDP && | |
| 254 turn_transport_type != cricket::PROTO_TCP)) { | |
| 255 LOG(LS_WARNING) << "Transport parameter should always be udp or tcp."; | |
| 256 return RTCErrorType::SYNTAX_ERROR; | |
| 257 } | |
| 258 } | |
| 259 | |
| 260 std::string hoststring; | |
| 261 ServiceType service_type; | |
| 262 if (!GetServiceTypeAndHostnameFromUri(uri_without_transport, | |
| 263 &service_type, | |
| 264 &hoststring)) { | |
| 265 LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: " << url; | |
| 266 return RTCErrorType::SYNTAX_ERROR; | |
| 267 } | |
| 268 | |
| 269 // GetServiceTypeAndHostnameFromUri should never give an empty hoststring | |
| 270 RTC_DCHECK(!hoststring.empty()); | |
| 271 | |
| 272 // Let's break hostname. | |
| 273 tokens.clear(); | |
| 274 rtc::tokenize_with_empty_tokens(hoststring, '@', &tokens); | |
| 275 | |
| 276 std::string username(server.username); | |
| 277 if (tokens.size() > kTurnHostTokensNum) { | |
| 278 LOG(LS_WARNING) << "Invalid user@hostname format: " << hoststring; | |
| 279 return RTCErrorType::SYNTAX_ERROR; | |
| 280 } | |
| 281 if (tokens.size() == kTurnHostTokensNum) { | |
| 282 if (tokens[0].empty() || tokens[1].empty()) { | |
| 283 LOG(LS_WARNING) << "Invalid user@hostname format: " << hoststring; | |
| 284 return RTCErrorType::SYNTAX_ERROR; | |
| 285 } | |
| 286 username.assign(rtc::s_url_decode(tokens[0])); | |
| 287 hoststring = tokens[1]; | |
| 288 } else { | |
| 289 hoststring = tokens[0]; | |
| 290 } | |
| 291 | |
| 292 int port = kDefaultStunPort; | |
| 293 if (service_type == TURNS) { | |
| 294 port = kDefaultStunTlsPort; | |
| 295 turn_transport_type = cricket::PROTO_TLS; | |
| 296 } | |
| 297 | |
| 298 std::string address; | |
| 299 if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) { | |
| 300 LOG(WARNING) << "Invalid hostname format: " << uri_without_transport; | |
| 301 return RTCErrorType::SYNTAX_ERROR; | |
| 302 } | |
| 303 | |
| 304 if (port <= 0 || port > 0xffff) { | |
| 305 LOG(WARNING) << "Invalid port: " << port; | |
| 306 return RTCErrorType::SYNTAX_ERROR; | |
| 307 } | |
| 308 | |
| 309 switch (service_type) { | |
| 310 case STUN: | |
| 311 case STUNS: | |
| 312 stun_servers->insert(rtc::SocketAddress(address, port)); | |
| 313 break; | |
| 314 case TURN: | |
| 315 case TURNS: { | |
| 316 if (username.empty() || server.password.empty()) { | |
| 317 // The WebRTC spec requires throwing an InvalidAccessError when username | |
| 318 // or credential are ommitted; this is the native equivalent. | |
| 319 return RTCErrorType::INVALID_PARAMETER; | |
| 320 } | |
| 321 cricket::RelayServerConfig config = cricket::RelayServerConfig( | |
| 322 address, port, username, server.password, turn_transport_type); | |
| 323 if (server.tls_cert_policy == | |
| 324 PeerConnectionInterface::kTlsCertPolicyInsecureNoCheck) { | |
| 325 config.tls_cert_policy = | |
| 326 cricket::TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK; | |
| 327 } | |
| 328 turn_servers->push_back(config); | |
| 329 break; | |
| 330 } | |
| 331 default: | |
| 332 // We shouldn't get to this point with an invalid service_type, we should | |
| 333 // have returned an error already. | |
| 334 RTC_NOTREACHED() << "Unexpected service type"; | |
| 335 return RTCErrorType::INTERNAL_ERROR; | |
| 336 } | |
| 337 return RTCErrorType::NONE; | |
| 338 } | |
| 339 | |
| 340 // Check if we can send |new_stream| on a PeerConnection. | 102 // Check if we can send |new_stream| on a PeerConnection. |
| 341 bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams, | 103 bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams, |
| 342 webrtc::MediaStreamInterface* new_stream) { | 104 webrtc::MediaStreamInterface* new_stream) { |
| 343 if (!new_stream || !current_streams) { | 105 if (!new_stream || !current_streams) { |
| 344 return false; | 106 return false; |
| 345 } | 107 } |
| 346 if (current_streams->find(new_stream->label()) != nullptr) { | 108 if (current_streams->find(new_stream->label()) != nullptr) { |
| 347 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label() | 109 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label() |
| 348 << " is already added."; | 110 << " is already added."; |
| 349 return false; | 111 return false; |
| (...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 622 for (auto& kv : session_options->transport_options) { | 384 for (auto& kv : session_options->transport_options) { |
| 623 kv.second.ice_restart = ice_restart; | 385 kv.second.ice_restart = ice_restart; |
| 624 } | 386 } |
| 625 | 387 |
| 626 if (!constraints) { | 388 if (!constraints) { |
| 627 return true; | 389 return true; |
| 628 } | 390 } |
| 629 return mandatory_constraints_satisfied == constraints->GetMandatory().size(); | 391 return mandatory_constraints_satisfied == constraints->GetMandatory().size(); |
| 630 } | 392 } |
| 631 | 393 |
| 632 RTCErrorType ParseIceServers( | |
| 633 const PeerConnectionInterface::IceServers& servers, | |
| 634 cricket::ServerAddresses* stun_servers, | |
| 635 std::vector<cricket::RelayServerConfig>* turn_servers) { | |
| 636 for (const webrtc::PeerConnectionInterface::IceServer& server : servers) { | |
| 637 if (!server.urls.empty()) { | |
| 638 for (const std::string& url : server.urls) { | |
| 639 if (url.empty()) { | |
| 640 LOG(LS_ERROR) << "Empty uri."; | |
| 641 return RTCErrorType::SYNTAX_ERROR; | |
| 642 } | |
| 643 RTCErrorType err = | |
| 644 ParseIceServerUrl(server, url, stun_servers, turn_servers); | |
| 645 if (err != RTCErrorType::NONE) { | |
| 646 return err; | |
| 647 } | |
| 648 } | |
| 649 } else if (!server.uri.empty()) { | |
| 650 // Fallback to old .uri if new .urls isn't present. | |
| 651 RTCErrorType err = | |
| 652 ParseIceServerUrl(server, server.uri, stun_servers, turn_servers); | |
| 653 if (err != RTCErrorType::NONE) { | |
| 654 return err; | |
| 655 } | |
| 656 } else { | |
| 657 LOG(LS_ERROR) << "Empty uri."; | |
| 658 return RTCErrorType::SYNTAX_ERROR; | |
| 659 } | |
| 660 } | |
| 661 // Candidates must have unique priorities, so that connectivity checks | |
| 662 // are performed in a well-defined order. | |
| 663 int priority = static_cast<int>(turn_servers->size() - 1); | |
| 664 for (cricket::RelayServerConfig& turn_server : *turn_servers) { | |
| 665 // First in the list gets highest priority. | |
| 666 turn_server.priority = priority--; | |
| 667 } | |
| 668 return RTCErrorType::NONE; | |
| 669 } | |
| 670 | |
| 671 PeerConnection::PeerConnection(PeerConnectionFactory* factory) | 394 PeerConnection::PeerConnection(PeerConnectionFactory* factory) |
| 672 : factory_(factory), | 395 : factory_(factory), |
| 673 observer_(NULL), | 396 observer_(NULL), |
| 674 uma_observer_(NULL), | 397 uma_observer_(NULL), |
| 675 signaling_state_(kStable), | 398 signaling_state_(kStable), |
| 676 ice_connection_state_(kIceConnectionNew), | 399 ice_connection_state_(kIceConnectionNew), |
| 677 ice_gathering_state_(kIceGatheringNew), | 400 ice_gathering_state_(kIceGatheringNew), |
| 678 event_log_(RtcEventLog::Create()), | 401 event_log_(RtcEventLog::Create()), |
| 679 rtcp_cname_(GenerateRtcpCname()), | 402 rtcp_cname_(GenerateRtcpCname()), |
| 680 local_streams_(StreamCollection::Create()), | 403 local_streams_(StreamCollection::Create()), |
| (...skipping 1904 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2585 } | 2308 } |
| 2586 return event_log_->StartLogging(file, max_size_bytes); | 2309 return event_log_->StartLogging(file, max_size_bytes); |
| 2587 } | 2310 } |
| 2588 | 2311 |
| 2589 void PeerConnection::StopRtcEventLog_w() { | 2312 void PeerConnection::StopRtcEventLog_w() { |
| 2590 if (event_log_) { | 2313 if (event_log_) { |
| 2591 event_log_->StopLogging(); | 2314 event_log_->StopLogging(); |
| 2592 } | 2315 } |
| 2593 } | 2316 } |
| 2594 } // namespace webrtc | 2317 } // namespace webrtc |
| OLD | NEW |