MediaTransportHandler.cpp (60371B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "MediaTransportHandler.h" 6 7 #include "MediaTransportHandlerIPC.h" 8 #include "transport/nricemediastream.h" 9 #include "transport/nriceresolver.h" 10 #include "transport/sigslot.h" 11 #include "transport/transportflow.h" 12 #include "transport/transportlayerdtls.h" 13 #include "transport/transportlayerice.h" 14 #include "transport/transportlayersrtp.h" 15 16 // Config stuff 17 #include "mozilla/Preferences.h" 18 #include "mozilla/StaticPrefs_network.h" 19 #include "mozilla/dom/RTCConfigurationBinding.h" 20 21 // Parsing STUN/TURN URIs 22 #include "nsIURI.h" 23 #include "nsIURLParser.h" 24 #include "nsNetUtil.h" 25 #include "nsURLHelper.h" 26 27 // Logging stuff 28 #include "common/browser_logging/CSFLog.h" 29 30 // For fetching ICE logging 31 #include "transport/rlogconnector.h" 32 33 // DTLS 34 #include <map> 35 #include <string> 36 #include <vector> 37 38 #include "mozilla/PublicSSL.h" // For psm::InitializeCipherSuite 39 #include "mozilla/dom/RTCStatsReportBinding.h" 40 #include "nsDNSService2.h" 41 #include "nsISocketTransportService.h" 42 #include "nss.h" // For NSS_NoDB_Init 43 #include "sdp/SdpAttribute.h" 44 #include "transport/runnable_utils.h" 45 46 #ifdef MOZ_GECKO_PROFILER 47 # include "mozilla/ProfilerMarkers.h" 48 49 # define MEDIA_TRANSPORT_HANDLER_PACKET_RECEIVED(aPacket) \ 50 PROFILER_MARKER_TEXT( \ 51 "WebRTC Packet Received", MEDIA_RT, {}, \ 52 ProfilerString8View::WrapNullTerminatedString( \ 53 MediaPacket::EnumValueToString((aPacket).type()))); 54 #else 55 # define MEDIA_TRANSPORT_HANDLER_PACKET_RECEIVED(aPacket) 56 #endif 57 58 namespace mozilla { 59 60 static const char* mthLogTag = "MediaTransportHandler"; 61 #ifdef LOGTAG 62 # undef LOGTAG 63 #endif 64 #define LOGTAG mthLogTag 65 66 class MediaTransportHandlerSTS : public MediaTransportHandler, 67 public sigslot::has_slots<> { 68 public: 69 explicit MediaTransportHandlerSTS(); 70 71 RefPtr<IceLogPromise> GetIceLog(const nsCString& aPattern) override; 72 void ClearIceLog() override; 73 void EnterPrivateMode() override; 74 void ExitPrivateMode() override; 75 76 void CreateIceCtx(const std::string& aName) override; 77 78 nsresult SetIceConfig(const nsTArray<dom::RTCIceServer>& aIceServers, 79 dom::RTCIceTransportPolicy aIcePolicy) override; 80 81 // We will probably be able to move the proxy lookup stuff into 82 // this class once we move mtransport to its own process. 83 void SetProxyConfig(NrSocketProxyConfig&& aProxyConfig) override; 84 85 void EnsureProvisionalTransport(const std::string& aTransportId, 86 const std::string& aUfrag, 87 const std::string& aPwd, 88 int aComponentCount) override; 89 90 void SetTargetForDefaultLocalAddressLookup(const std::string& aTargetIp, 91 uint16_t aTargetPort) override; 92 93 // We set default-route-only as late as possible because it depends on what 94 // capture permissions have been granted on the window, which could easily 95 // change between Init (ie; when the PC is created) and StartIceGathering 96 // (ie; when we set the local description). 97 void StartIceGathering(bool aDefaultRouteOnly, bool aObfuscateHostAddresses, 98 // This will go away once mtransport moves to its 99 // own process, because we won't need to get this 100 // via IPC anymore 101 const nsTArray<NrIceStunAddr>& aStunAddrs) override; 102 103 void ActivateTransport( 104 const std::string& aTransportId, const std::string& aLocalUfrag, 105 const std::string& aLocalPwd, size_t aComponentCount, 106 const std::string& aUfrag, const std::string& aPassword, 107 const nsTArray<uint8_t>& aKeyDer, const nsTArray<uint8_t>& aCertDer, 108 SSLKEAType aAuthType, bool aDtlsClient, const DtlsDigestList& aDigests, 109 bool aPrivacyRequested) override; 110 111 void RemoveTransportsExcept( 112 const std::set<std::string>& aTransportIds) override; 113 114 void StartIceChecks(bool aIsControlling, 115 const std::vector<std::string>& aIceOptions) override; 116 117 void AddIceCandidate(const std::string& aTransportId, 118 const std::string& aCandidate, const std::string& aUfrag, 119 const std::string& aObfuscatedAddress) override; 120 121 void UpdateNetworkState(bool aOnline) override; 122 123 void SendPacket(const std::string& aTransportId, 124 MediaPacket&& aPacket) override; 125 126 RefPtr<dom::RTCStatsPromise> GetIceStats(const std::string& aTransportId, 127 DOMHighResTimeStamp aNow) override; 128 129 void Shutdown(); 130 131 private: 132 void Destroy() override; 133 void DestroyFinal(); 134 void Shutdown_s(); 135 RefPtr<TransportFlow> CreateTransportFlow( 136 const std::string& aTransportId, bool aIsRtcp, 137 const RefPtr<DtlsIdentity>& aDtlsIdentity, bool aDtlsClient, 138 const DtlsDigestList& aDigests, bool aPrivacyRequested); 139 140 struct Transport { 141 RefPtr<TransportFlow> mFlow; 142 RefPtr<TransportFlow> mRtcpFlow; 143 }; 144 145 using MediaTransportHandler::OnAlpnNegotiated; 146 using MediaTransportHandler::OnCandidate; 147 using MediaTransportHandler::OnConnectionStateChange; 148 using MediaTransportHandler::OnEncryptedSending; 149 using MediaTransportHandler::OnGatheringStateChange; 150 using MediaTransportHandler::OnPacketReceived; 151 using MediaTransportHandler::OnRtcpStateChange; 152 using MediaTransportHandler::OnStateChange; 153 154 void OnGatheringStateChange(const std::string& aTransportId, 155 NrIceMediaStream::GatheringState aState); 156 void OnConnectionStateChange(NrIceMediaStream* aIceStream, 157 NrIceCtx::ConnectionState aState); 158 void OnCandidateFound(NrIceMediaStream* aStream, 159 const std::string& aCandidate, 160 const std::string& aUfrag, const std::string& aMDNSAddr, 161 const std::string& aActualAddr); 162 void OnStateChange(TransportLayer* aLayer, TransportLayer::State); 163 void OnRtcpStateChange(TransportLayer* aLayer, TransportLayer::State); 164 void PacketReceived(TransportLayer* aLayer, MediaPacket& aPacket); 165 void EncryptedPacketSending(TransportLayer* aLayer, MediaPacket& aPacket); 166 RefPtr<TransportFlow> GetTransportFlow(const std::string& aTransportId, 167 bool aIsRtcp) const; 168 void GetIceStats(const NrIceMediaStream& aStream, DOMHighResTimeStamp aNow, 169 dom::RTCStatsCollection* aStats) const; 170 171 virtual ~MediaTransportHandlerSTS() = default; 172 nsCOMPtr<nsISerialEventTarget> mStsThread; 173 RefPtr<NrIceCtx> mIceCtx; 174 RefPtr<NrIceResolver> mDNSResolver; 175 std::map<std::string, Transport> mTransports; 176 bool mObfuscateHostAddresses = false; 177 bool mTurnDisabled = false; 178 uint32_t mMinDtlsVersion = 0; 179 uint32_t mMaxDtlsVersion = 0; 180 bool mForceNoHost = false; 181 bool mAllowLoopback = false; 182 bool mAllowLinkLocal = false; 183 Maybe<NrIceCtx::NatSimulatorConfig> mNatConfig; 184 185 std::set<std::string> mSignaledAddresses; 186 187 // Init can only be done on main, but we want this to be usable on any thread 188 using InitPromise = MozPromise<bool, std::string, false>; 189 RefPtr<InitPromise> mInitPromise; 190 }; 191 192 /* static */ 193 already_AddRefed<MediaTransportHandler> MediaTransportHandler::Create() { 194 RefPtr<MediaTransportHandler> result; 195 if (XRE_IsContentProcess() && 196 Preferences::GetBool("media.peerconnection.mtransport_process") && 197 StaticPrefs::network_process_enabled()) { 198 result = new MediaTransportHandlerIPC(); 199 } else { 200 result = new MediaTransportHandlerSTS(); 201 } 202 result->Initialize(); 203 return result.forget(); 204 } 205 206 class STSShutdownHandler : public nsISTSShutdownObserver { 207 public: 208 NS_DECL_ISUPPORTS 209 210 // Lazy singleton 211 static RefPtr<STSShutdownHandler>& Instance() { 212 MOZ_ASSERT(NS_IsMainThread()); 213 static RefPtr<STSShutdownHandler> sHandler(new STSShutdownHandler); 214 return sHandler; 215 } 216 217 void Shutdown() { 218 MOZ_ASSERT(NS_IsMainThread()); 219 for (const auto& handler : mHandlers) { 220 handler->Shutdown(); 221 } 222 mHandlers.clear(); 223 } 224 225 STSShutdownHandler() { 226 CSFLogDebug(LOGTAG, "%s", __func__); 227 nsresult res; 228 nsCOMPtr<nsISocketTransportService> sts = 229 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &res); 230 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(res)); 231 MOZ_RELEASE_ASSERT(sts); 232 sts->AddShutdownObserver(this); 233 } 234 235 NS_IMETHOD Observe() override { 236 CSFLogDebug(LOGTAG, "%s", __func__); 237 Shutdown(); 238 nsresult res; 239 nsCOMPtr<nsISocketTransportService> sts = 240 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &res); 241 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(res)); 242 MOZ_RELEASE_ASSERT(sts); 243 sts->RemoveShutdownObserver(this); 244 Instance() = nullptr; 245 return NS_OK; 246 } 247 248 void Register(MediaTransportHandlerSTS* aHandler) { 249 MOZ_ASSERT(NS_IsMainThread()); 250 mHandlers.insert(aHandler); 251 } 252 253 void Deregister(MediaTransportHandlerSTS* aHandler) { 254 MOZ_ASSERT(NS_IsMainThread()); 255 mHandlers.erase(aHandler); 256 } 257 258 private: 259 virtual ~STSShutdownHandler() = default; 260 261 // Raw ptrs, registered on init, deregistered on destruction, all on main 262 std::set<MediaTransportHandlerSTS*> mHandlers; 263 }; 264 265 NS_IMPL_ISUPPORTS(STSShutdownHandler, nsISTSShutdownObserver); 266 267 MediaTransportHandlerSTS::MediaTransportHandlerSTS() { 268 nsresult rv; 269 mStsThread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); 270 if (!mStsThread) { 271 MOZ_CRASH(); 272 } 273 274 RLogConnector::CreateInstance(); 275 276 CSFLogDebug(LOGTAG, "%s done %p", __func__, this); 277 278 // We do not set up mDNSService here, because we are not running on main (we 279 // use PBackground), and the DNS service asserts. 280 } 281 282 static NrIceCtx::Policy toNrIcePolicy(dom::RTCIceTransportPolicy aPolicy) { 283 switch (aPolicy) { 284 case dom::RTCIceTransportPolicy::Relay: 285 return NrIceCtx::ICE_POLICY_RELAY; 286 case dom::RTCIceTransportPolicy::All: 287 return NrIceCtx::ICE_POLICY_ALL; 288 default: 289 MOZ_CRASH(); 290 } 291 return NrIceCtx::ICE_POLICY_ALL; 292 } 293 294 // list of known acceptable ports for webrtc 295 int16_t gGoodWebrtcPortList[] = { 296 53, // Some deplyoments use DNS port to punch through overzealous NATs 297 3478, // stun or turn 298 5349, // stuns or turns 299 0, // Sentinel value: This MUST be zero 300 }; 301 302 static nsresult addNrIceServer(const nsString& aIceUrl, 303 const dom::RTCIceServer& aIceServer, 304 std::vector<NrIceStunServer>* aStunServersOut, 305 std::vector<NrIceTurnServer>* aTurnServersOut) { 306 // Without STUN/TURN handlers, NS_NewURI returns nsSimpleURI rather than 307 // nsStandardURL. To parse STUN/TURN URI's to spec 308 // http://tools.ietf.org/html/draft-nandakumar-rtcweb-stun-uri-02#section-3 309 // http://tools.ietf.org/html/draft-petithuguenin-behave-turn-uri-03#section-3 310 // we parse out the query-string, and use ParseAuthority() on the rest 311 RefPtr<nsIURI> url; 312 nsresult rv = NS_NewURI(getter_AddRefs(url), aIceUrl); 313 NS_ENSURE_SUCCESS(rv, rv); 314 bool isStun = url->SchemeIs("stun"); 315 bool isStuns = url->SchemeIs("stuns"); 316 bool isTurn = url->SchemeIs("turn"); 317 bool isTurns = url->SchemeIs("turns"); 318 if (!(isStun || isStuns || isTurn || isTurns)) { 319 return NS_ERROR_FAILURE; 320 } 321 if (isStuns) { 322 return NS_OK; // TODO: Support STUNS (Bug 1056934) 323 } 324 325 nsAutoCString spec; 326 rv = url->GetSpec(spec); 327 NS_ENSURE_SUCCESS(rv, rv); 328 329 // TODO(jib@mozilla.com): Revisit once nsURI supports STUN/TURN (Bug 833509) 330 int32_t port; 331 nsAutoCString host; 332 nsAutoCString transport; 333 { 334 uint32_t hostPos; 335 int32_t hostLen; 336 nsAutoCString path; 337 rv = url->GetPathQueryRef(path); 338 NS_ENSURE_SUCCESS(rv, rv); 339 340 // Tolerate query-string + parse 'transport=[udp|tcp]' by hand. 341 int32_t questionmark = path.FindChar('?'); 342 if (questionmark >= 0) { 343 const nsCString match = "transport="_ns; 344 345 for (int32_t i = questionmark, endPos; i >= 0; i = endPos) { 346 endPos = path.FindCharInSet("&", i + 1); 347 const nsDependentCSubstring fieldvaluepair = 348 Substring(path, i + 1, endPos); 349 if (StringBeginsWith(fieldvaluepair, match)) { 350 transport = Substring(fieldvaluepair, match.Length()); 351 ToLowerCase(transport); 352 } 353 } 354 path.SetLength(questionmark); 355 } 356 357 nsCOMPtr<nsIURLParser> parser = net_GetAuthURLParser(); 358 rv = parser->ParseAuthority(path.get(), static_cast<int>(path.Length()), 359 nullptr, nullptr, nullptr, nullptr, &hostPos, 360 &hostLen, &port); 361 NS_ENSURE_SUCCESS(rv, rv); 362 if (!hostLen) { 363 return NS_ERROR_FAILURE; 364 } 365 if (hostPos > 1) { 366 /* The username was removed */ 367 return NS_ERROR_FAILURE; 368 } 369 path.Mid(host, hostPos, hostLen); 370 // Strip off brackets around IPv6 literals 371 host.Trim("[]"); 372 } 373 if (port == -1) port = (isStuns || isTurns) ? 5349 : 3478; 374 375 // First check the known good ports for webrtc 376 bool goodPort = false; 377 for (int i = 0; !goodPort && gGoodWebrtcPortList[i]; i++) { 378 if (port == gGoodWebrtcPortList[i]) { 379 goodPort = true; 380 } 381 } 382 383 // if not in the list of known good ports for webrtc, check 384 // the generic block list using NS_CheckPortSafety. 385 if (!goodPort) { 386 rv = NS_CheckPortSafety(port, nullptr); 387 NS_ENSURE_SUCCESS(rv, rv); 388 } 389 390 if (isStuns || isTurns) { 391 // Should we barf if transport is set to udp or something? 392 transport = kNrIceTransportTls; 393 } 394 395 if (transport.IsEmpty()) { 396 transport = kNrIceTransportUdp; 397 } 398 399 if (isTurn || isTurns) { 400 std::string pwd( 401 NS_ConvertUTF16toUTF8(aIceServer.mCredential.Value()).get()); 402 std::string username( 403 NS_ConvertUTF16toUTF8(aIceServer.mUsername.Value()).get()); 404 405 std::vector<unsigned char> password(pwd.begin(), pwd.end()); 406 407 UniquePtr<NrIceTurnServer> server(NrIceTurnServer::Create( 408 host.get(), port, username, password, transport.get())); 409 if (!server) { 410 return NS_ERROR_FAILURE; 411 } 412 if (server->HasFqdn()) { 413 // Add an IPv4 entry, then an IPv6 entry 414 aTurnServersOut->push_back(*server); 415 server->SetUseIPv6IfFqdn(); 416 } 417 aTurnServersOut->emplace_back(std::move(*server)); 418 } else { 419 UniquePtr<NrIceStunServer> server( 420 NrIceStunServer::Create(host.get(), port, transport.get())); 421 if (!server) { 422 return NS_ERROR_FAILURE; 423 } 424 if (server->HasFqdn()) { 425 // Add an IPv4 entry, then an IPv6 entry 426 aStunServersOut->push_back(*server); 427 server->SetUseIPv6IfFqdn(); 428 } 429 aStunServersOut->emplace_back(std::move(*server)); 430 } 431 return NS_OK; 432 } 433 434 /* static */ 435 nsresult MediaTransportHandler::ConvertIceServers( 436 const nsTArray<dom::RTCIceServer>& aIceServers, 437 std::vector<NrIceStunServer>* aStunServers, 438 std::vector<NrIceTurnServer>* aTurnServers) { 439 for (const auto& iceServer : aIceServers) { 440 NS_ENSURE_STATE(iceServer.mUrls.WasPassed()); 441 NS_ENSURE_STATE(iceServer.mUrls.Value().IsStringSequence()); 442 for (const auto& iceUrl : iceServer.mUrls.Value().GetAsStringSequence()) { 443 nsresult rv = 444 addNrIceServer(iceUrl, iceServer, aStunServers, aTurnServers); 445 if (NS_FAILED(rv)) { 446 CSFLogError(LOGTAG, "%s: invalid STUN/TURN server: %s", __FUNCTION__, 447 NS_ConvertUTF16toUTF8(iceUrl).get()); 448 return rv; 449 } 450 } 451 } 452 453 return NS_OK; 454 } 455 456 static NrIceCtx::GlobalConfig GetGlobalConfig() { 457 NrIceCtx::GlobalConfig config; 458 config.mTcpEnabled = 459 Preferences::GetBool("media.peerconnection.ice.tcp", false); 460 config.mStunClientMaxTransmits = Preferences::GetInt( 461 "media.peerconnection.ice.stun_client_maximum_transmits", 462 config.mStunClientMaxTransmits); 463 config.mTrickleIceGracePeriod = 464 Preferences::GetInt("media.peerconnection.ice.trickle_grace_period", 465 config.mTrickleIceGracePeriod); 466 config.mIceTcpSoSockCount = Preferences::GetInt( 467 "media.peerconnection.ice.tcp_so_sock_count", config.mIceTcpSoSockCount); 468 config.mIceTcpListenBacklog = 469 Preferences::GetInt("media.peerconnection.ice.tcp_listen_backlog", 470 config.mIceTcpListenBacklog); 471 (void)Preferences::GetCString("media.peerconnection.ice.force_interface", 472 config.mForceNetInterface); 473 return config; 474 } 475 476 static Maybe<NrIceCtx::NatSimulatorConfig> GetNatConfig() { 477 bool block_tcp = Preferences::GetBool( 478 "media.peerconnection.nat_simulator.block_tcp", false); 479 bool block_udp = Preferences::GetBool( 480 "media.peerconnection.nat_simulator.block_udp", false); 481 bool block_tls = Preferences::GetBool( 482 "media.peerconnection.nat_simulator.block_tls", false); 483 int error_code_for_drop = Preferences::GetInt( 484 "media.peerconnection.nat_simulator.error_code_for_drop", 0); 485 nsAutoCString mapping_type; 486 (void)Preferences::GetCString( 487 "media.peerconnection.nat_simulator.mapping_type", mapping_type); 488 nsAutoCString filtering_type; 489 (void)Preferences::GetCString( 490 "media.peerconnection.nat_simulator.filtering_type", filtering_type); 491 nsAutoCString redirect_address; 492 (void)Preferences::GetCString( 493 "media.peerconnection.nat_simulator.redirect_address", redirect_address); 494 nsAutoCString redirect_targets; 495 (void)Preferences::GetCString( 496 "media.peerconnection.nat_simulator.redirect_targets", redirect_targets); 497 int network_delay_ms = Preferences::GetInt( 498 "media.peerconnection.nat_simulator.network_delay_ms", 0); 499 500 if (block_udp || block_tcp || block_tls || !mapping_type.IsEmpty() || 501 !filtering_type.IsEmpty() || !redirect_address.IsEmpty()) { 502 CSFLogDebug(LOGTAG, "NAT filtering type: %s", filtering_type.get()); 503 CSFLogDebug(LOGTAG, "NAT mapping type: %s", mapping_type.get()); 504 CSFLogDebug(LOGTAG, "NAT network delay: %d", network_delay_ms); 505 NrIceCtx::NatSimulatorConfig natConfig; 506 natConfig.mBlockUdp = block_udp; 507 natConfig.mBlockTcp = block_tcp; 508 natConfig.mBlockTls = block_tls; 509 natConfig.mErrorCodeForDrop = error_code_for_drop; 510 natConfig.mFilteringType = filtering_type; 511 natConfig.mMappingType = mapping_type; 512 natConfig.mNetworkDelayMs = network_delay_ms; 513 if (redirect_address.Length()) { 514 CSFLogDebug(LOGTAG, "Redirect address: %s", redirect_address.get()); 515 CSFLogDebug(LOGTAG, "Redirect targets: %s", redirect_targets.get()); 516 natConfig.mRedirectAddress = redirect_address; 517 std::stringstream str(redirect_targets.Data()); 518 std::string target; 519 while (getline(str, target, ',')) { 520 CSFLogDebug(LOGTAG, "Adding target: %s", target.c_str()); 521 natConfig.mRedirectTargets.AppendElement(target); 522 } 523 } 524 return Some(natConfig); 525 } 526 return Nothing(); 527 } 528 529 void MediaTransportHandlerSTS::CreateIceCtx(const std::string& aName) { 530 mInitPromise = InvokeAsync( 531 GetMainThreadSerialEventTarget(), __func__, 532 [=, self = RefPtr<MediaTransportHandlerSTS>(this)]() { 533 CSFLogDebug(LOGTAG, "%s starting", __func__); 534 if (!NSS_IsInitialized()) { 535 if (NSS_NoDB_Init(nullptr) != SECSuccess) { 536 MOZ_CRASH(); 537 return InitPromise::CreateAndReject("NSS_NoDB_Init failed", 538 __func__); 539 } 540 541 if (NS_FAILED(mozilla::psm::InitializeCipherSuite())) { 542 MOZ_CRASH(); 543 return InitPromise::CreateAndReject("InitializeCipherSuite failed", 544 __func__); 545 } 546 547 mozilla::psm::DisableMD5(); 548 } 549 550 static bool globalInitDone = false; 551 if (!globalInitDone) { 552 // Ensure the DNS service is initted for the first time on main 553 DebugOnly<RefPtr<nsIDNSService>> dnsService = 554 RefPtr<nsIDNSService>(nsDNSService::GetXPCOMSingleton()); 555 MOZ_ASSERT(dnsService.value); 556 mStsThread->Dispatch( 557 WrapRunnableNM(&NrIceCtx::InitializeGlobals, GetGlobalConfig()), 558 NS_DISPATCH_NORMAL); 559 globalInitDone = true; 560 } 561 562 // Give us a way to globally turn off TURN support 563 mTurnDisabled = 564 Preferences::GetBool("media.peerconnection.turn.disable", false); 565 // We are reading these here, because when we setup the DTLS transport 566 // we are on the wrong thread to read prefs 567 mMinDtlsVersion = 568 Preferences::GetUint("media.peerconnection.dtls.version.min"); 569 mMaxDtlsVersion = 570 Preferences::GetUint("media.peerconnection.dtls.version.max"); 571 mForceNoHost = 572 Preferences::GetBool("media.peerconnection.ice.no_host", false); 573 mNatConfig = GetNatConfig(); 574 mAllowLoopback = 575 Preferences::GetBool("media.peerconnection.ice.loopback", false); 576 mAllowLinkLocal = 577 Preferences::GetBool("media.peerconnection.ice.link_local", false); 578 579 MOZ_RELEASE_ASSERT(STSShutdownHandler::Instance()); 580 STSShutdownHandler::Instance()->Register(this); 581 582 return InvokeAsync( 583 mStsThread, __func__, 584 [=, self = RefPtr<MediaTransportHandlerSTS>(this)]() { 585 mIceCtx = NrIceCtx::Create(aName); 586 if (!mIceCtx) { 587 return InitPromise::CreateAndReject("NrIceCtx::Create failed", 588 __func__); 589 } 590 591 mIceCtx->SignalConnectionStateChange.connect( 592 this, &MediaTransportHandlerSTS::OnConnectionStateChange); 593 594 mDNSResolver = new NrIceResolver; 595 nsresult rv; 596 if (NS_FAILED(rv = mDNSResolver->Init())) { 597 CSFLogError(LOGTAG, "%s: Failed to initialize dns resolver", 598 __FUNCTION__); 599 return InitPromise::CreateAndReject( 600 "Failed to initialize dns resolver", __func__); 601 } 602 if (NS_FAILED(rv = mIceCtx->SetResolver( 603 mDNSResolver->AllocateResolver()))) { 604 CSFLogError(LOGTAG, "%s: Failed to get dns resolver", 605 __FUNCTION__); 606 return InitPromise::CreateAndReject( 607 "Failed to get dns resolver", __func__); 608 } 609 610 CSFLogDebug(LOGTAG, "%s done", __func__); 611 return InitPromise::CreateAndResolve(true, __func__); 612 }); 613 }); 614 } 615 616 nsresult MediaTransportHandlerSTS::SetIceConfig( 617 const nsTArray<dom::RTCIceServer>& aIceServers, 618 dom::RTCIceTransportPolicy aIcePolicy) { 619 // We rely on getting an error when this happens, so do it up front. 620 std::vector<NrIceStunServer> stunServers; 621 std::vector<NrIceTurnServer> turnServers; 622 nsresult rv = ConvertIceServers(aIceServers, &stunServers, &turnServers); 623 if (NS_FAILED(rv)) { 624 return rv; 625 } 626 627 MOZ_RELEASE_ASSERT(mInitPromise); 628 629 mInitPromise->Then( 630 mStsThread, __func__, 631 [=, self = RefPtr<MediaTransportHandlerSTS>(this)]() { 632 if (!mIceCtx) { 633 CSFLogError(LOGTAG, "%s: mIceCtx is null", __FUNCTION__); 634 return; 635 } 636 NrIceCtx::Config config; 637 config.mPolicy = toNrIcePolicy(aIcePolicy); 638 if (config.mPolicy == NrIceCtx::ICE_POLICY_ALL && mForceNoHost) { 639 config.mPolicy = NrIceCtx::ICE_POLICY_NO_HOST; 640 } 641 642 config.mAllowLoopback = mAllowLoopback; 643 config.mAllowLinkLocal = mAllowLinkLocal; 644 config.mNatSimulatorConfig = mNatConfig; 645 646 nsresult rv; 647 648 if (NS_FAILED(rv = mIceCtx->SetStunServers(stunServers))) { 649 CSFLogError(LOGTAG, "%s: Failed to set stun servers", __FUNCTION__); 650 return; 651 } 652 if (!mTurnDisabled) { 653 if (NS_FAILED(rv = mIceCtx->SetTurnServers(turnServers))) { 654 CSFLogError(LOGTAG, "%s: Failed to set turn servers", __FUNCTION__); 655 return; 656 } 657 } else if (!turnServers.empty()) { 658 CSFLogError(LOGTAG, "%s: Setting turn servers disabled", 659 __FUNCTION__); 660 } 661 if (NS_FAILED(rv = mIceCtx->SetIceConfig(config))) { 662 CSFLogError(LOGTAG, "%s: Failed to set config", __FUNCTION__); 663 } 664 }); 665 666 return NS_OK; 667 } 668 669 void MediaTransportHandlerSTS::Shutdown() { 670 CSFLogDebug(LOGTAG, "%s", __func__); 671 MOZ_ASSERT(NS_IsMainThread()); 672 mStsThread->Dispatch(NewNonOwningRunnableMethod( 673 __func__, this, &MediaTransportHandlerSTS::Shutdown_s)); 674 } 675 676 void MediaTransportHandlerSTS::Shutdown_s() { 677 CSFLogDebug(LOGTAG, "%s", __func__); 678 // Clear the transports before destroying the ice ctx so that 679 // the close_notify alerts have a chance to be sent as the 680 // TransportFlow destructors execute. 681 mTransports.clear(); 682 if (mIceCtx) { 683 NrIceStats stats = mIceCtx->Destroy(); 684 CSFLogDebug(LOGTAG, 685 "Ice Telemetry: stun (retransmits: %d)" 686 " turn (401s: %d 403s: %d 438s: %d)", 687 stats.stun_retransmits, stats.turn_401s, stats.turn_403s, 688 stats.turn_438s); 689 } 690 mIceCtx = nullptr; 691 mDNSResolver = nullptr; 692 } 693 694 void MediaTransportHandlerSTS::Destroy() { 695 CSFLogDebug(LOGTAG, "%s %p", __func__, this); 696 // Our "destruction tour" starts on main, because we need to deregister. 697 if (!NS_IsMainThread()) { 698 GetMainThreadSerialEventTarget()->Dispatch( 699 NewNonOwningRunnableMethod("MediaTransportHandlerSTS::Destroy", this, 700 &MediaTransportHandlerSTS::Destroy)); 701 return; 702 } 703 704 MOZ_ASSERT(NS_IsMainThread()); 705 if (STSShutdownHandler::Instance()) { 706 STSShutdownHandler::Instance()->Deregister(this); 707 Shutdown(); 708 } 709 710 // mIceCtx still has a reference to us via sigslot! We must dispach to STS, 711 // and clean up there. 712 nsresult rv = mStsThread->Dispatch( 713 NewNonOwningRunnableMethod("MediaTransportHandlerSTS::DestroyFinal", this, 714 &MediaTransportHandlerSTS::DestroyFinal)); 715 if (NS_WARN_IF(NS_FAILED(rv))) { 716 CSFLogError(LOGTAG, 717 "Unable to dispatch to STS: why has the XPCOM shutdown handler " 718 "not been invoked?"); 719 delete this; 720 } 721 } 722 723 void MediaTransportHandlerSTS::DestroyFinal() { delete this; } 724 725 void MediaTransportHandlerSTS::SetProxyConfig( 726 NrSocketProxyConfig&& aProxyConfig) { 727 MOZ_RELEASE_ASSERT(mInitPromise); 728 729 mInitPromise->Then( 730 mStsThread, __func__, 731 [this, self = RefPtr<MediaTransportHandlerSTS>(this), 732 aProxyConfig = std::move(aProxyConfig)]() mutable { 733 if (!mIceCtx) { 734 return; // Probably due to XPCOM shutdown 735 } 736 737 mIceCtx->SetProxyConfig(std::move(aProxyConfig)); 738 }, 739 [](const std::string& aError) {}); 740 } 741 742 void MediaTransportHandlerSTS::EnsureProvisionalTransport( 743 const std::string& aTransportId, const std::string& aUfrag, 744 const std::string& aPwd, int aComponentCount) { 745 MOZ_RELEASE_ASSERT(mInitPromise); 746 747 mInitPromise->Then( 748 mStsThread, __func__, 749 [=, self = RefPtr<MediaTransportHandlerSTS>(this)]() { 750 if (!mIceCtx) { 751 return; // Probably due to XPCOM shutdown 752 } 753 754 RefPtr<NrIceMediaStream> stream(mIceCtx->GetStream(aTransportId)); 755 if (!stream) { 756 CSFLogDebug(LOGTAG, "%s: Creating ICE media stream=%s components=%d", 757 mIceCtx->name().c_str(), aTransportId.c_str(), 758 aComponentCount); 759 760 std::ostringstream os; 761 os << mIceCtx->name() << " transport-id=" << aTransportId; 762 stream = 763 mIceCtx->CreateStream(aTransportId, os.str(), aComponentCount); 764 765 if (!stream) { 766 CSFLogError(LOGTAG, "Failed to create ICE stream."); 767 return; 768 } 769 770 stream->SignalCandidate.connect( 771 this, &MediaTransportHandlerSTS::OnCandidateFound); 772 stream->SignalGatheringStateChange.connect( 773 this, &MediaTransportHandlerSTS::OnGatheringStateChange); 774 } 775 776 // Begins an ICE restart if this stream has a different ufrag/pwd 777 stream->SetIceCredentials(aUfrag, aPwd); 778 779 // Make sure there's an entry in mTransports 780 mTransports[aTransportId]; 781 }, 782 [](const std::string& aError) {}); 783 } 784 785 void MediaTransportHandlerSTS::ActivateTransport( 786 const std::string& aTransportId, const std::string& aLocalUfrag, 787 const std::string& aLocalPwd, size_t aComponentCount, 788 const std::string& aUfrag, const std::string& aPassword, 789 const nsTArray<uint8_t>& aKeyDer, const nsTArray<uint8_t>& aCertDer, 790 SSLKEAType aAuthType, bool aDtlsClient, const DtlsDigestList& aDigests, 791 bool aPrivacyRequested) { 792 MOZ_RELEASE_ASSERT(mInitPromise); 793 794 mInitPromise->Then( 795 mStsThread, __func__, 796 [=, keyDer = aKeyDer.Clone(), certDer = aCertDer.Clone(), 797 self = RefPtr<MediaTransportHandlerSTS>(this)]() { 798 if (!mIceCtx) { 799 return; // Probably due to XPCOM shutdown 800 } 801 802 MOZ_ASSERT(aComponentCount); 803 RefPtr<DtlsIdentity> dtlsIdentity( 804 DtlsIdentity::Deserialize(keyDer, certDer, aAuthType)); 805 if (!dtlsIdentity) { 806 MOZ_ASSERT(false); 807 return; 808 } 809 810 RefPtr<NrIceMediaStream> stream(mIceCtx->GetStream(aTransportId)); 811 if (!stream) { 812 MOZ_ASSERT(false); 813 return; 814 } 815 816 CSFLogDebug(LOGTAG, "%s: Activating ICE media stream=%s components=%u", 817 mIceCtx->name().c_str(), aTransportId.c_str(), 818 static_cast<unsigned>(aComponentCount)); 819 820 std::vector<std::string> attrs; 821 attrs.reserve(2 /* ufrag + pwd */); 822 attrs.push_back("ice-ufrag:" + aUfrag); 823 attrs.push_back("ice-pwd:" + aPassword); 824 825 // If we started an ICE restart in EnsureProvisionalTransport, this is 826 // where we decide whether to commit or rollback. 827 nsresult rv = stream->ConnectToPeer(aLocalUfrag, aLocalPwd, attrs); 828 if (NS_FAILED(rv)) { 829 CSFLogError(LOGTAG, "Couldn't parse ICE attributes, rv=%u", 830 static_cast<unsigned>(rv)); 831 MOZ_ASSERT(false); 832 return; 833 } 834 835 Transport transport = mTransports[aTransportId]; 836 if (!transport.mFlow) { 837 transport.mFlow = 838 CreateTransportFlow(aTransportId, false, dtlsIdentity, 839 aDtlsClient, aDigests, aPrivacyRequested); 840 if (!transport.mFlow) { 841 return; 842 } 843 TransportLayer* dtls = 844 transport.mFlow->GetLayer(TransportLayerDtls::ID()); 845 dtls->SignalStateChange.connect( 846 this, &MediaTransportHandlerSTS::OnStateChange); 847 if (aComponentCount < 2) { 848 dtls->SignalStateChange.connect( 849 this, &MediaTransportHandlerSTS::OnRtcpStateChange); 850 } 851 } 852 853 if (aComponentCount == 2) { 854 if (!transport.mRtcpFlow) { 855 transport.mRtcpFlow = 856 CreateTransportFlow(aTransportId, true, dtlsIdentity, 857 aDtlsClient, aDigests, aPrivacyRequested); 858 if (!transport.mRtcpFlow) { 859 return; 860 } 861 TransportLayer* dtls = 862 transport.mRtcpFlow->GetLayer(TransportLayerDtls::ID()); 863 dtls->SignalStateChange.connect( 864 this, &MediaTransportHandlerSTS::OnRtcpStateChange); 865 } 866 } else { 867 transport.mRtcpFlow = nullptr; 868 // components are 1-indexed 869 stream->DisableComponent(2); 870 } 871 872 mTransports[aTransportId] = transport; 873 }, 874 [](const std::string& aError) {}); 875 } 876 877 void MediaTransportHandlerSTS::SetTargetForDefaultLocalAddressLookup( 878 const std::string& aTargetIp, uint16_t aTargetPort) { 879 MOZ_RELEASE_ASSERT(mInitPromise); 880 881 mInitPromise->Then( 882 mStsThread, __func__, 883 [=, self = RefPtr<MediaTransportHandlerSTS>(this)]() { 884 if (!mIceCtx) { 885 return; // Probably due to XPCOM shutdown 886 } 887 888 mIceCtx->SetTargetForDefaultLocalAddressLookup(aTargetIp, aTargetPort); 889 }, 890 [](const std::string& aError) {}); 891 } 892 893 void MediaTransportHandlerSTS::StartIceGathering( 894 bool aDefaultRouteOnly, bool aObfuscateHostAddresses, 895 const nsTArray<NrIceStunAddr>& aStunAddrs) { 896 MOZ_RELEASE_ASSERT(mInitPromise); 897 898 mInitPromise->Then( 899 mStsThread, __func__, 900 [=, stunAddrs = aStunAddrs.Clone(), 901 self = RefPtr<MediaTransportHandlerSTS>(this)]() { 902 if (!mIceCtx) { 903 return; // Probably due to XPCOM shutdown 904 } 905 906 mObfuscateHostAddresses = aObfuscateHostAddresses; 907 908 // Belt and suspenders - in e10s mode, the call below to SetStunAddrs 909 // needs to have the proper flags set on ice ctx. For non-e10s, 910 // setting those flags happens in StartGathering. We could probably 911 // just set them here, and only do it here. 912 mIceCtx->SetCtxFlags(aDefaultRouteOnly); 913 914 if (stunAddrs.Length()) { 915 mIceCtx->SetStunAddrs(stunAddrs); 916 } 917 918 // Start gathering, but only if there are streams 919 if (!mIceCtx->GetStreams().empty()) { 920 mIceCtx->StartGathering(aDefaultRouteOnly, aObfuscateHostAddresses); 921 } 922 }, 923 [](const std::string& aError) {}); 924 } 925 926 void MediaTransportHandlerSTS::StartIceChecks( 927 bool aIsControlling, const std::vector<std::string>& aIceOptions) { 928 MOZ_RELEASE_ASSERT(mInitPromise); 929 930 mInitPromise->Then( 931 mStsThread, __func__, 932 [=, self = RefPtr<MediaTransportHandlerSTS>(this)]() { 933 if (!mIceCtx) { 934 return; // Probably due to XPCOM shutdown 935 } 936 937 nsresult rv = mIceCtx->ParseGlobalAttributes(aIceOptions); 938 if (NS_FAILED(rv)) { 939 CSFLogError(LOGTAG, "%s: couldn't parse global parameters", 940 __FUNCTION__); 941 return; 942 } 943 944 rv = mIceCtx->SetControlling(aIsControlling ? NrIceCtx::ICE_CONTROLLING 945 : NrIceCtx::ICE_CONTROLLED); 946 if (NS_FAILED(rv)) { 947 CSFLogError(LOGTAG, "%s: couldn't set controlling to %d", 948 __FUNCTION__, aIsControlling); 949 return; 950 } 951 952 rv = mIceCtx->StartChecks(); 953 if (NS_FAILED(rv)) { 954 CSFLogError(LOGTAG, "%s: couldn't start checks", __FUNCTION__); 955 return; 956 } 957 }, 958 [](const std::string& aError) {}); 959 } 960 961 void TokenizeCandidate(const std::string& aCandidate, 962 std::vector<std::string>& aTokens) { 963 aTokens.clear(); 964 965 std::istringstream iss(aCandidate); 966 std::string token; 967 while (std::getline(iss, token, ' ')) { 968 aTokens.push_back(token); 969 } 970 } 971 972 void MediaTransportHandlerSTS::AddIceCandidate( 973 const std::string& aTransportId, const std::string& aCandidate, 974 const std::string& aUfrag, const std::string& aObfuscatedAddress) { 975 MOZ_RELEASE_ASSERT(mInitPromise); 976 977 mInitPromise->Then( 978 mStsThread, __func__, 979 [=, self = RefPtr<MediaTransportHandlerSTS>(this)]() { 980 if (!mIceCtx) { 981 return; // Probably due to XPCOM shutdown 982 } 983 984 std::vector<std::string> tokens; 985 TokenizeCandidate(aCandidate, tokens); 986 987 RefPtr<NrIceMediaStream> stream(mIceCtx->GetStream(aTransportId)); 988 if (!stream) { 989 CSFLogError(LOGTAG, 990 "No ICE stream for candidate with transport id %s: %s", 991 aTransportId.c_str(), aCandidate.c_str()); 992 return; 993 } 994 995 nsresult rv = stream->ParseTrickleCandidate(aCandidate, aUfrag, 996 aObfuscatedAddress); 997 if (NS_SUCCEEDED(rv)) { 998 // If the address is not obfuscated, we want to track it as 999 // explicitly signaled so that we know it is fine to reveal 1000 // the address later on. 1001 if (mObfuscateHostAddresses && tokens.size() > 4 && 1002 aObfuscatedAddress.empty()) { 1003 mSignaledAddresses.insert(tokens[4]); 1004 } 1005 } else { 1006 CSFLogError(LOGTAG, 1007 "Couldn't process ICE candidate with transport id %s: " 1008 "%s", 1009 aTransportId.c_str(), aCandidate.c_str()); 1010 } 1011 }, 1012 [](const std::string& aError) {}); 1013 } 1014 1015 void MediaTransportHandlerSTS::UpdateNetworkState(bool aOnline) { 1016 MOZ_RELEASE_ASSERT(mInitPromise); 1017 1018 mInitPromise->Then( 1019 mStsThread, __func__, 1020 [=, self = RefPtr<MediaTransportHandlerSTS>(this)]() { 1021 if (!mIceCtx) { 1022 return; // Probably due to XPCOM shutdown 1023 } 1024 1025 mIceCtx->UpdateNetworkState(aOnline); 1026 }, 1027 [](const std::string& aError) {}); 1028 } 1029 1030 void MediaTransportHandlerSTS::RemoveTransportsExcept( 1031 const std::set<std::string>& aTransportIds) { 1032 MOZ_RELEASE_ASSERT(mInitPromise); 1033 1034 mInitPromise->Then( 1035 mStsThread, __func__, 1036 [=, self = RefPtr<MediaTransportHandlerSTS>(this)]() { 1037 if (!mIceCtx) { 1038 return; // Probably due to XPCOM shutdown 1039 } 1040 1041 for (auto it = mTransports.begin(); it != mTransports.end();) { 1042 const std::string transportId(it->first); 1043 if (!aTransportIds.count(transportId)) { 1044 if (it->second.mFlow) { 1045 OnStateChange(transportId, TransportLayer::TS_NONE); 1046 OnRtcpStateChange(transportId, TransportLayer::TS_NONE); 1047 } 1048 // Erase the transport before destroying the ice stream so that 1049 // the close_notify alerts have a chance to be sent as the 1050 // TransportFlow destructors execute. 1051 it = mTransports.erase(it); 1052 // We're already on the STS thread, but the TransportFlow 1053 // destructor executed when mTransports.erase(it) is called 1054 // above dispatches the call to DestroyFinal to the STS thread. If 1055 // we don't also dispatch the call to destroy the NrIceMediaStream 1056 // to the STS thread, it will tear down the NrIceMediaStream 1057 // before the TransportFlow is destroyed. Without a valid 1058 // NrIceMediaStream the close_notify alert cannot be sent. 1059 mStsThread->Dispatch(NS_NewRunnableFunction( 1060 __func__, [iceCtx = RefPtr<NrIceCtx>(mIceCtx), transportId] { 1061 iceCtx->DestroyStream(transportId); 1062 })); 1063 } else { 1064 MOZ_ASSERT(it->second.mFlow); 1065 ++it; 1066 } 1067 } 1068 }, 1069 [](const std::string& aError) {}); 1070 } 1071 1072 void MediaTransportHandlerSTS::SendPacket(const std::string& aTransportId, 1073 MediaPacket&& aPacket) { 1074 MOZ_RELEASE_ASSERT(mInitPromise); 1075 1076 mInitPromise->Then( 1077 mStsThread, __func__, 1078 [this, self = RefPtr<MediaTransportHandlerSTS>(this), aTransportId, 1079 aPacket = std::move(aPacket)]() mutable { 1080 if (!mIceCtx) { 1081 return; // Probably due to XPCOM shutdown 1082 } 1083 1084 MOZ_ASSERT(aPacket.type() != MediaPacket::UNCLASSIFIED); 1085 RefPtr<TransportFlow> flow = 1086 GetTransportFlow(aTransportId, aPacket.type() == MediaPacket::RTCP); 1087 1088 if (!flow) { 1089 CSFLogError(LOGTAG, 1090 "%s: No such transport flow (%s) for outgoing packet", 1091 mIceCtx->name().c_str(), aTransportId.c_str()); 1092 return; 1093 } 1094 1095 TransportLayer* layer = nullptr; 1096 switch (aPacket.type()) { 1097 case MediaPacket::SCTP: 1098 layer = flow->GetLayer(TransportLayerDtls::ID()); 1099 break; 1100 case MediaPacket::RTP: 1101 case MediaPacket::RTCP: 1102 layer = flow->GetLayer(TransportLayerSrtp::ID()); 1103 break; 1104 default: 1105 // Maybe it would be useful to allow the injection of other packet 1106 // types for testing? 1107 MOZ_ASSERT(false); 1108 return; 1109 } 1110 1111 MOZ_ASSERT(layer); 1112 1113 if (int error = layer->SendPacket(aPacket); error < 0) { 1114 CSFLogError(LOGTAG, 1115 "%s: Transport flow (%s) failed to send packet. error=%d", 1116 mIceCtx->name().c_str(), aTransportId.c_str(), error); 1117 } 1118 }, 1119 [](const std::string& aError) {}); 1120 } 1121 1122 TransportLayer::State MediaTransportHandler::GetState( 1123 const std::string& aTransportId, bool aRtcp) const { 1124 MutexAutoLock lock(mStateCacheMutex); 1125 const std::map<std::string, TransportLayer::State>* cache = nullptr; 1126 if (aRtcp) { 1127 cache = &mRtcpStateCache; 1128 } else { 1129 cache = &mStateCache; 1130 } 1131 1132 auto it = cache->find(aTransportId); 1133 if (it != cache->end()) { 1134 return it->second; 1135 } 1136 return TransportLayer::TS_NONE; 1137 } 1138 1139 void MediaTransportHandler::OnCandidate(const std::string& aTransportId, 1140 CandidateInfo&& aCandidateInfo) { 1141 mCandidateGathered.Notify(aTransportId, std::move(aCandidateInfo)); 1142 } 1143 1144 void MediaTransportHandler::OnAlpnNegotiated(const std::string& aAlpn) { 1145 const bool privacyRequested = aAlpn == "c-webrtc"; 1146 mAlpnNegotiated.Notify(aAlpn, privacyRequested); 1147 } 1148 1149 void MediaTransportHandler::OnGatheringStateChange( 1150 const std::string& aTransportId, dom::RTCIceGathererState aState) { 1151 mGatheringStateChange.Notify(aTransportId, aState); 1152 } 1153 1154 void MediaTransportHandler::OnConnectionStateChange( 1155 const std::string& aTransportId, dom::RTCIceTransportState aState) { 1156 mConnectionStateChange.Notify(aTransportId, aState); 1157 } 1158 1159 void MediaTransportHandler::OnPacketReceived(std::string&& aTransportId, 1160 MediaPacket&& aPacket) { 1161 switch (aPacket.type()) { 1162 case MediaPacket::UNCLASSIFIED: 1163 case MediaPacket::DTLS: 1164 case MediaPacket::SRTP: 1165 case MediaPacket::SRTCP: 1166 // Shouldn't happen, and nothing would care if it did 1167 break; 1168 case MediaPacket::RTP: 1169 case MediaPacket::RTCP: 1170 mRtpPacketReceived.Notify(std::forward<std::string>(aTransportId), 1171 std::forward<MediaPacket>(aPacket)); 1172 break; 1173 case MediaPacket::SCTP: 1174 mSctpPacketReceived.Notify(std::forward<std::string>(aTransportId), 1175 std::forward<MediaPacket>(aPacket)); 1176 break; 1177 } 1178 } 1179 1180 void MediaTransportHandler::OnEncryptedSending(const std::string& aTransportId, 1181 MediaPacket&& aPacket) { 1182 mEncryptedSending.Notify(aTransportId, std::move(aPacket)); 1183 } 1184 1185 void MediaTransportHandler::OnStateChange(const std::string& aTransportId, 1186 TransportLayer::State aState) { 1187 { 1188 MutexAutoLock lock(mStateCacheMutex); 1189 if (aState == TransportLayer::TS_NONE) { 1190 mStateCache.erase(aTransportId); 1191 } else { 1192 mStateCache[aTransportId] = aState; 1193 } 1194 } 1195 mStateChange.Notify(aTransportId, aState); 1196 } 1197 1198 void MediaTransportHandler::OnRtcpStateChange(const std::string& aTransportId, 1199 TransportLayer::State aState) { 1200 { 1201 MutexAutoLock lock(mStateCacheMutex); 1202 if (aState == TransportLayer::TS_NONE) { 1203 mRtcpStateCache.erase(aTransportId); 1204 } else { 1205 mRtcpStateCache[aTransportId] = aState; 1206 } 1207 } 1208 mRtcpStateChange.Notify(aTransportId, aState); 1209 } 1210 1211 RefPtr<dom::RTCStatsPromise> MediaTransportHandlerSTS::GetIceStats( 1212 const std::string& aTransportId, DOMHighResTimeStamp aNow) { 1213 MOZ_RELEASE_ASSERT(mInitPromise); 1214 1215 return mInitPromise->Then(mStsThread, __func__, [=, self = RefPtr(this)]() { 1216 UniquePtr<dom::RTCStatsCollection> stats(new dom::RTCStatsCollection); 1217 if (mIceCtx) { 1218 for (const auto& stream : mIceCtx->GetStreams()) { 1219 if (aTransportId.empty() || aTransportId == stream->GetId()) { 1220 GetIceStats(*stream, aNow, stats.get()); 1221 } 1222 } 1223 } 1224 return dom::RTCStatsPromise::CreateAndResolve(std::move(stats), __func__); 1225 }); 1226 } 1227 1228 RefPtr<MediaTransportHandler::IceLogPromise> 1229 MediaTransportHandlerSTS::GetIceLog(const nsCString& aPattern) { 1230 return InvokeAsync( 1231 mStsThread, __func__, [=, self = RefPtr<MediaTransportHandlerSTS>(this)] { 1232 dom::Sequence<nsString> converted; 1233 RLogConnector* logs = RLogConnector::GetInstance(); 1234 std::deque<std::string> result; 1235 // Might not exist yet. 1236 if (logs) { 1237 logs->Filter(aPattern.get(), 0, &result); 1238 } 1239 /// XXX(Bug 1631386) Check if we should reject the promise instead of 1240 /// crashing in an OOM situation. 1241 if (!converted.SetCapacity(result.size(), fallible)) { 1242 mozalloc_handle_oom(sizeof(nsString) * result.size()); 1243 } 1244 for (auto& line : result) { 1245 // Cannot fail, SetCapacity was called before. 1246 (void)converted.AppendElement(NS_ConvertUTF8toUTF16(line.c_str()), 1247 fallible); 1248 } 1249 return IceLogPromise::CreateAndResolve(std::move(converted), __func__); 1250 }); 1251 } 1252 1253 void MediaTransportHandlerSTS::ClearIceLog() { 1254 if (!mStsThread->IsOnCurrentThread()) { 1255 mStsThread->Dispatch(WrapRunnable(RefPtr<MediaTransportHandlerSTS>(this), 1256 &MediaTransportHandlerSTS::ClearIceLog), 1257 NS_DISPATCH_NORMAL); 1258 return; 1259 } 1260 1261 RLogConnector* logs = RLogConnector::GetInstance(); 1262 if (logs) { 1263 logs->Clear(); 1264 } 1265 } 1266 1267 void MediaTransportHandlerSTS::EnterPrivateMode() { 1268 if (!mStsThread->IsOnCurrentThread()) { 1269 mStsThread->Dispatch( 1270 WrapRunnable(RefPtr<MediaTransportHandlerSTS>(this), 1271 &MediaTransportHandlerSTS::EnterPrivateMode), 1272 NS_DISPATCH_NORMAL); 1273 return; 1274 } 1275 1276 RLogConnector::GetInstance()->EnterPrivateMode(); 1277 } 1278 1279 void MediaTransportHandlerSTS::ExitPrivateMode() { 1280 if (!mStsThread->IsOnCurrentThread()) { 1281 mStsThread->Dispatch( 1282 WrapRunnable(RefPtr<MediaTransportHandlerSTS>(this), 1283 &MediaTransportHandlerSTS::ExitPrivateMode), 1284 NS_DISPATCH_NORMAL); 1285 return; 1286 } 1287 1288 auto* log = RLogConnector::GetInstance(); 1289 MOZ_ASSERT(log); 1290 if (log) { 1291 log->ExitPrivateMode(); 1292 } 1293 } 1294 1295 static void ToRTCIceCandidateStats( 1296 const std::vector<NrIceCandidate>& candidates, 1297 dom::RTCStatsType candidateType, const nsString& transportId, 1298 DOMHighResTimeStamp now, dom::RTCStatsCollection* stats, 1299 bool obfuscateHostAddresses, 1300 const std::set<std::string>& signaledAddresses) { 1301 MOZ_ASSERT(stats); 1302 for (const auto& candidate : candidates) { 1303 dom::RTCIceCandidateStats cand; 1304 cand.mType.Construct(candidateType); 1305 NS_ConvertASCIItoUTF16 codeword(candidate.codeword.c_str()); 1306 cand.mTransportId.Construct(transportId); 1307 cand.mId.Construct(codeword); 1308 cand.mTimestamp.Construct(now); 1309 cand.mCandidateType.Construct(dom::RTCIceCandidateType(candidate.type)); 1310 cand.mPriority.Construct(candidate.priority); 1311 // https://tools.ietf.org/html/draft-ietf-rtcweb-mdns-ice-candidates-03#section-3.3.1 1312 // This obfuscates the address with the mDNS address if one exists 1313 if (!candidate.mdns_addr.empty()) { 1314 cand.mAddress.Construct( 1315 NS_ConvertASCIItoUTF16(candidate.mdns_addr.c_str())); 1316 } else if (obfuscateHostAddresses && 1317 candidate.type == NrIceCandidate::ICE_PEER_REFLEXIVE && 1318 signaledAddresses.find(candidate.cand_addr.host) == 1319 signaledAddresses.end()) { 1320 cand.mAddress.Construct(NS_ConvertASCIItoUTF16("(redacted)")); 1321 } else { 1322 cand.mAddress.Construct( 1323 NS_ConvertASCIItoUTF16(candidate.cand_addr.host.c_str())); 1324 } 1325 cand.mPort.Construct(candidate.cand_addr.port); 1326 cand.mProtocol.Construct( 1327 NS_ConvertASCIItoUTF16(candidate.cand_addr.transport.c_str())); 1328 if (candidateType == dom::RTCStatsType::Local_candidate && 1329 dom::RTCIceCandidateType(candidate.type) == 1330 dom::RTCIceCandidateType::Relay) { 1331 cand.mRelayProtocol.Construct( 1332 NS_ConvertASCIItoUTF16(candidate.local_addr.transport.c_str())); 1333 } 1334 cand.mProxied.Construct(NS_ConvertASCIItoUTF16( 1335 candidate.is_proxied ? "proxied" : "non-proxied")); 1336 if (!stats->mIceCandidateStats.AppendElement(cand, fallible)) { 1337 // XXX(Bug 1632090) Instead of extending the array 1-by-1 (which might 1338 // involve multiple reallocations) and potentially crashing here, 1339 // SetCapacity could be called outside the loop once. 1340 mozalloc_handle_oom(0); 1341 } 1342 if (candidate.trickled) { 1343 if (!stats->mTrickledIceCandidateStats.AppendElement(cand, fallible)) { 1344 mozalloc_handle_oom(0); 1345 } 1346 } 1347 } 1348 } 1349 1350 void MediaTransportHandlerSTS::GetIceStats( 1351 const NrIceMediaStream& aStream, DOMHighResTimeStamp aNow, 1352 dom::RTCStatsCollection* aStats) const { 1353 MOZ_ASSERT(mStsThread->IsOnCurrentThread()); 1354 1355 NS_ConvertASCIItoUTF16 transportId(aStream.GetId().c_str()); 1356 1357 std::vector<NrIceCandidatePair> candPairs; 1358 nsresult res = aStream.GetCandidatePairs(&candPairs); 1359 if (NS_FAILED(res)) { 1360 CSFLogError(LOGTAG, 1361 "%s: Error getting candidate pairs for transport id \"%s\"", 1362 __FUNCTION__, aStream.GetId().c_str()); 1363 return; 1364 } 1365 1366 for (auto& candPair : candPairs) { 1367 NS_ConvertASCIItoUTF16 codeword(candPair.codeword.c_str()); 1368 NS_ConvertASCIItoUTF16 localCodeword(candPair.local.codeword.c_str()); 1369 NS_ConvertASCIItoUTF16 remoteCodeword(candPair.remote.codeword.c_str()); 1370 // Only expose candidate-pair statistics to chrome, until we've thought 1371 // through the implications of exposing it to content. 1372 1373 dom::RTCIceCandidatePairStats s; 1374 s.mId.Construct(codeword); 1375 s.mTransportId.Construct(transportId); 1376 s.mTimestamp.Construct(aNow); 1377 s.mType.Construct(dom::RTCStatsType::Candidate_pair); 1378 s.mLocalCandidateId.Construct(localCodeword); 1379 s.mRemoteCandidateId.Construct(remoteCodeword); 1380 s.mNominated.Construct(candPair.nominated); 1381 s.mWritable.Construct(candPair.writable); 1382 s.mReadable.Construct(candPair.readable); 1383 s.mPriority.Construct(candPair.priority); 1384 s.mSelected.Construct(candPair.selected); 1385 s.mBytesSent.Construct(candPair.bytes_sent); 1386 s.mBytesReceived.Construct(candPair.bytes_recvd); 1387 s.mLastPacketSentTimestamp.Construct(candPair.ms_since_last_send); 1388 s.mLastPacketReceivedTimestamp.Construct(candPair.ms_since_last_recv); 1389 s.mState.Construct(dom::RTCStatsIceCandidatePairState(candPair.state)); 1390 s.mResponsesReceived.Construct(candPair.responses_recvd); 1391 s.mCurrentRoundTripTime.Construct(candPair.current_rtt_ms / 1000.0); 1392 s.mTotalRoundTripTime.Construct(candPair.total_rtt_ms / 1000.0); 1393 s.mComponentId.Construct(candPair.component_id); 1394 if (!aStats->mIceCandidatePairStats.AppendElement(s, fallible)) { 1395 // XXX(Bug 1632090) Instead of extending the array 1-by-1 (which might 1396 // involve multiple reallocations) and potentially crashing here, 1397 // SetCapacity could be called outside the loop once. 1398 mozalloc_handle_oom(0); 1399 } 1400 } 1401 1402 std::vector<NrIceCandidate> candidates; 1403 if (NS_SUCCEEDED(aStream.GetLocalCandidates(&candidates))) { 1404 ToRTCIceCandidateStats(candidates, dom::RTCStatsType::Local_candidate, 1405 transportId, aNow, aStats, mObfuscateHostAddresses, 1406 mSignaledAddresses); 1407 // add the local candidates unparsed string to a sequence 1408 for (const auto& candidate : candidates) { 1409 if (!aStats->mRawLocalCandidates.AppendElement( 1410 NS_ConvertASCIItoUTF16(candidate.label.c_str()), fallible)) { 1411 // XXX(Bug 1632090) Instead of extending the array 1-by-1 (which might 1412 // involve multiple reallocations) and potentially crashing here, 1413 // SetCapacity could be called outside the loop once. 1414 mozalloc_handle_oom(0); 1415 } 1416 } 1417 } 1418 candidates.clear(); 1419 1420 if (NS_SUCCEEDED(aStream.GetRemoteCandidates(&candidates))) { 1421 ToRTCIceCandidateStats(candidates, dom::RTCStatsType::Remote_candidate, 1422 transportId, aNow, aStats, mObfuscateHostAddresses, 1423 mSignaledAddresses); 1424 // add the remote candidates unparsed string to a sequence 1425 for (const auto& candidate : candidates) { 1426 if (!aStats->mRawRemoteCandidates.AppendElement( 1427 NS_ConvertASCIItoUTF16(candidate.label.c_str()), fallible)) { 1428 // XXX(Bug 1632090) Instead of extending the array 1-by-1 (which might 1429 // involve multiple reallocations) and potentially crashing here, 1430 // SetCapacity could be called outside the loop once. 1431 mozalloc_handle_oom(0); 1432 } 1433 } 1434 } 1435 } 1436 1437 RefPtr<TransportFlow> MediaTransportHandlerSTS::GetTransportFlow( 1438 const std::string& aTransportId, bool aIsRtcp) const { 1439 auto it = mTransports.find(aTransportId); 1440 if (it == mTransports.end()) { 1441 return nullptr; 1442 } 1443 1444 if (aIsRtcp) { 1445 return it->second.mRtcpFlow ? it->second.mRtcpFlow : it->second.mFlow; 1446 ; 1447 } 1448 1449 return it->second.mFlow; 1450 } 1451 1452 RefPtr<TransportFlow> MediaTransportHandlerSTS::CreateTransportFlow( 1453 const std::string& aTransportId, bool aIsRtcp, 1454 const RefPtr<DtlsIdentity>& aDtlsIdentity, bool aDtlsClient, 1455 const DtlsDigestList& aDigests, bool aPrivacyRequested) { 1456 nsresult rv; 1457 RefPtr<TransportFlow> flow = new TransportFlow(aTransportId); 1458 1459 // The media streams are made on STS so we need to defer setup. 1460 auto ice = MakeUnique<TransportLayerIce>(); 1461 auto dtls = MakeUnique<TransportLayerDtls>(); 1462 auto srtp = MakeUnique<TransportLayerSrtp>(*dtls); 1463 dtls->SetRole(aDtlsClient ? TransportLayerDtls::CLIENT 1464 : TransportLayerDtls::SERVER); 1465 1466 dtls->SetIdentity(aDtlsIdentity); 1467 1468 dtls->SetMinMaxVersion( 1469 static_cast<TransportLayerDtls::Version>(mMinDtlsVersion), 1470 static_cast<TransportLayerDtls::Version>(mMaxDtlsVersion)); 1471 1472 for (const auto& digest : aDigests) { 1473 rv = dtls->SetVerificationDigest(digest); 1474 if (NS_FAILED(rv)) { 1475 CSFLogError(LOGTAG, "Could not set fingerprint"); 1476 return nullptr; 1477 } 1478 } 1479 1480 std::vector<uint16_t> srtpCiphers = 1481 TransportLayerDtls::GetDefaultSrtpCiphers(); 1482 1483 rv = dtls->SetSrtpCiphers(srtpCiphers); 1484 if (NS_FAILED(rv)) { 1485 CSFLogError(LOGTAG, "Couldn't set SRTP ciphers"); 1486 return nullptr; 1487 } 1488 1489 // Always permits negotiation of the confidential mode. 1490 // Only allow non-confidential (which is an allowed default), 1491 // if we aren't confidential. 1492 std::set<std::string> alpn = {"c-webrtc"}; 1493 std::string alpnDefault; 1494 if (!aPrivacyRequested) { 1495 alpnDefault = "webrtc"; 1496 alpn.insert(alpnDefault); 1497 } 1498 rv = dtls->SetAlpn(alpn, alpnDefault); 1499 if (NS_FAILED(rv)) { 1500 CSFLogError(LOGTAG, "Couldn't set ALPN"); 1501 return nullptr; 1502 } 1503 1504 ice->SetParameters(mIceCtx->GetStream(aTransportId), aIsRtcp ? 2 : 1); 1505 NS_ENSURE_SUCCESS(ice->Init(), nullptr); 1506 NS_ENSURE_SUCCESS(dtls->Init(), nullptr); 1507 NS_ENSURE_SUCCESS(srtp->Init(), nullptr); 1508 dtls->Chain(ice.get()); 1509 srtp->Chain(ice.get()); 1510 1511 dtls->SignalPacketReceived.connect(this, 1512 &MediaTransportHandlerSTS::PacketReceived); 1513 srtp->SignalPacketReceived.connect(this, 1514 &MediaTransportHandlerSTS::PacketReceived); 1515 ice->SignalPacketSending.connect( 1516 this, &MediaTransportHandlerSTS::EncryptedPacketSending); 1517 flow->PushLayer(ice.release()); 1518 flow->PushLayer(dtls.release()); 1519 flow->PushLayer(srtp.release()); 1520 return flow; 1521 } 1522 1523 static mozilla::dom::RTCIceGathererState toDomIceGathererState( 1524 NrIceMediaStream::GatheringState aState) { 1525 switch (aState) { 1526 case NrIceMediaStream::ICE_STREAM_GATHER_INIT: 1527 return dom::RTCIceGathererState::New; 1528 case NrIceMediaStream::ICE_STREAM_GATHER_STARTED: 1529 return dom::RTCIceGathererState::Gathering; 1530 case NrIceMediaStream::ICE_STREAM_GATHER_COMPLETE: 1531 return dom::RTCIceGathererState::Complete; 1532 } 1533 MOZ_CRASH(); 1534 } 1535 1536 void MediaTransportHandlerSTS::OnGatheringStateChange( 1537 const std::string& aTransportId, NrIceMediaStream::GatheringState aState) { 1538 OnGatheringStateChange(aTransportId, toDomIceGathererState(aState)); 1539 } 1540 1541 static mozilla::dom::RTCIceTransportState toDomIceTransportState( 1542 NrIceCtx::ConnectionState aState) { 1543 switch (aState) { 1544 case NrIceCtx::ICE_CTX_INIT: 1545 return dom::RTCIceTransportState::New; 1546 case NrIceCtx::ICE_CTX_CHECKING: 1547 return dom::RTCIceTransportState::Checking; 1548 case NrIceCtx::ICE_CTX_CONNECTED: 1549 return dom::RTCIceTransportState::Connected; 1550 case NrIceCtx::ICE_CTX_COMPLETED: 1551 return dom::RTCIceTransportState::Completed; 1552 case NrIceCtx::ICE_CTX_FAILED: 1553 return dom::RTCIceTransportState::Failed; 1554 case NrIceCtx::ICE_CTX_DISCONNECTED: 1555 return dom::RTCIceTransportState::Disconnected; 1556 case NrIceCtx::ICE_CTX_CLOSED: 1557 return dom::RTCIceTransportState::Closed; 1558 } 1559 MOZ_CRASH(); 1560 } 1561 1562 void MediaTransportHandlerSTS::OnConnectionStateChange( 1563 NrIceMediaStream* aIceStream, NrIceCtx::ConnectionState aState) { 1564 OnConnectionStateChange(aIceStream->GetId(), toDomIceTransportState(aState)); 1565 } 1566 1567 // The stuff below here will eventually go into the MediaTransportChild class 1568 void MediaTransportHandlerSTS::OnCandidateFound( 1569 NrIceMediaStream* aStream, const std::string& aCandidate, 1570 const std::string& aUfrag, const std::string& aMDNSAddr, 1571 const std::string& aActualAddr) { 1572 CandidateInfo info; 1573 info.mCandidate = aCandidate; 1574 MOZ_ASSERT(!aUfrag.empty()); 1575 info.mUfrag = aUfrag; 1576 NrIceCandidate defaultRtpCandidate; 1577 NrIceCandidate defaultRtcpCandidate; 1578 nsresult rv = aStream->GetDefaultCandidate(1, &defaultRtpCandidate); 1579 if (NS_SUCCEEDED(rv)) { 1580 if (!defaultRtpCandidate.mdns_addr.empty()) { 1581 info.mDefaultHostRtp = "0.0.0.0"; 1582 info.mDefaultPortRtp = 9; 1583 } else { 1584 info.mDefaultHostRtp = defaultRtpCandidate.cand_addr.host; 1585 info.mDefaultPortRtp = defaultRtpCandidate.cand_addr.port; 1586 } 1587 } else { 1588 CSFLogError(LOGTAG, 1589 "%s: GetDefaultCandidates failed for transport id %s, " 1590 "res=%u", 1591 __FUNCTION__, aStream->GetId().c_str(), 1592 static_cast<unsigned>(rv)); 1593 } 1594 1595 // Optional; component won't exist if doing rtcp-mux 1596 if (NS_SUCCEEDED(aStream->GetDefaultCandidate(2, &defaultRtcpCandidate))) { 1597 if (!defaultRtcpCandidate.mdns_addr.empty()) { 1598 info.mDefaultHostRtcp = defaultRtcpCandidate.mdns_addr; 1599 } else { 1600 info.mDefaultHostRtcp = defaultRtcpCandidate.cand_addr.host; 1601 } 1602 info.mDefaultPortRtcp = defaultRtcpCandidate.cand_addr.port; 1603 } 1604 1605 info.mMDNSAddress = aMDNSAddr; 1606 info.mActualAddress = aActualAddr; 1607 1608 OnCandidate(aStream->GetId(), std::move(info)); 1609 } 1610 1611 void MediaTransportHandlerSTS::OnStateChange(TransportLayer* aLayer, 1612 TransportLayer::State aState) { 1613 if (aState == TransportLayer::TS_OPEN) { 1614 MOZ_ASSERT(aLayer->id() == TransportLayerDtls::ID()); 1615 TransportLayerDtls* dtlsLayer = static_cast<TransportLayerDtls*>(aLayer); 1616 OnAlpnNegotiated(dtlsLayer->GetNegotiatedAlpn()); 1617 } 1618 1619 // DTLS state indicates the readiness of the transport as a whole, because 1620 // SRTP uses the keys from the DTLS handshake. 1621 MediaTransportHandler::OnStateChange(aLayer->flow_id(), aState); 1622 } 1623 1624 void MediaTransportHandlerSTS::OnRtcpStateChange(TransportLayer* aLayer, 1625 TransportLayer::State aState) { 1626 MediaTransportHandler::OnRtcpStateChange(aLayer->flow_id(), aState); 1627 } 1628 1629 void MediaTransportHandlerSTS::PacketReceived(TransportLayer* aLayer, 1630 MediaPacket& aPacket) { 1631 MEDIA_TRANSPORT_HANDLER_PACKET_RECEIVED(aPacket); 1632 OnPacketReceived(std::string(aLayer->flow_id()), std::move(aPacket)); 1633 } 1634 1635 void MediaTransportHandlerSTS::EncryptedPacketSending(TransportLayer* aLayer, 1636 MediaPacket& aPacket) { 1637 OnEncryptedSending(aLayer->flow_id(), std::move(aPacket)); 1638 } 1639 1640 } // namespace mozilla 1641 1642 #undef MEDIA_TRANSPORT_HANDLER_PACKET_RECEIVED