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