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 "MediaTransportHandlerIPC.h"
6 #include "mozilla/dom/MediaTransportChild.h"
7 #include "nsThreadUtils.h"
8 #include "mozilla/net/SocketProcessBridgeChild.h"
9 #include "mozilla/RefPtr.h"
10 #include "mozilla/ipc/BackgroundChild.h"
11 #include "mozilla/ipc/PBackgroundChild.h"
12 #include "CSFLog.h"
13 
14 namespace mozilla {
15 
16 static const char* mthipcLogTag = "MediaTransportHandler";
17 #ifdef LOGTAG
18 #  undef LOGTAG
19 #endif
20 #define LOGTAG mthipcLogTag
21 
MediaTransportHandlerIPC(nsISerialEventTarget * aCallbackThread)22 MediaTransportHandlerIPC::MediaTransportHandlerIPC(
23     nsISerialEventTarget* aCallbackThread)
24     : MediaTransportHandler(aCallbackThread) {
25   mInitPromise = net::SocketProcessBridgeChild::GetSocketProcessBridge()->Then(
26       mCallbackThread, __func__,
27       [this, self = RefPtr<MediaTransportHandlerIPC>(this)](
28           const RefPtr<net::SocketProcessBridgeChild>& aBridge) {
29         ipc::PBackgroundChild* actor =
30             ipc::BackgroundChild::GetOrCreateSocketActorForCurrentThread();
31         if (!actor) {
32           NS_WARNING(
33               "MediaTransportHandlerIPC async init failed! Webrtc networking "
34               "will not work!");
35           return InitPromise::CreateAndReject(
36               nsCString("GetOrCreateSocketActorForCurrentThread failed!"),
37               __func__);
38         }
39         MediaTransportChild* child = new MediaTransportChild(this);
40         actor->SetEventTargetForActor(child, mCallbackThread);
41         // PBackgroungChild owns mChild! When it is done with it,
42         // mChild will let us know it it going away.
43         mChild = actor->SendPMediaTransportConstructor(child);
44         CSFLogDebug(LOGTAG, "%s Init done", __func__);
45         return InitPromise::CreateAndResolve(true, __func__);
46       },
47       [=](const nsCString& aError) {
48         CSFLogError(LOGTAG,
49                     "MediaTransportHandlerIPC async init failed! Webrtc "
50                     "networking will not work! Error was %s",
51                     aError.get());
52         NS_WARNING(
53             "MediaTransportHandlerIPC async init failed! Webrtc networking "
54             "will not work!");
55         return InitPromise::CreateAndReject(aError, __func__);
56       });
57 }
58 
59 RefPtr<MediaTransportHandler::IceLogPromise>
GetIceLog(const nsCString & aPattern)60 MediaTransportHandlerIPC::GetIceLog(const nsCString& aPattern) {
61   return mInitPromise->Then(
62       mCallbackThread, __func__,
63       [=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /* dummy */) {
64         if (!mChild) {
65           return IceLogPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
66         }
67         // Compiler has trouble deducing the return type here for some reason,
68         // so we use a temp variable as a hint.
69         // SendGetIceLog _almost_ returns an IceLogPromise; the reject value
70         // differs (ipc::ResponseRejectReason vs nsresult) so we need to
71         // convert.
72         RefPtr<IceLogPromise> promise = mChild->SendGetIceLog(aPattern)->Then(
73             mCallbackThread, __func__,
74             [](WebrtcGlobalLog&& aLogLines) {
75               return IceLogPromise::CreateAndResolve(std::move(aLogLines),
76                                                      __func__);
77             },
78             [](ipc::ResponseRejectReason aReason) {
79               return IceLogPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
80             });
81         return promise;
82       },
83       [](const nsCString& aError) {
84         return IceLogPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
85       });
86 }
87 
ClearIceLog()88 void MediaTransportHandlerIPC::ClearIceLog() {
89   mInitPromise->Then(
90       mCallbackThread, __func__,
91       [=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
92         if (mChild) {
93           mChild->SendClearIceLog();
94         }
95       },
96       [](const nsCString& aError) {});
97 }
98 
EnterPrivateMode()99 void MediaTransportHandlerIPC::EnterPrivateMode() {
100   mInitPromise->Then(
101       mCallbackThread, __func__,
102       [=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
103         if (mChild) {
104           mChild->SendEnterPrivateMode();
105         }
106       },
107       [](const nsCString& aError) {});
108 }
109 
ExitPrivateMode()110 void MediaTransportHandlerIPC::ExitPrivateMode() {
111   mInitPromise->Then(
112       mCallbackThread, __func__,
113       [=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
114         if (mChild) {
115           mChild->SendExitPrivateMode();
116         }
117       },
118       [](const nsCString& aError) {});
119 }
120 
CreateIceCtx(const std::string & aName,const nsTArray<dom::RTCIceServer> & aIceServers,dom::RTCIceTransportPolicy aIcePolicy)121 nsresult MediaTransportHandlerIPC::CreateIceCtx(
122     const std::string& aName, const nsTArray<dom::RTCIceServer>& aIceServers,
123     dom::RTCIceTransportPolicy aIcePolicy) {
124   CSFLogDebug(LOGTAG, "MediaTransportHandlerIPC::CreateIceCtx start");
125   // Run some validation on this side of the IPC boundary so we can return
126   // errors synchronously. We don't actually use the results. It might make
127   // sense to move this check to PeerConnection and have this API take the
128   // converted form, but we would need to write IPC serialization code for
129   // the NrIce*Server types.
130   std::vector<NrIceStunServer> stunServers;
131   std::vector<NrIceTurnServer> turnServers;
132   nsresult rv = ConvertIceServers(aIceServers, &stunServers, &turnServers);
133   if (NS_FAILED(rv)) {
134     return rv;
135   }
136 
137   mInitPromise->Then(
138       mCallbackThread, __func__,
139       [=, iceServers = aIceServers.Clone(),
140        self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
141         if (mChild) {
142           CSFLogDebug(LOGTAG, "%s starting", __func__);
143           if (!mChild->SendCreateIceCtx(aName, std::move(iceServers),
144                                         aIcePolicy)) {
145             CSFLogError(LOGTAG, "%s failed!", __func__);
146           }
147         }
148       },
149       [](const nsCString& aError) {});
150 
151   return NS_OK;
152 }
153 
Destroy()154 void MediaTransportHandlerIPC::Destroy() {
155   mInitPromise->Then(
156       mCallbackThread, __func__,
157       [=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
158         if (mChild) {
159           MediaTransportChild::Send__delete__(mChild);
160           mChild = nullptr;
161         }
162       },
163       [](const nsCString& aError) {});
164 }
165 
166 // We will probably be able to move the proxy lookup stuff into
167 // this class once we move mtransport to its own process.
SetProxyConfig(NrSocketProxyConfig && aProxyConfig)168 void MediaTransportHandlerIPC::SetProxyConfig(
169     NrSocketProxyConfig&& aProxyConfig) {
170   mInitPromise->Then(
171       mCallbackThread, __func__,
172       [aProxyConfig = std::move(aProxyConfig), this,
173        self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) mutable {
174         if (mChild) {
175           mChild->SendSetProxyConfig(aProxyConfig.GetConfig());
176         }
177       },
178       [](const nsCString& aError) {});
179 }
180 
EnsureProvisionalTransport(const std::string & aTransportId,const std::string & aLocalUfrag,const std::string & aLocalPwd,size_t aComponentCount)181 void MediaTransportHandlerIPC::EnsureProvisionalTransport(
182     const std::string& aTransportId, const std::string& aLocalUfrag,
183     const std::string& aLocalPwd, size_t aComponentCount) {
184   mInitPromise->Then(
185       mCallbackThread, __func__,
186       [=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
187         if (mChild) {
188           mChild->SendEnsureProvisionalTransport(aTransportId, aLocalUfrag,
189                                                  aLocalPwd, aComponentCount);
190         }
191       },
192       [](const nsCString& aError) {});
193 }
194 
SetTargetForDefaultLocalAddressLookup(const std::string & aTargetIp,uint16_t aTargetPort)195 void MediaTransportHandlerIPC::SetTargetForDefaultLocalAddressLookup(
196     const std::string& aTargetIp, uint16_t aTargetPort) {
197   mInitPromise->Then(
198       mCallbackThread, __func__,
199       [=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
200         if (mChild) {
201           mChild->SendSetTargetForDefaultLocalAddressLookup(aTargetIp,
202                                                             aTargetPort);
203         }
204       },
205       [](const nsCString& aError) {});
206 }
207 
208 // We set default-route-only as late as possible because it depends on what
209 // capture permissions have been granted on the window, which could easily
210 // change between Init (ie; when the PC is created) and StartIceGathering
211 // (ie; when we set the local description).
StartIceGathering(bool aDefaultRouteOnly,bool aObfuscateHostAddresses,const nsTArray<NrIceStunAddr> & aStunAddrs)212 void MediaTransportHandlerIPC::StartIceGathering(
213     bool aDefaultRouteOnly, bool aObfuscateHostAddresses,
214     // TODO(bug 1522205): It probably makes sense to look this up internally
215     const nsTArray<NrIceStunAddr>& aStunAddrs) {
216   mInitPromise->Then(
217       mCallbackThread, __func__,
218       [=, stunAddrs = aStunAddrs.Clone(),
219        self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
220         if (mChild) {
221           mChild->SendStartIceGathering(aDefaultRouteOnly,
222                                         aObfuscateHostAddresses, stunAddrs);
223         }
224       },
225       [](const nsCString& aError) {});
226 }
227 
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)228 void MediaTransportHandlerIPC::ActivateTransport(
229     const std::string& aTransportId, const std::string& aLocalUfrag,
230     const std::string& aLocalPwd, size_t aComponentCount,
231     const std::string& aUfrag, const std::string& aPassword,
232     const nsTArray<uint8_t>& aKeyDer, const nsTArray<uint8_t>& aCertDer,
233     SSLKEAType aAuthType, bool aDtlsClient, const DtlsDigestList& aDigests,
234     bool aPrivacyRequested) {
235   mInitPromise->Then(
236       mCallbackThread, __func__,
237       [=, keyDer = aKeyDer.Clone(), certDer = aCertDer.Clone(),
238        self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
239         if (mChild) {
240           mChild->SendActivateTransport(aTransportId, aLocalUfrag, aLocalPwd,
241                                         aComponentCount, aUfrag, aPassword,
242                                         keyDer, certDer, aAuthType, aDtlsClient,
243                                         aDigests, aPrivacyRequested);
244         }
245       },
246       [](const nsCString& aError) {});
247 }
248 
RemoveTransportsExcept(const std::set<std::string> & aTransportIds)249 void MediaTransportHandlerIPC::RemoveTransportsExcept(
250     const std::set<std::string>& aTransportIds) {
251   std::vector<std::string> transportIds(aTransportIds.begin(),
252                                         aTransportIds.end());
253   mInitPromise->Then(
254       mCallbackThread, __func__,
255       [=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
256         if (mChild) {
257           mChild->SendRemoveTransportsExcept(transportIds);
258         }
259       },
260       [](const nsCString& aError) {});
261 }
262 
StartIceChecks(bool aIsControlling,const std::vector<std::string> & aIceOptions)263 void MediaTransportHandlerIPC::StartIceChecks(
264     bool aIsControlling, const std::vector<std::string>& aIceOptions) {
265   mInitPromise->Then(
266       mCallbackThread, __func__,
267       [=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
268         if (mChild) {
269           mChild->SendStartIceChecks(aIsControlling, aIceOptions);
270         }
271       },
272       [](const nsCString& aError) {});
273 }
274 
SendPacket(const std::string & aTransportId,MediaPacket && aPacket)275 void MediaTransportHandlerIPC::SendPacket(const std::string& aTransportId,
276                                           MediaPacket&& aPacket) {
277   mInitPromise->Then(
278       mCallbackThread, __func__,
279       [this, self = RefPtr<MediaTransportHandlerIPC>(this), aTransportId,
280        aPacket = std::move(aPacket)](bool /*dummy*/) mutable {
281         if (mChild) {
282           mChild->SendSendPacket(aTransportId, aPacket);
283         }
284       },
285       [](const nsCString& aError) {});
286 }
287 
AddIceCandidate(const std::string & aTransportId,const std::string & aCandidate,const std::string & aUfrag,const std::string & aObfuscatedAddress)288 void MediaTransportHandlerIPC::AddIceCandidate(
289     const std::string& aTransportId, const std::string& aCandidate,
290     const std::string& aUfrag, const std::string& aObfuscatedAddress) {
291   mInitPromise->Then(
292       mCallbackThread, __func__,
293       [=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
294         if (mChild) {
295           mChild->SendAddIceCandidate(aTransportId, aCandidate, aUfrag,
296                                       aObfuscatedAddress);
297         }
298       },
299       [](const nsCString& aError) {});
300 }
301 
UpdateNetworkState(bool aOnline)302 void MediaTransportHandlerIPC::UpdateNetworkState(bool aOnline) {
303   mInitPromise->Then(
304       mCallbackThread, __func__,
305       [=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
306         if (mChild) {
307           mChild->SendUpdateNetworkState(aOnline);
308         }
309       },
310       [](const nsCString& aError) {});
311 }
312 
GetIceStats(const std::string & aTransportId,DOMHighResTimeStamp aNow)313 RefPtr<dom::RTCStatsPromise> MediaTransportHandlerIPC::GetIceStats(
314     const std::string& aTransportId, DOMHighResTimeStamp aNow) {
315   return mInitPromise->Then(
316       mCallbackThread, __func__,
317       [aTransportId, aNow, this,
318        self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
319         if (!mChild) {
320           return dom::RTCStatsPromise::CreateAndReject(NS_ERROR_FAILURE,
321                                                        __func__);
322         }
323         RefPtr<dom::RTCStatsPromise> promise =
324             mChild->SendGetIceStats(aTransportId, aNow)
325                 ->Then(
326                     mCallbackThread, __func__,
327                     [](const dom::RTCStatsCollection& aStats) {
328                       UniquePtr<dom::RTCStatsCollection> stats(
329                           new dom::RTCStatsCollection(aStats));
330                       return dom::RTCStatsPromise::CreateAndResolve(
331                           std::move(stats), __func__);
332                     },
333                     [](ipc::ResponseRejectReason aReason) {
334                       return dom::RTCStatsPromise::CreateAndReject(
335                           NS_ERROR_FAILURE, __func__);
336                     });
337         return promise;
338       },
339       [](const nsCString& aError) {
340         return dom::RTCStatsPromise::CreateAndReject(NS_ERROR_FAILURE,
341                                                      __func__);
342       });
343 }
344 
MediaTransportChild(MediaTransportHandlerIPC * aUser)345 MediaTransportChild::MediaTransportChild(MediaTransportHandlerIPC* aUser)
346     : mUser(aUser) {}
347 
~MediaTransportChild()348 MediaTransportChild::~MediaTransportChild() { mUser->mChild = nullptr; }
349 
RecvOnCandidate(const string & transportId,const CandidateInfo & candidateInfo)350 mozilla::ipc::IPCResult MediaTransportChild::RecvOnCandidate(
351     const string& transportId, const CandidateInfo& candidateInfo) {
352   mUser->OnCandidate(transportId, candidateInfo);
353   return ipc::IPCResult::Ok();
354 }
355 
RecvOnAlpnNegotiated(const string & alpn)356 mozilla::ipc::IPCResult MediaTransportChild::RecvOnAlpnNegotiated(
357     const string& alpn) {
358   mUser->OnAlpnNegotiated(alpn);
359   return ipc::IPCResult::Ok();
360 }
361 
RecvOnGatheringStateChange(const int & state)362 mozilla::ipc::IPCResult MediaTransportChild::RecvOnGatheringStateChange(
363     const int& state) {
364   mUser->OnGatheringStateChange(static_cast<dom::RTCIceGatheringState>(state));
365   return ipc::IPCResult::Ok();
366 }
367 
RecvOnConnectionStateChange(const int & state)368 mozilla::ipc::IPCResult MediaTransportChild::RecvOnConnectionStateChange(
369     const int& state) {
370   mUser->OnConnectionStateChange(
371       static_cast<dom::RTCIceConnectionState>(state));
372   return ipc::IPCResult::Ok();
373 }
374 
RecvOnPacketReceived(const string & transportId,const MediaPacket & packet)375 mozilla::ipc::IPCResult MediaTransportChild::RecvOnPacketReceived(
376     const string& transportId, const MediaPacket& packet) {
377   MediaPacket copy(packet);  // Laaaaaame! Might be safe to const_cast?
378   mUser->OnPacketReceived(transportId, copy);
379   return ipc::IPCResult::Ok();
380 }
381 
RecvOnEncryptedSending(const string & transportId,const MediaPacket & packet)382 mozilla::ipc::IPCResult MediaTransportChild::RecvOnEncryptedSending(
383     const string& transportId, const MediaPacket& packet) {
384   MediaPacket copy(packet);  // Laaaaaame! Might be safe to const_cast?
385   mUser->OnEncryptedSending(transportId, copy);
386   return ipc::IPCResult::Ok();
387 }
388 
RecvOnStateChange(const string & transportId,const int & state)389 mozilla::ipc::IPCResult MediaTransportChild::RecvOnStateChange(
390     const string& transportId, const int& state) {
391   mUser->OnStateChange(transportId, static_cast<TransportLayer::State>(state));
392   return ipc::IPCResult::Ok();
393 }
394 
RecvOnRtcpStateChange(const string & transportId,const int & state)395 mozilla::ipc::IPCResult MediaTransportChild::RecvOnRtcpStateChange(
396     const string& transportId, const int& state) {
397   mUser->OnRtcpStateChange(transportId,
398                            static_cast<TransportLayer::State>(state));
399   return ipc::IPCResult::Ok();
400 }
401 
402 }  // namespace mozilla
403