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