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