/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "MediaTransportHandlerIPC.h" #include "mozilla/dom/MediaTransportChild.h" #include "nsThreadUtils.h" #include "mozilla/net/SocketProcessBridgeChild.h" #include "mozilla/RefPtr.h" #include "mozilla/ipc/BackgroundChild.h" #include "mozilla/ipc/PBackgroundChild.h" #include "common/browser_logging/CSFLog.h" namespace mozilla { static const char* mthipcLogTag = "MediaTransportHandler"; #ifdef LOGTAG # undef LOGTAG #endif #define LOGTAG mthipcLogTag MediaTransportHandlerIPC::MediaTransportHandlerIPC( nsISerialEventTarget* aCallbackThread) : MediaTransportHandler(aCallbackThread) {} void MediaTransportHandlerIPC::Initialize() { mInitPromise = net::SocketProcessBridgeChild::GetSocketProcessBridge()->Then( mCallbackThread, __func__, [this, self = RefPtr(this)]( const RefPtr& aBridge) { ipc::PBackgroundChild* actor = ipc::BackgroundChild::GetOrCreateSocketActorForCurrentThread(); // An actor that can't send is possible if the socket process has // crashed but hasn't been reconnected properly. See // SocketProcessBridgeChild::ActorDestroy for more info. if (!actor || !actor->CanSend()) { NS_WARNING( "MediaTransportHandlerIPC async init failed! Webrtc networking " "will not work!"); return InitPromise::CreateAndReject( nsCString("GetOrCreateSocketActorForCurrentThread failed!"), __func__); } MediaTransportChild* child = new MediaTransportChild(this); // PBackgroungChild owns mChild! When it is done with it, // mChild will let us know it it going away. mChild = actor->SendPMediaTransportConstructor(child); CSFLogDebug(LOGTAG, "%s Init done", __func__); return InitPromise::CreateAndResolve(true, __func__); }, [=](const nsCString& aError) { CSFLogError(LOGTAG, "MediaTransportHandlerIPC async init failed! Webrtc " "networking will not work! Error was %s", aError.get()); NS_WARNING( "MediaTransportHandlerIPC async init failed! Webrtc networking " "will not work!"); return InitPromise::CreateAndReject(aError, __func__); }); } RefPtr MediaTransportHandlerIPC::GetIceLog(const nsCString& aPattern) { return mInitPromise->Then( mCallbackThread, __func__, [=, self = RefPtr(this)](bool /* dummy */) { if (!mChild) { return IceLogPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); } // Compiler has trouble deducing the return type here for some reason, // so we use a temp variable as a hint. // SendGetIceLog _almost_ returns an IceLogPromise; the reject value // differs (ipc::ResponseRejectReason vs nsresult) so we need to // convert. RefPtr promise = mChild->SendGetIceLog(aPattern)->Then( mCallbackThread, __func__, [](WebrtcGlobalLog&& aLogLines) { return IceLogPromise::CreateAndResolve(std::move(aLogLines), __func__); }, [](ipc::ResponseRejectReason aReason) { return IceLogPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); }); return promise; }, [](const nsCString& aError) { return IceLogPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); }); } void MediaTransportHandlerIPC::ClearIceLog() { mInitPromise->Then( mCallbackThread, __func__, [=, self = RefPtr(this)](bool /*dummy*/) { if (mChild) { mChild->SendClearIceLog(); } }, [](const nsCString& aError) {}); } void MediaTransportHandlerIPC::EnterPrivateMode() { mInitPromise->Then( mCallbackThread, __func__, [=, self = RefPtr(this)](bool /*dummy*/) { if (mChild) { mChild->SendEnterPrivateMode(); } }, [](const nsCString& aError) {}); } void MediaTransportHandlerIPC::ExitPrivateMode() { mInitPromise->Then( mCallbackThread, __func__, [=, self = RefPtr(this)](bool /*dummy*/) { if (mChild) { mChild->SendExitPrivateMode(); } }, [](const nsCString& aError) {}); } void MediaTransportHandlerIPC::CreateIceCtx(const std::string& aName) { CSFLogDebug(LOGTAG, "MediaTransportHandlerIPC::CreateIceCtx start"); mInitPromise->Then( mCallbackThread, __func__, [=, self = RefPtr(this)](bool /*dummy*/) { if (mChild) { CSFLogDebug(LOGTAG, "%s starting", __func__); if (NS_WARN_IF(!mChild->SendCreateIceCtx(aName))) { CSFLogError(LOGTAG, "%s failed!", __func__); } } }, [](const nsCString& aError) {}); } nsresult MediaTransportHandlerIPC::SetIceConfig( const nsTArray& aIceServers, dom::RTCIceTransportPolicy aIcePolicy) { // Run some validation on this side of the IPC boundary so we can return // errors synchronously. We don't actually use the results. It might make // sense to move this check to PeerConnection and have this API take the // converted form, but we would need to write IPC serialization code for // the NrIce*Server types. std::vector stunServers; std::vector turnServers; nsresult rv = ConvertIceServers(aIceServers, &stunServers, &turnServers); if (NS_FAILED(rv)) { return rv; } mInitPromise->Then( mCallbackThread, __func__, [=, iceServers = aIceServers.Clone(), self = RefPtr(this)](bool /*dummy*/) { if (mChild) { if (NS_WARN_IF(!mChild->SendSetIceConfig(std::move(iceServers), aIcePolicy))) { CSFLogError(LOGTAG, "%s failed!", __func__); } } }, [](const nsCString& aError) {}); return NS_OK; } void MediaTransportHandlerIPC::Destroy() { if (mChild) { MediaTransportChild::Send__delete__(mChild); mChild = nullptr; } delete this; } // We will probably be able to move the proxy lookup stuff into // this class once we move mtransport to its own process. void MediaTransportHandlerIPC::SetProxyConfig( NrSocketProxyConfig&& aProxyConfig) { mInitPromise->Then( mCallbackThread, __func__, [aProxyConfig = std::move(aProxyConfig), this, self = RefPtr(this)](bool /*dummy*/) mutable { if (mChild) { mChild->SendSetProxyConfig(aProxyConfig.GetConfig()); } }, [](const nsCString& aError) {}); } void MediaTransportHandlerIPC::EnsureProvisionalTransport( const std::string& aTransportId, const std::string& aLocalUfrag, const std::string& aLocalPwd, int aComponentCount) { mInitPromise->Then( mCallbackThread, __func__, [=, self = RefPtr(this)](bool /*dummy*/) { if (mChild) { mChild->SendEnsureProvisionalTransport(aTransportId, aLocalUfrag, aLocalPwd, aComponentCount); } }, [](const nsCString& aError) {}); } void MediaTransportHandlerIPC::SetTargetForDefaultLocalAddressLookup( const std::string& aTargetIp, uint16_t aTargetPort) { mInitPromise->Then( mCallbackThread, __func__, [=, self = RefPtr(this)](bool /*dummy*/) { if (mChild) { mChild->SendSetTargetForDefaultLocalAddressLookup(aTargetIp, aTargetPort); } }, [](const nsCString& aError) {}); } // We set default-route-only as late as possible because it depends on what // capture permissions have been granted on the window, which could easily // change between Init (ie; when the PC is created) and StartIceGathering // (ie; when we set the local description). void MediaTransportHandlerIPC::StartIceGathering( bool aDefaultRouteOnly, bool aObfuscateHostAddresses, // TODO(bug 1522205): It probably makes sense to look this up internally const nsTArray& aStunAddrs) { mInitPromise->Then( mCallbackThread, __func__, [=, stunAddrs = aStunAddrs.Clone(), self = RefPtr(this)](bool /*dummy*/) { if (mChild) { mChild->SendStartIceGathering(aDefaultRouteOnly, aObfuscateHostAddresses, stunAddrs); } }, [](const nsCString& aError) {}); } void MediaTransportHandlerIPC::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& aKeyDer, const nsTArray& aCertDer, SSLKEAType aAuthType, bool aDtlsClient, const DtlsDigestList& aDigests, bool aPrivacyRequested) { mInitPromise->Then( mCallbackThread, __func__, [=, keyDer = aKeyDer.Clone(), certDer = aCertDer.Clone(), self = RefPtr(this)](bool /*dummy*/) { if (mChild) { mChild->SendActivateTransport(aTransportId, aLocalUfrag, aLocalPwd, aComponentCount, aUfrag, aPassword, keyDer, certDer, aAuthType, aDtlsClient, aDigests, aPrivacyRequested); } }, [](const nsCString& aError) {}); } void MediaTransportHandlerIPC::RemoveTransportsExcept( const std::set& aTransportIds) { std::vector transportIds(aTransportIds.begin(), aTransportIds.end()); mInitPromise->Then( mCallbackThread, __func__, [=, self = RefPtr(this)](bool /*dummy*/) { if (mChild) { mChild->SendRemoveTransportsExcept(transportIds); } }, [](const nsCString& aError) {}); } void MediaTransportHandlerIPC::StartIceChecks( bool aIsControlling, const std::vector& aIceOptions) { mInitPromise->Then( mCallbackThread, __func__, [=, self = RefPtr(this)](bool /*dummy*/) { if (mChild) { mChild->SendStartIceChecks(aIsControlling, aIceOptions); } }, [](const nsCString& aError) {}); } void MediaTransportHandlerIPC::SendPacket(const std::string& aTransportId, MediaPacket&& aPacket) { mInitPromise->Then( mCallbackThread, __func__, [this, self = RefPtr(this), aTransportId, aPacket = std::move(aPacket)](bool /*dummy*/) mutable { if (mChild) { mChild->SendSendPacket(aTransportId, aPacket); } }, [](const nsCString& aError) {}); } void MediaTransportHandlerIPC::AddIceCandidate( const std::string& aTransportId, const std::string& aCandidate, const std::string& aUfrag, const std::string& aObfuscatedAddress) { mInitPromise->Then( mCallbackThread, __func__, [=, self = RefPtr(this)](bool /*dummy*/) { if (mChild) { mChild->SendAddIceCandidate(aTransportId, aCandidate, aUfrag, aObfuscatedAddress); } }, [](const nsCString& aError) {}); } void MediaTransportHandlerIPC::UpdateNetworkState(bool aOnline) { mInitPromise->Then( mCallbackThread, __func__, [=, self = RefPtr(this)](bool /*dummy*/) { if (mChild) { mChild->SendUpdateNetworkState(aOnline); } }, [](const nsCString& aError) {}); } RefPtr MediaTransportHandlerIPC::GetIceStats( const std::string& aTransportId, DOMHighResTimeStamp aNow) { using IPCPromise = dom::PMediaTransportChild::GetIceStatsPromise; return mInitPromise ->Then(mCallbackThread, __func__, [aTransportId, aNow, this, self = RefPtr(this)]( const InitPromise::ResolveOrRejectValue& aValue) { if (aValue.IsReject()) { return IPCPromise::CreateAndResolve( MakeUnique(), "MediaTransportHandlerIPC::GetIceStats_1"); } if (!mChild) { return IPCPromise::CreateAndResolve( MakeUnique(), "MediaTransportHandlerIPC::GetIceStats_1"); } return mChild->SendGetIceStats(aTransportId, aNow); }) ->Then(mCallbackThread, __func__, [](IPCPromise::ResolveOrRejectValue&& aValue) { if (aValue.IsReject()) { return dom::RTCStatsPromise::CreateAndResolve( MakeUnique(), "MediaTransportHandlerIPC::GetIceStats_2"); } return dom::RTCStatsPromise::CreateAndResolve( std::move(aValue.ResolveValue()), "MediaTransportHandlerIPC::GetIceStats_2"); }); } MediaTransportChild::MediaTransportChild(MediaTransportHandlerIPC* aUser) : mUser(aUser) {} MediaTransportChild::~MediaTransportChild() { mUser->mChild = nullptr; } mozilla::ipc::IPCResult MediaTransportChild::RecvOnCandidate( const string& transportId, const CandidateInfo& candidateInfo) { mUser->OnCandidate(transportId, candidateInfo); return ipc::IPCResult::Ok(); } mozilla::ipc::IPCResult MediaTransportChild::RecvOnAlpnNegotiated( const string& alpn) { mUser->OnAlpnNegotiated(alpn); return ipc::IPCResult::Ok(); } mozilla::ipc::IPCResult MediaTransportChild::RecvOnGatheringStateChange( const int& state) { mUser->OnGatheringStateChange(static_cast(state)); return ipc::IPCResult::Ok(); } mozilla::ipc::IPCResult MediaTransportChild::RecvOnConnectionStateChange( const int& state) { mUser->OnConnectionStateChange( static_cast(state)); return ipc::IPCResult::Ok(); } mozilla::ipc::IPCResult MediaTransportChild::RecvOnPacketReceived( const string& transportId, const MediaPacket& packet) { mUser->OnPacketReceived(transportId, packet); return ipc::IPCResult::Ok(); } mozilla::ipc::IPCResult MediaTransportChild::RecvOnEncryptedSending( const string& transportId, const MediaPacket& packet) { mUser->OnEncryptedSending(transportId, packet); return ipc::IPCResult::Ok(); } mozilla::ipc::IPCResult MediaTransportChild::RecvOnStateChange( const string& transportId, const int& state) { mUser->OnStateChange(transportId, static_cast(state)); return ipc::IPCResult::Ok(); } mozilla::ipc::IPCResult MediaTransportChild::RecvOnRtcpStateChange( const string& transportId, const int& state) { mUser->OnRtcpStateChange(transportId, static_cast(state)); return ipc::IPCResult::Ok(); } } // namespace mozilla