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