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