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