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