diff options
Diffstat (limited to 'dom/presentation/ipc')
-rw-r--r-- | dom/presentation/ipc/PPresentation.ipdl | 112 | ||||
-rw-r--r-- | dom/presentation/ipc/PPresentationBuilder.ipdl | 34 | ||||
-rw-r--r-- | dom/presentation/ipc/PPresentationRequest.ipdl | 22 | ||||
-rw-r--r-- | dom/presentation/ipc/PresentationBuilderChild.cpp | 184 | ||||
-rw-r--r-- | dom/presentation/ipc/PresentationBuilderChild.h | 48 | ||||
-rw-r--r-- | dom/presentation/ipc/PresentationBuilderParent.cpp | 267 | ||||
-rw-r--r-- | dom/presentation/ipc/PresentationBuilderParent.h | 52 | ||||
-rw-r--r-- | dom/presentation/ipc/PresentationChild.cpp | 198 | ||||
-rw-r--r-- | dom/presentation/ipc/PresentationChild.h | 101 | ||||
-rw-r--r-- | dom/presentation/ipc/PresentationContentSessionInfo.cpp | 109 | ||||
-rw-r--r-- | dom/presentation/ipc/PresentationContentSessionInfo.h | 62 | ||||
-rw-r--r-- | dom/presentation/ipc/PresentationIPCService.cpp | 538 | ||||
-rw-r--r-- | dom/presentation/ipc/PresentationIPCService.h | 75 | ||||
-rw-r--r-- | dom/presentation/ipc/PresentationParent.cpp | 553 | ||||
-rw-r--r-- | dom/presentation/ipc/PresentationParent.h | 137 |
15 files changed, 2492 insertions, 0 deletions
diff --git a/dom/presentation/ipc/PPresentation.ipdl b/dom/presentation/ipc/PPresentation.ipdl new file mode 100644 index 000000000..e0f4d2888 --- /dev/null +++ b/dom/presentation/ipc/PPresentation.ipdl @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et ft=cpp : */ +/* 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 protocol PContent; +include protocol PPresentationRequest; +include protocol PPresentationBuilder; + +include InputStreamParams; + +using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h"; +using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h"; + +namespace mozilla { +namespace dom { + +struct StartSessionRequest +{ + nsString[] urls; + nsString sessionId; + nsString origin; + nsString deviceId; + uint64_t windowId; + TabId tabId; + Principal principal; +}; + +struct SendSessionMessageRequest +{ + nsString sessionId; + uint8_t role; + nsString data; +}; + +struct CloseSessionRequest +{ + nsString sessionId; + uint8_t role; + uint8_t closedReason; +}; + +struct TerminateSessionRequest +{ + nsString sessionId; + uint8_t role; +}; + +struct ReconnectSessionRequest +{ + nsString[] urls; + nsString sessionId; + uint8_t role; +}; + +struct BuildTransportRequest +{ + nsString sessionId; + uint8_t role; +}; + +union PresentationIPCRequest +{ + StartSessionRequest; + SendSessionMessageRequest; + CloseSessionRequest; + TerminateSessionRequest; + ReconnectSessionRequest; + BuildTransportRequest; +}; + +sync protocol PPresentation +{ + manager PContent; + manages PPresentationBuilder; + manages PPresentationRequest; + +child: + async NotifyAvailableChange(nsString[] aAvailabilityUrls, + bool aAvailable); + async NotifySessionStateChange(nsString aSessionId, + uint16_t aState, + nsresult aReason); + async NotifyMessage(nsString aSessionId, nsCString aData, bool aIsBinary); + async NotifySessionConnect(uint64_t aWindowId, nsString aSessionId); + async NotifyCloseSessionTransport(nsString aSessionId, + uint8_t aRole, + nsresult aReason); + + async PPresentationBuilder(nsString aSessionId, uint8_t aRole); + +parent: + async __delete__(); + + async RegisterAvailabilityHandler(nsString[] aAvailabilityUrls); + async UnregisterAvailabilityHandler(nsString[] aAvailabilityUrls); + + async RegisterSessionHandler(nsString aSessionId, uint8_t aRole); + async UnregisterSessionHandler(nsString aSessionId, uint8_t aRole); + + async RegisterRespondingHandler(uint64_t aWindowId); + async UnregisterRespondingHandler(uint64_t aWindowId); + + async PPresentationRequest(PresentationIPCRequest aRequest); + + async NotifyReceiverReady(nsString aSessionId, uint64_t aWindowId, bool aIsLoading); + async NotifyTransportClosed(nsString aSessionId, uint8_t aRole, nsresult aReason); +}; + +} // namespace dom +} // namespace mozilla diff --git a/dom/presentation/ipc/PPresentationBuilder.ipdl b/dom/presentation/ipc/PPresentationBuilder.ipdl new file mode 100644 index 000000000..e32b02e8f --- /dev/null +++ b/dom/presentation/ipc/PPresentationBuilder.ipdl @@ -0,0 +1,34 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* 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 protocol PPresentation; + +namespace mozilla { +namespace dom { + +async protocol PPresentationBuilder +{ + manager PPresentation; + +parent: + async SendOffer(nsString aSDP); + async SendAnswer(nsString aSDP); + async SendIceCandidate(nsString aCandidate); + async Close(nsresult aReason); + + async OnSessionTransport(); + async OnSessionTransportError(nsresult aReason); + +child: + async OnOffer(nsString aSDP); + async OnAnswer(nsString aSDP); + async OnIceCandidate(nsString aCandidate); + + async __delete__(); +}; + +} // namespace dom +} // namespace mozilla diff --git a/dom/presentation/ipc/PPresentationRequest.ipdl b/dom/presentation/ipc/PPresentationRequest.ipdl new file mode 100644 index 000000000..fa99dfcab --- /dev/null +++ b/dom/presentation/ipc/PPresentationRequest.ipdl @@ -0,0 +1,22 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* 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 protocol PPresentation; + +namespace mozilla { +namespace dom { + +sync protocol PPresentationRequest +{ + manager PPresentation; + +child: + async __delete__(nsresult result); + async NotifyRequestUrlSelected(nsString aUrl); +}; + +} // namespace dom +} // namespace mozilla diff --git a/dom/presentation/ipc/PresentationBuilderChild.cpp b/dom/presentation/ipc/PresentationBuilderChild.cpp new file mode 100644 index 000000000..387332e9e --- /dev/null +++ b/dom/presentation/ipc/PresentationBuilderChild.cpp @@ -0,0 +1,184 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* 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 "DCPresentationChannelDescription.h" +#include "nsComponentManagerUtils.h" +#include "nsGlobalWindow.h" +#include "PresentationBuilderChild.h" +#include "PresentationIPCService.h" +#include "nsServiceManagerUtils.h" +#include "mozilla/Unused.h" + +namespace mozilla { +namespace dom { + +NS_IMPL_ISUPPORTS(PresentationBuilderChild, + nsIPresentationSessionTransportBuilderListener) + +PresentationBuilderChild::PresentationBuilderChild(const nsString& aSessionId, + uint8_t aRole) + : mSessionId(aSessionId) + , mRole(aRole) +{ +} + +nsresult PresentationBuilderChild::Init() +{ + mBuilder = do_CreateInstance("@mozilla.org/presentation/datachanneltransportbuilder;1"); + if (NS_WARN_IF(!mBuilder)) { + return NS_ERROR_NOT_AVAILABLE; + } + + uint64_t windowId = 0; + + nsCOMPtr<nsIPresentationService> service = + do_GetService(PRESENTATION_SERVICE_CONTRACTID); + if (NS_WARN_IF(!service)) { + return NS_ERROR_NOT_AVAILABLE; + } + + if (NS_WARN_IF(NS_FAILED(service->GetWindowIdBySessionId( + mSessionId, + mRole, + &windowId)))) { + return NS_ERROR_NOT_AVAILABLE; + } + + nsPIDOMWindowInner* window = nsGlobalWindow::GetInnerWindowWithId(windowId)->AsInner(); + if (NS_WARN_IF(!window)) { + return NS_ERROR_NOT_AVAILABLE; + } + + return mBuilder->BuildDataChannelTransport(mRole, window, this); +} + +void +PresentationBuilderChild::ActorDestroy(ActorDestroyReason aWhy) +{ + mBuilder = nullptr; + mActorDestroyed = true; +} + +bool +PresentationBuilderChild::RecvOnOffer(const nsString& aSDP) +{ + if (NS_WARN_IF(!mBuilder)) { + return false; + } + RefPtr<DCPresentationChannelDescription> description = + new DCPresentationChannelDescription(aSDP); + + if (NS_WARN_IF(NS_FAILED(mBuilder->OnOffer(description)))) { + return false; + } + return true; +} + +bool +PresentationBuilderChild::RecvOnAnswer(const nsString& aSDP) +{ + if (NS_WARN_IF(!mBuilder)) { + return false; + } + RefPtr<DCPresentationChannelDescription> description = + new DCPresentationChannelDescription(aSDP); + + if (NS_WARN_IF(NS_FAILED(mBuilder->OnAnswer(description)))) { + return false; + } + return true; +} + +bool +PresentationBuilderChild::RecvOnIceCandidate(const nsString& aCandidate) +{ + if (NS_WARN_IF(mBuilder && NS_FAILED(mBuilder->OnIceCandidate(aCandidate)))) { + return false; + } + return true; +} + +// nsPresentationSessionTransportBuilderListener +NS_IMETHODIMP +PresentationBuilderChild::OnSessionTransport(nsIPresentationSessionTransport* aTransport) +{ + if (NS_WARN_IF(mActorDestroyed || !SendOnSessionTransport())){ + return NS_ERROR_FAILURE; + } + + nsCOMPtr<nsIPresentationService> service = + do_GetService(PRESENTATION_SERVICE_CONTRACTID); + NS_WARNING_ASSERTION(service, "no presentation service"); + if (service) { + Unused << NS_WARN_IF(NS_FAILED(static_cast<PresentationIPCService*>(service.get())-> + NotifySessionTransport(mSessionId, mRole, aTransport))); + } + mBuilder = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +PresentationBuilderChild::OnError(nsresult reason) +{ + mBuilder = nullptr; + + if (NS_WARN_IF(mActorDestroyed || !SendOnSessionTransportError(reason))){ + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +NS_IMETHODIMP +PresentationBuilderChild::SendOffer(nsIPresentationChannelDescription* aOffer) +{ + nsAutoString SDP; + nsresult rv = aOffer->GetDataChannelSDP(SDP); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (NS_WARN_IF(mActorDestroyed || !SendSendOffer(SDP))){ + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +NS_IMETHODIMP +PresentationBuilderChild::SendAnswer(nsIPresentationChannelDescription* aAnswer) +{ + nsAutoString SDP; + nsresult rv = aAnswer->GetDataChannelSDP(SDP); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (NS_WARN_IF(mActorDestroyed || !SendSendAnswer(SDP))){ + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +NS_IMETHODIMP +PresentationBuilderChild::SendIceCandidate(const nsAString& candidate) +{ + if (NS_WARN_IF(mActorDestroyed || !SendSendIceCandidate(nsString(candidate)))) { + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +NS_IMETHODIMP +PresentationBuilderChild::Close(nsresult reason) +{ + if (NS_WARN_IF(mActorDestroyed || !SendClose(reason))) { + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +} // namespace dom +} // namespace mozilla + diff --git a/dom/presentation/ipc/PresentationBuilderChild.h b/dom/presentation/ipc/PresentationBuilderChild.h new file mode 100644 index 000000000..5ada53ab7 --- /dev/null +++ b/dom/presentation/ipc/PresentationBuilderChild.h @@ -0,0 +1,48 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef mozilla_dom_PresentationBuilderChild_h +#define mozilla_dom_PresentationBuilderChild_h + +#include "mozilla/dom/PPresentationBuilderChild.h" +#include "nsIPresentationSessionTransportBuilder.h" + +namespace mozilla { +namespace dom { + +class PresentationBuilderChild final: public PPresentationBuilderChild + , public nsIPresentationSessionTransportBuilderListener +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPRESENTATIONSESSIONTRANSPORTBUILDERLISTENER + + explicit PresentationBuilderChild(const nsString& aSessionId, + uint8_t aRole); + + nsresult Init(); + + virtual void ActorDestroy(ActorDestroyReason aWhy) override; + + virtual bool RecvOnOffer(const nsString& aSDP) override; + + virtual bool RecvOnAnswer(const nsString& aSDP) override; + + virtual bool RecvOnIceCandidate(const nsString& aCandidate) override; + +private: + virtual ~PresentationBuilderChild() = default; + + nsString mSessionId; + uint8_t mRole; + bool mActorDestroyed = false; + nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder> mBuilder; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_PresentationBuilderChild_h diff --git a/dom/presentation/ipc/PresentationBuilderParent.cpp b/dom/presentation/ipc/PresentationBuilderParent.cpp new file mode 100644 index 000000000..dc784b13c --- /dev/null +++ b/dom/presentation/ipc/PresentationBuilderParent.cpp @@ -0,0 +1,267 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* 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 "DCPresentationChannelDescription.h" +#include "PresentationBuilderParent.h" +#include "PresentationSessionInfo.h" + +namespace mozilla { +namespace dom { + +namespace { + +class PresentationSessionTransportIPC final : + public nsIPresentationSessionTransport +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPRESENTATIONSESSIONTRANSPORT + + PresentationSessionTransportIPC(PresentationParent* aParent, + const nsAString& aSessionId, + uint8_t aRole) + : mParent(aParent) + , mSessionId(aSessionId) + , mRole(aRole) + { + MOZ_ASSERT(mParent); + } + +private: + virtual ~PresentationSessionTransportIPC() = default; + + RefPtr<PresentationParent> mParent; + nsString mSessionId; + uint8_t mRole; +}; + +NS_IMPL_ISUPPORTS(PresentationSessionTransportIPC, + nsIPresentationSessionTransport) + +NS_IMETHODIMP +PresentationSessionTransportIPC::GetCallback( + nsIPresentationSessionTransportCallback** aCallback) +{ + return NS_OK; +} + +NS_IMETHODIMP +PresentationSessionTransportIPC::SetCallback( + nsIPresentationSessionTransportCallback* aCallback) +{ + if (aCallback) { + aCallback->NotifyTransportReady(); + } + return NS_OK; +} + +NS_IMETHODIMP +PresentationSessionTransportIPC::GetSelfAddress(nsINetAddr** aSelfAddress) +{ + MOZ_ASSERT(false, "Not expected."); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +PresentationSessionTransportIPC::EnableDataNotification() +{ + return NS_OK; +} + +NS_IMETHODIMP +PresentationSessionTransportIPC::Send(const nsAString& aData) +{ + return NS_OK; +} + +NS_IMETHODIMP +PresentationSessionTransportIPC::SendBinaryMsg(const nsACString& aData) +{ + return NS_OK; +} + +NS_IMETHODIMP +PresentationSessionTransportIPC::SendBlob(nsIDOMBlob* aBlob) +{ + return NS_OK; +} + +NS_IMETHODIMP +PresentationSessionTransportIPC::Close(nsresult aReason) +{ + if (NS_WARN_IF(!mParent->SendNotifyCloseSessionTransport(mSessionId, + mRole, + aReason))) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +} // anonymous namespace + +NS_IMPL_ISUPPORTS(PresentationBuilderParent, + nsIPresentationSessionTransportBuilder, + nsIPresentationDataChannelSessionTransportBuilder) + +PresentationBuilderParent::PresentationBuilderParent(PresentationParent* aParent) + : mParent(aParent) +{ + MOZ_COUNT_CTOR(PresentationBuilderParent); +} + +PresentationBuilderParent::~PresentationBuilderParent() +{ + MOZ_COUNT_DTOR(PresentationBuilderParent); + + if (mNeedDestroyActor) { + Unused << NS_WARN_IF(!Send__delete__(this)); + } +} + +NS_IMETHODIMP +PresentationBuilderParent::BuildDataChannelTransport( + uint8_t aRole, + mozIDOMWindow* aWindow, /* unused */ + nsIPresentationSessionTransportBuilderListener* aListener) +{ + mBuilderListener = aListener; + + RefPtr<PresentationSessionInfo> info = static_cast<PresentationSessionInfo*>(aListener); + nsAutoString sessionId(info->GetSessionId()); + if (NS_WARN_IF(!mParent->SendPPresentationBuilderConstructor(this, + sessionId, + aRole))) { + return NS_ERROR_FAILURE; + } + mIPCSessionTransport = new PresentationSessionTransportIPC(mParent, + sessionId, + aRole); + mNeedDestroyActor = true; + mParent = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +PresentationBuilderParent::OnIceCandidate(const nsAString& aCandidate) +{ + if (NS_WARN_IF(!SendOnIceCandidate(nsString(aCandidate)))){ + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +NS_IMETHODIMP +PresentationBuilderParent::OnOffer(nsIPresentationChannelDescription* aDescription) +{ + nsAutoString SDP; + nsresult rv = aDescription->GetDataChannelSDP(SDP); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (NS_WARN_IF(!SendOnOffer(SDP))){ + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +NS_IMETHODIMP +PresentationBuilderParent::OnAnswer(nsIPresentationChannelDescription* aDescription) +{ + nsAutoString SDP; + nsresult rv = aDescription->GetDataChannelSDP(SDP); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (NS_WARN_IF(!SendOnAnswer(SDP))){ + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +NS_IMETHODIMP +PresentationBuilderParent::NotifyDisconnected(nsresult aReason) +{ + return NS_OK; +} + +void +PresentationBuilderParent::ActorDestroy(ActorDestroyReason aWhy) +{ + mNeedDestroyActor = false; + mParent = nullptr; + mBuilderListener = nullptr; +} + +bool +PresentationBuilderParent::RecvSendOffer(const nsString& aSDP) +{ + RefPtr<DCPresentationChannelDescription> description = + new DCPresentationChannelDescription(aSDP); + if (NS_WARN_IF(!mBuilderListener || + NS_FAILED(mBuilderListener->SendOffer(description)))) { + return false; + } + return true; +} + +bool +PresentationBuilderParent::RecvSendAnswer(const nsString& aSDP) +{ + RefPtr<DCPresentationChannelDescription> description = + new DCPresentationChannelDescription(aSDP); + if (NS_WARN_IF(!mBuilderListener || + NS_FAILED(mBuilderListener->SendAnswer(description)))) { + return false; + } + return true; +} + +bool +PresentationBuilderParent::RecvSendIceCandidate(const nsString& aCandidate) +{ + if (NS_WARN_IF(!mBuilderListener || + NS_FAILED(mBuilderListener->SendIceCandidate(aCandidate)))) { + return false; + } + return true; +} + +bool +PresentationBuilderParent::RecvClose(const nsresult& aReason) +{ + if (NS_WARN_IF(!mBuilderListener || + NS_FAILED(mBuilderListener->Close(aReason)))) { + return false; + } + return true; +} + +// Delegate to nsIPresentationSessionTransportBuilderListener +bool +PresentationBuilderParent::RecvOnSessionTransport() +{ + RefPtr<PresentationBuilderParent> kungFuDeathGrip = this; + Unused << + NS_WARN_IF(!mBuilderListener || + NS_FAILED(mBuilderListener->OnSessionTransport(mIPCSessionTransport))); + return true; +} + +bool +PresentationBuilderParent::RecvOnSessionTransportError(const nsresult& aReason) +{ + if (NS_WARN_IF(!mBuilderListener || + NS_FAILED(mBuilderListener->OnError(aReason)))) { + return false; + } + return true; +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/presentation/ipc/PresentationBuilderParent.h b/dom/presentation/ipc/PresentationBuilderParent.h new file mode 100644 index 000000000..7fd211ce5 --- /dev/null +++ b/dom/presentation/ipc/PresentationBuilderParent.h @@ -0,0 +1,52 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef mozilla_dom_PresentationBuilderParent_h__ +#define mozilla_dom_PresentationBuilderParent_h__ + +#include "mozilla/dom/PPresentationBuilderParent.h" +#include "PresentationParent.h" +#include "nsIPresentationSessionTransportBuilder.h" + +namespace mozilla { +namespace dom { + +class PresentationBuilderParent final: public PPresentationBuilderParent + , public nsIPresentationDataChannelSessionTransportBuilder +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPRESENTATIONSESSIONTRANSPORTBUILDER + NS_DECL_NSIPRESENTATIONDATACHANNELSESSIONTRANSPORTBUILDER + + explicit PresentationBuilderParent(PresentationParent* aParent); + + virtual bool RecvSendOffer(const nsString& aSDP) override; + + virtual bool RecvSendAnswer(const nsString& aSDP) override; + + virtual bool RecvSendIceCandidate(const nsString& aCandidate) override; + + virtual bool RecvClose(const nsresult& aReason) override; + + virtual void ActorDestroy(ActorDestroyReason aWhy) override; + + virtual bool RecvOnSessionTransport() override; + + virtual bool RecvOnSessionTransportError(const nsresult& aReason) override; + +private: + virtual ~PresentationBuilderParent(); + bool mNeedDestroyActor = false; + RefPtr<PresentationParent> mParent; + nsCOMPtr<nsIPresentationSessionTransportBuilderListener> mBuilderListener; + nsCOMPtr<nsIPresentationSessionTransport> mIPCSessionTransport; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_PresentationBuilderParent_h__ diff --git a/dom/presentation/ipc/PresentationChild.cpp b/dom/presentation/ipc/PresentationChild.cpp new file mode 100644 index 000000000..d24ba9e8c --- /dev/null +++ b/dom/presentation/ipc/PresentationChild.cpp @@ -0,0 +1,198 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* 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 "DCPresentationChannelDescription.h" +#include "mozilla/StaticPtr.h" +#include "PresentationBuilderChild.h" +#include "PresentationChild.h" +#include "PresentationIPCService.h" +#include "nsThreadUtils.h" + +using namespace mozilla; +using namespace mozilla::dom; + +/* + * Implementation of PresentationChild + */ + +PresentationChild::PresentationChild(PresentationIPCService* aService) + : mActorDestroyed(false) + , mService(aService) +{ + MOZ_ASSERT(mService); + + MOZ_COUNT_CTOR(PresentationChild); +} + +PresentationChild::~PresentationChild() +{ + MOZ_COUNT_DTOR(PresentationChild); + + if (!mActorDestroyed) { + Send__delete__(this); + } + mService = nullptr; +} + +void +PresentationChild::ActorDestroy(ActorDestroyReason aWhy) +{ + mActorDestroyed = true; + mService->NotifyPresentationChildDestroyed(); + mService = nullptr; +} + +PPresentationRequestChild* +PresentationChild::AllocPPresentationRequestChild(const PresentationIPCRequest& aRequest) +{ + NS_NOTREACHED("We should never be manually allocating PPresentationRequestChild actors"); + return nullptr; +} + +bool +PresentationChild::DeallocPPresentationRequestChild(PPresentationRequestChild* aActor) +{ + delete aActor; + return true; +} + +bool PresentationChild::RecvPPresentationBuilderConstructor( + PPresentationBuilderChild* aActor, + const nsString& aSessionId, + const uint8_t& aRole) +{ + // Child will build the session transport + PresentationBuilderChild* actor = static_cast<PresentationBuilderChild*>(aActor); + return NS_WARN_IF(NS_FAILED(actor->Init())) ? false : true; +} + +PPresentationBuilderChild* +PresentationChild::AllocPPresentationBuilderChild(const nsString& aSessionId, + const uint8_t& aRole) +{ + RefPtr<PresentationBuilderChild> actor + = new PresentationBuilderChild(aSessionId, aRole); + + return actor.forget().take(); +} + +bool +PresentationChild::DeallocPPresentationBuilderChild(PPresentationBuilderChild* aActor) +{ + RefPtr<PresentationBuilderChild> actor = + dont_AddRef(static_cast<PresentationBuilderChild*>(aActor)); + return true; +} + + +bool +PresentationChild::RecvNotifyAvailableChange( + nsTArray<nsString>&& aAvailabilityUrls, + const bool& aAvailable) +{ + if (mService) { + Unused << + NS_WARN_IF(NS_FAILED(mService->NotifyAvailableChange(aAvailabilityUrls, + aAvailable))); + } + return true; +} + +bool +PresentationChild::RecvNotifySessionStateChange(const nsString& aSessionId, + const uint16_t& aState, + const nsresult& aReason) +{ + if (mService) { + Unused << NS_WARN_IF(NS_FAILED(mService->NotifySessionStateChange(aSessionId, + aState, + aReason))); + } + return true; +} + +bool +PresentationChild::RecvNotifyMessage(const nsString& aSessionId, + const nsCString& aData, + const bool& aIsBinary) +{ + if (mService) { + Unused << NS_WARN_IF(NS_FAILED(mService->NotifyMessage(aSessionId, + aData, + aIsBinary))); + } + return true; +} + +bool +PresentationChild::RecvNotifySessionConnect(const uint64_t& aWindowId, + const nsString& aSessionId) +{ + if (mService) { + Unused << NS_WARN_IF(NS_FAILED(mService->NotifySessionConnect(aWindowId, aSessionId))); + } + return true; +} + +bool +PresentationChild::RecvNotifyCloseSessionTransport(const nsString& aSessionId, + const uint8_t& aRole, + const nsresult& aReason) +{ + if (mService) { + Unused << NS_WARN_IF(NS_FAILED( + mService->CloseContentSessionTransport(aSessionId, aRole, aReason))); + } + return true; +} + +/* + * Implementation of PresentationRequestChild + */ + +PresentationRequestChild::PresentationRequestChild(nsIPresentationServiceCallback* aCallback) + : mActorDestroyed(false) + , mCallback(aCallback) +{ + MOZ_COUNT_CTOR(PresentationRequestChild); +} + +PresentationRequestChild::~PresentationRequestChild() +{ + MOZ_COUNT_DTOR(PresentationRequestChild); + + mCallback = nullptr; +} + +void +PresentationRequestChild::ActorDestroy(ActorDestroyReason aWhy) +{ + mActorDestroyed = true; + mCallback = nullptr; +} + +bool +PresentationRequestChild::Recv__delete__(const nsresult& aResult) +{ + if (mActorDestroyed) { + return true; + } + + if (mCallback) { + if (NS_FAILED(aResult)) { + Unused << NS_WARN_IF(NS_FAILED(mCallback->NotifyError(aResult))); + } + } + + return true; +} + +bool +PresentationRequestChild::RecvNotifyRequestUrlSelected(const nsString& aUrl) +{ + Unused << NS_WARN_IF(NS_FAILED(mCallback->NotifySuccess(aUrl))); + return true; +} diff --git a/dom/presentation/ipc/PresentationChild.h b/dom/presentation/ipc/PresentationChild.h new file mode 100644 index 000000000..1c625b8ce --- /dev/null +++ b/dom/presentation/ipc/PresentationChild.h @@ -0,0 +1,101 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef mozilla_dom_PresentationChild_h +#define mozilla_dom_PresentationChild_h + +#include "mozilla/dom/PPresentationBuilderChild.h" +#include "mozilla/dom/PPresentationChild.h" +#include "mozilla/dom/PPresentationRequestChild.h" + +class nsIPresentationServiceCallback; + +namespace mozilla { +namespace dom { + +class PresentationIPCService; + +class PresentationChild final : public PPresentationChild +{ +public: + explicit PresentationChild(PresentationIPCService* aService); + + virtual void + ActorDestroy(ActorDestroyReason aWhy) override; + + virtual PPresentationRequestChild* + AllocPPresentationRequestChild(const PresentationIPCRequest& aRequest) override; + + virtual bool + DeallocPPresentationRequestChild(PPresentationRequestChild* aActor) override; + + bool RecvPPresentationBuilderConstructor(PPresentationBuilderChild* aActor, + const nsString& aSessionId, + const uint8_t& aRole) override; + + virtual PPresentationBuilderChild* + AllocPPresentationBuilderChild(const nsString& aSessionId, const uint8_t& aRole) override; + + virtual bool + DeallocPPresentationBuilderChild(PPresentationBuilderChild* aActor) override; + + virtual bool + RecvNotifyAvailableChange(nsTArray<nsString>&& aAvailabilityUrls, + const bool& aAvailable) override; + + virtual bool + RecvNotifySessionStateChange(const nsString& aSessionId, + const uint16_t& aState, + const nsresult& aReason) override; + + virtual bool + RecvNotifyMessage(const nsString& aSessionId, + const nsCString& aData, + const bool& aIsBinary) override; + + virtual bool + RecvNotifySessionConnect(const uint64_t& aWindowId, + const nsString& aSessionId) override; + + virtual bool + RecvNotifyCloseSessionTransport(const nsString& aSessionId, + const uint8_t& aRole, + const nsresult& aReason) override; + +private: + virtual ~PresentationChild(); + + bool mActorDestroyed = false; + RefPtr<PresentationIPCService> mService; +}; + +class PresentationRequestChild final : public PPresentationRequestChild +{ + friend class PresentationChild; + +public: + explicit PresentationRequestChild(nsIPresentationServiceCallback* aCallback); + + virtual void + ActorDestroy(ActorDestroyReason aWhy) override; + + virtual bool + Recv__delete__(const nsresult& aResult) override; + + virtual bool + RecvNotifyRequestUrlSelected(const nsString& aUrl) override; + +private: + virtual ~PresentationRequestChild(); + + bool mActorDestroyed = false; + nsCOMPtr<nsIPresentationServiceCallback> mCallback; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_PresentationChild_h diff --git a/dom/presentation/ipc/PresentationContentSessionInfo.cpp b/dom/presentation/ipc/PresentationContentSessionInfo.cpp new file mode 100644 index 000000000..071ea924f --- /dev/null +++ b/dom/presentation/ipc/PresentationContentSessionInfo.cpp @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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 "nsServiceManagerUtils.h" +#include "PresentationContentSessionInfo.h" +#include "PresentationIPCService.h" + +namespace mozilla { +namespace dom { + +NS_IMPL_ISUPPORTS(PresentationContentSessionInfo, + nsIPresentationSessionTransportCallback); + +nsresult +PresentationContentSessionInfo::Init() { + if (NS_WARN_IF(NS_FAILED(mTransport->SetCallback(this)))) { + return NS_ERROR_NOT_AVAILABLE; + } + if (NS_WARN_IF(NS_FAILED(mTransport->EnableDataNotification()))) { + return NS_ERROR_NOT_AVAILABLE; + } + return NS_OK; +} + +nsresult +PresentationContentSessionInfo::Send(const nsAString& aData) +{ + if (!mTransport) { + return NS_ERROR_NOT_AVAILABLE; + } + + return mTransport->Send(aData); +} + +nsresult +PresentationContentSessionInfo::SendBinaryMsg(const nsACString& aData) +{ + if (NS_WARN_IF(!mTransport)) { + return NS_ERROR_NOT_AVAILABLE; + } + + return mTransport->SendBinaryMsg(aData); +} + +nsresult +PresentationContentSessionInfo::SendBlob(nsIDOMBlob* aBlob) +{ + if (NS_WARN_IF(!mTransport)) { + return NS_ERROR_NOT_AVAILABLE; + } + + return mTransport->SendBlob(aBlob); +} + +nsresult +PresentationContentSessionInfo::Close(nsresult aReason) +{ + if (!mTransport) { + return NS_ERROR_NOT_AVAILABLE; + } + + return mTransport->Close(aReason); +} + +// nsIPresentationSessionTransportCallback +NS_IMETHODIMP +PresentationContentSessionInfo::NotifyTransportReady() +{ + // do nothing since |onSessionTransport| implies this + return NS_OK; +} + +NS_IMETHODIMP +PresentationContentSessionInfo::NotifyTransportClosed(nsresult aReason) +{ + MOZ_ASSERT(NS_IsMainThread()); + + // Nullify |mTransport| here so it won't try to re-close |mTransport| in + // potential subsequent |Shutdown| calls. + mTransport = nullptr; + nsCOMPtr<nsIPresentationService> service = + do_GetService(PRESENTATION_SERVICE_CONTRACTID); + if (NS_WARN_IF(!service)) { + return NS_ERROR_NOT_AVAILABLE; + } + return static_cast<PresentationIPCService*>(service.get())-> + NotifyTransportClosed(mSessionId, mRole, aReason); +} + +NS_IMETHODIMP +PresentationContentSessionInfo::NotifyData(const nsACString& aData, + bool aIsBinary) +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsCOMPtr<nsIPresentationService> service = + do_GetService(PRESENTATION_SERVICE_CONTRACTID); + if (NS_WARN_IF(!service)) { + return NS_ERROR_NOT_AVAILABLE; + } + return static_cast<PresentationIPCService*>(service.get())-> + NotifyMessage(mSessionId, aData, aIsBinary); +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/presentation/ipc/PresentationContentSessionInfo.h b/dom/presentation/ipc/PresentationContentSessionInfo.h new file mode 100644 index 000000000..447485dbd --- /dev/null +++ b/dom/presentation/ipc/PresentationContentSessionInfo.h @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef mozilla_dom_PresentationContentSessionInfo_h +#define mozilla_dom_PresentationContentSessionInfo_h + +#include "nsCOMPtr.h" +#include "nsIPresentationSessionTransport.h" + +namespace mozilla { +namespace dom { + +/** + * PresentationContentSessionInfo manages nsIPresentationSessionTransport and + * delegates the callbacks to PresentationIPCService. Only lives in content + * process. + */ +class PresentationContentSessionInfo final : public nsIPresentationSessionTransportCallback +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPRESENTATIONSESSIONTRANSPORTCALLBACK + + PresentationContentSessionInfo(const nsAString& aSessionId, + uint8_t aRole, + nsIPresentationSessionTransport* aTransport) + : mSessionId(aSessionId) + , mRole(aRole) + , mTransport(aTransport) + { + MOZ_ASSERT(XRE_IsContentProcess()); + MOZ_ASSERT(!aSessionId.IsEmpty()); + MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER || + aRole == nsIPresentationService::ROLE_RECEIVER); + MOZ_ASSERT(aTransport); + } + + nsresult Init(); + + nsresult Send(const nsAString& aData); + + nsresult SendBinaryMsg(const nsACString& aData); + + nsresult SendBlob(nsIDOMBlob* aBlob); + + nsresult Close(nsresult aReason); + +private: + virtual ~PresentationContentSessionInfo() {} + + nsString mSessionId; + uint8_t mRole; + nsCOMPtr<nsIPresentationSessionTransport> mTransport; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_PresentationContentSessionInfo_h diff --git a/dom/presentation/ipc/PresentationIPCService.cpp b/dom/presentation/ipc/PresentationIPCService.cpp new file mode 100644 index 000000000..8c85b239d --- /dev/null +++ b/dom/presentation/ipc/PresentationIPCService.cpp @@ -0,0 +1,538 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et ft=cpp : */ +/* 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 "mozilla/dom/ContentChild.h" +#include "mozilla/dom/PermissionMessageUtils.h" +#include "mozilla/dom/PPresentation.h" +#include "mozilla/dom/TabParent.h" +#include "mozilla/ipc/InputStreamUtils.h" +#include "mozilla/ipc/URIUtils.h" +#include "nsGlobalWindow.h" +#include "nsIPresentationListener.h" +#include "PresentationCallbacks.h" +#include "PresentationChild.h" +#include "PresentationContentSessionInfo.h" +#include "PresentationIPCService.h" +#include "PresentationLog.h" + +using namespace mozilla; +using namespace mozilla::dom; +using namespace mozilla::ipc; + +namespace { + +PresentationChild* sPresentationChild; + +} // anonymous + +NS_IMPL_ISUPPORTS(PresentationIPCService, + nsIPresentationService, + nsIPresentationAvailabilityListener) + +PresentationIPCService::PresentationIPCService() +{ + ContentChild* contentChild = ContentChild::GetSingleton(); + if (NS_WARN_IF(!contentChild)) { + return; + } + sPresentationChild = new PresentationChild(this); + Unused << + NS_WARN_IF(!contentChild->SendPPresentationConstructor(sPresentationChild)); +} + +/* virtual */ +PresentationIPCService::~PresentationIPCService() +{ + Shutdown(); + + mSessionListeners.Clear(); + mSessionInfoAtController.Clear(); + mSessionInfoAtReceiver.Clear(); + sPresentationChild = nullptr; +} + +NS_IMETHODIMP +PresentationIPCService::StartSession( + const nsTArray<nsString>& aUrls, + const nsAString& aSessionId, + const nsAString& aOrigin, + const nsAString& aDeviceId, + uint64_t aWindowId, + nsIDOMEventTarget* aEventTarget, + nsIPrincipal* aPrincipal, + nsIPresentationServiceCallback* aCallback, + nsIPresentationTransportBuilderConstructor* aBuilderConstructor) +{ + if (aWindowId != 0) { + AddRespondingSessionId(aWindowId, + aSessionId, + nsIPresentationService::ROLE_CONTROLLER); + } + + nsPIDOMWindowInner* window = + nsGlobalWindow::GetInnerWindowWithId(aWindowId)->AsInner(); + TabId tabId = TabParent::GetTabIdFrom(window->GetDocShell()); + + return SendRequest(aCallback, StartSessionRequest(aUrls, + nsString(aSessionId), + nsString(aOrigin), + nsString(aDeviceId), + aWindowId, + tabId, + IPC::Principal(aPrincipal))); +} + +NS_IMETHODIMP +PresentationIPCService::SendSessionMessage(const nsAString& aSessionId, + uint8_t aRole, + const nsAString& aData) +{ + MOZ_ASSERT(!aSessionId.IsEmpty()); + MOZ_ASSERT(!aData.IsEmpty()); + + RefPtr<PresentationContentSessionInfo> info = + GetSessionInfo(aSessionId, aRole); + // data channel session transport is maintained by content process + if (info) { + return info->Send(aData); + } + + return SendRequest(nullptr, SendSessionMessageRequest(nsString(aSessionId), + aRole, + nsString(aData))); +} + +NS_IMETHODIMP +PresentationIPCService::SendSessionBinaryMsg(const nsAString& aSessionId, + uint8_t aRole, + const nsACString &aData) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!aData.IsEmpty()); + MOZ_ASSERT(!aSessionId.IsEmpty()); + MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER || + aRole == nsIPresentationService::ROLE_RECEIVER); + + RefPtr<PresentationContentSessionInfo> info = + GetSessionInfo(aSessionId, aRole); + // data channel session transport is maintained by content process + if (info) { + return info->SendBinaryMsg(aData); + } + + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +PresentationIPCService::SendSessionBlob(const nsAString& aSessionId, + uint8_t aRole, + nsIDOMBlob* aBlob) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!aSessionId.IsEmpty()); + MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER || + aRole == nsIPresentationService::ROLE_RECEIVER); + MOZ_ASSERT(aBlob); + + RefPtr<PresentationContentSessionInfo> info = + GetSessionInfo(aSessionId, aRole); + // data channel session transport is maintained by content process + if (info) { + return info->SendBlob(aBlob); + } + + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +PresentationIPCService::CloseSession(const nsAString& aSessionId, + uint8_t aRole, + uint8_t aClosedReason) +{ + MOZ_ASSERT(!aSessionId.IsEmpty()); + + nsresult rv = SendRequest(nullptr, CloseSessionRequest(nsString(aSessionId), + aRole, + aClosedReason)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + RefPtr<PresentationContentSessionInfo> info = + GetSessionInfo(aSessionId, aRole); + if (info) { + return info->Close(NS_OK); + } + + return NS_OK; +} + +NS_IMETHODIMP +PresentationIPCService::TerminateSession(const nsAString& aSessionId, + uint8_t aRole) +{ + MOZ_ASSERT(!aSessionId.IsEmpty()); + + nsresult rv = SendRequest(nullptr, TerminateSessionRequest(nsString(aSessionId), aRole)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + RefPtr<PresentationContentSessionInfo> info = + GetSessionInfo(aSessionId, aRole); + if (info) { + return info->Close(NS_OK); + } + + return NS_OK; +} + +NS_IMETHODIMP +PresentationIPCService::ReconnectSession(const nsTArray<nsString>& aUrls, + const nsAString& aSessionId, + uint8_t aRole, + nsIPresentationServiceCallback* aCallback) +{ + MOZ_ASSERT(!aSessionId.IsEmpty()); + + if (aRole != nsIPresentationService::ROLE_CONTROLLER) { + MOZ_ASSERT(false, "Only controller can call ReconnectSession."); + return NS_ERROR_INVALID_ARG; + } + + return SendRequest(aCallback, ReconnectSessionRequest(aUrls, + nsString(aSessionId), + aRole)); +} + +NS_IMETHODIMP +PresentationIPCService::BuildTransport(const nsAString& aSessionId, + uint8_t aRole) +{ + MOZ_ASSERT(!aSessionId.IsEmpty()); + + if (aRole != nsIPresentationService::ROLE_CONTROLLER) { + MOZ_ASSERT(false, "Only controller can call ReconnectSession."); + return NS_ERROR_INVALID_ARG; + } + + return SendRequest(nullptr, BuildTransportRequest(nsString(aSessionId), + aRole)); +} + +nsresult +PresentationIPCService::SendRequest(nsIPresentationServiceCallback* aCallback, + const PresentationIPCRequest& aRequest) +{ + if (sPresentationChild) { + PresentationRequestChild* actor = new PresentationRequestChild(aCallback); + Unused << NS_WARN_IF(!sPresentationChild->SendPPresentationRequestConstructor(actor, aRequest)); + } + return NS_OK; +} + +NS_IMETHODIMP +PresentationIPCService::RegisterAvailabilityListener( + const nsTArray<nsString>& aAvailabilityUrls, + nsIPresentationAvailabilityListener* aListener) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!aAvailabilityUrls.IsEmpty()); + MOZ_ASSERT(aListener); + + nsTArray<nsString> addedUrls; + mAvailabilityManager.AddAvailabilityListener(aAvailabilityUrls, + aListener, + addedUrls); + + if (sPresentationChild && !addedUrls.IsEmpty()) { + Unused << + NS_WARN_IF( + !sPresentationChild->SendRegisterAvailabilityHandler(addedUrls)); + } + return NS_OK; +} + +NS_IMETHODIMP +PresentationIPCService::UnregisterAvailabilityListener( + const nsTArray<nsString>& aAvailabilityUrls, + nsIPresentationAvailabilityListener* aListener) +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsTArray<nsString> removedUrls; + mAvailabilityManager.RemoveAvailabilityListener(aAvailabilityUrls, + aListener, + removedUrls); + + if (sPresentationChild && !removedUrls.IsEmpty()) { + Unused << + NS_WARN_IF( + !sPresentationChild->SendUnregisterAvailabilityHandler(removedUrls)); + } + return NS_OK; +} + +NS_IMETHODIMP +PresentationIPCService::RegisterSessionListener(const nsAString& aSessionId, + uint8_t aRole, + nsIPresentationSessionListener* aListener) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aListener); + + nsCOMPtr<nsIPresentationSessionListener> listener; + if (mSessionListeners.Get(aSessionId, getter_AddRefs(listener))) { + mSessionListeners.Put(aSessionId, aListener); + return NS_OK; + } + + mSessionListeners.Put(aSessionId, aListener); + if (sPresentationChild) { + Unused << + NS_WARN_IF(!sPresentationChild->SendRegisterSessionHandler( + nsString(aSessionId), aRole)); + } + return NS_OK; +} + +NS_IMETHODIMP +PresentationIPCService::UnregisterSessionListener(const nsAString& aSessionId, + uint8_t aRole) +{ + MOZ_ASSERT(NS_IsMainThread()); + + UntrackSessionInfo(aSessionId, aRole); + + mSessionListeners.Remove(aSessionId); + if (sPresentationChild) { + Unused << + NS_WARN_IF(!sPresentationChild->SendUnregisterSessionHandler( + nsString(aSessionId), aRole)); + } + return NS_OK; +} + +NS_IMETHODIMP +PresentationIPCService::RegisterRespondingListener(uint64_t aWindowId, + nsIPresentationRespondingListener* aListener) +{ + MOZ_ASSERT(NS_IsMainThread()); + + mRespondingListeners.Put(aWindowId, aListener); + if (sPresentationChild) { + Unused << + NS_WARN_IF(!sPresentationChild->SendRegisterRespondingHandler(aWindowId)); + } + return NS_OK; +} + +NS_IMETHODIMP +PresentationIPCService::UnregisterRespondingListener(uint64_t aWindowId) +{ + MOZ_ASSERT(NS_IsMainThread()); + + mRespondingListeners.Remove(aWindowId); + if (sPresentationChild) { + Unused << + NS_WARN_IF(!sPresentationChild->SendUnregisterRespondingHandler( + aWindowId)); + } + return NS_OK; +} + +nsresult +PresentationIPCService::NotifySessionTransport(const nsString& aSessionId, + const uint8_t& aRole, + nsIPresentationSessionTransport* aTransport) +{ + RefPtr<PresentationContentSessionInfo> info = + new PresentationContentSessionInfo(aSessionId, aRole, aTransport); + + if (NS_WARN_IF(NS_FAILED(info->Init()))) { + return NS_ERROR_NOT_AVAILABLE; + } + + if (aRole == nsIPresentationService::ROLE_CONTROLLER) { + mSessionInfoAtController.Put(aSessionId, info); + } else { + mSessionInfoAtReceiver.Put(aSessionId, info); + } + return NS_OK; +} + +NS_IMETHODIMP +PresentationIPCService::GetWindowIdBySessionId(const nsAString& aSessionId, + uint8_t aRole, + uint64_t* aWindowId) +{ + return GetWindowIdBySessionIdInternal(aSessionId, aRole, aWindowId); +} + +NS_IMETHODIMP +PresentationIPCService::UpdateWindowIdBySessionId(const nsAString& aSessionId, + uint8_t aRole, + const uint64_t aWindowId) +{ + return UpdateWindowIdBySessionIdInternal(aSessionId, aRole, aWindowId); +} + +nsresult +PresentationIPCService::NotifySessionStateChange(const nsAString& aSessionId, + uint16_t aState, + nsresult aReason) +{ + nsCOMPtr<nsIPresentationSessionListener> listener; + if (NS_WARN_IF(!mSessionListeners.Get(aSessionId, getter_AddRefs(listener)))) { + return NS_OK; + } + + return listener->NotifyStateChange(aSessionId, aState, aReason); +} + +// Only used for OOP RTCDataChannel session transport case. +nsresult +PresentationIPCService::NotifyMessage(const nsAString& aSessionId, + const nsACString& aData, + const bool& aIsBinary) +{ + nsCOMPtr<nsIPresentationSessionListener> listener; + if (NS_WARN_IF(!mSessionListeners.Get(aSessionId, getter_AddRefs(listener)))) { + return NS_OK; + } + + return listener->NotifyMessage(aSessionId, aData, aIsBinary); +} + +// Only used for OOP RTCDataChannel session transport case. +nsresult +PresentationIPCService::NotifyTransportClosed(const nsAString& aSessionId, + uint8_t aRole, + nsresult aReason) +{ + RefPtr<PresentationContentSessionInfo> info = + GetSessionInfo(aSessionId, aRole); + if (NS_WARN_IF(!info)) { + return NS_ERROR_NOT_AVAILABLE; + } + Unused << NS_WARN_IF(!sPresentationChild->SendNotifyTransportClosed(nsString(aSessionId), aRole, aReason)); + return NS_OK; +} + +nsresult +PresentationIPCService::NotifySessionConnect(uint64_t aWindowId, + const nsAString& aSessionId) +{ + nsCOMPtr<nsIPresentationRespondingListener> listener; + if (NS_WARN_IF(!mRespondingListeners.Get(aWindowId, getter_AddRefs(listener)))) { + return NS_OK; + } + + return listener->NotifySessionConnect(aWindowId, aSessionId); +} + +NS_IMETHODIMP +PresentationIPCService::NotifyAvailableChange( + const nsTArray<nsString>& aAvailabilityUrls, + bool aAvailable) +{ + return mAvailabilityManager.DoNotifyAvailableChange(aAvailabilityUrls, + aAvailable); +} + +NS_IMETHODIMP +PresentationIPCService::NotifyReceiverReady( + const nsAString& aSessionId, + uint64_t aWindowId, + bool aIsLoading, + nsIPresentationTransportBuilderConstructor* aBuilderConstructor) +{ + MOZ_ASSERT(NS_IsMainThread()); + + // No actual window uses 0 as its ID. + if (NS_WARN_IF(aWindowId == 0)) { + return NS_ERROR_NOT_AVAILABLE; + } + + // Track the responding info for an OOP receiver page. + AddRespondingSessionId(aWindowId, + aSessionId, + nsIPresentationService::ROLE_RECEIVER); + + Unused << NS_WARN_IF(!sPresentationChild->SendNotifyReceiverReady(nsString(aSessionId), + aWindowId, + aIsLoading)); + + // Release mCallback after using aSessionId + // because aSessionId is held by mCallback. + mCallback = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +PresentationIPCService::UntrackSessionInfo(const nsAString& aSessionId, + uint8_t aRole) +{ + PRES_DEBUG("content %s:id[%s], role[%d]\n", __func__, + NS_ConvertUTF16toUTF8(aSessionId).get(), aRole); + + if (nsIPresentationService::ROLE_RECEIVER == aRole) { + // Terminate receiver page. + uint64_t windowId; + if (NS_SUCCEEDED(GetWindowIdBySessionIdInternal(aSessionId, + aRole, + &windowId))) { + NS_DispatchToMainThread(NS_NewRunnableFunction([windowId]() -> void { + PRES_DEBUG("Attempt to close window[%d]\n", windowId); + + if (auto* window = nsGlobalWindow::GetInnerWindowWithId(windowId)) { + window->Close(); + } + })); + } + } + + // Remove the OOP responding info (if it has never been used). + RemoveRespondingSessionId(aSessionId, aRole); + + if (nsIPresentationService::ROLE_CONTROLLER == aRole) { + mSessionInfoAtController.Remove(aSessionId); + } else { + mSessionInfoAtReceiver.Remove(aSessionId); + } + + return NS_OK; +} + +void +PresentationIPCService::NotifyPresentationChildDestroyed() +{ + sPresentationChild = nullptr; +} + +nsresult +PresentationIPCService::MonitorResponderLoading(const nsAString& aSessionId, + nsIDocShell* aDocShell) +{ + MOZ_ASSERT(NS_IsMainThread()); + + mCallback = new PresentationResponderLoadingCallback(aSessionId); + return mCallback->Init(aDocShell); +} + +nsresult +PresentationIPCService::CloseContentSessionTransport(const nsString& aSessionId, + uint8_t aRole, + nsresult aReason) +{ + RefPtr<PresentationContentSessionInfo> info = + GetSessionInfo(aSessionId, aRole); + if (NS_WARN_IF(!info)) { + return NS_ERROR_NOT_AVAILABLE; + } + + return info->Close(aReason); +} diff --git a/dom/presentation/ipc/PresentationIPCService.h b/dom/presentation/ipc/PresentationIPCService.h new file mode 100644 index 000000000..5eab7e68a --- /dev/null +++ b/dom/presentation/ipc/PresentationIPCService.h @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et ft=cpp : */ +/* 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/. */ + +#ifndef mozilla_dom_PresentationIPCService_h +#define mozilla_dom_PresentationIPCService_h + +#include "mozilla/dom/PresentationServiceBase.h" +#include "nsIPresentationListener.h" +#include "nsIPresentationSessionTransport.h" +#include "nsIPresentationService.h" + +class nsIDocShell; + +namespace mozilla { +namespace dom { + +class PresentationIPCRequest; +class PresentationContentSessionInfo; +class PresentationResponderLoadingCallback; + +class PresentationIPCService final + : public nsIPresentationAvailabilityListener + , public nsIPresentationService + , public PresentationServiceBase<PresentationContentSessionInfo> +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPRESENTATIONAVAILABILITYLISTENER + NS_DECL_NSIPRESENTATIONSERVICE + + PresentationIPCService(); + + nsresult NotifySessionStateChange(const nsAString& aSessionId, + uint16_t aState, + nsresult aReason); + + nsresult NotifyMessage(const nsAString& aSessionId, + const nsACString& aData, + const bool& aIsBinary); + + nsresult NotifySessionConnect(uint64_t aWindowId, + const nsAString& aSessionId); + + void NotifyPresentationChildDestroyed(); + + nsresult MonitorResponderLoading(const nsAString& aSessionId, + nsIDocShell* aDocShell); + + nsresult NotifySessionTransport(const nsString& aSessionId, + const uint8_t& aRole, + nsIPresentationSessionTransport* transport); + + nsresult CloseContentSessionTransport(const nsString& aSessionId, + uint8_t aRole, + nsresult aReason); + +private: + virtual ~PresentationIPCService(); + nsresult SendRequest(nsIPresentationServiceCallback* aCallback, + const PresentationIPCRequest& aRequest); + + nsRefPtrHashtable<nsStringHashKey, + nsIPresentationSessionListener> mSessionListeners; + nsRefPtrHashtable<nsUint64HashKey, + nsIPresentationRespondingListener> mRespondingListeners; + RefPtr<PresentationResponderLoadingCallback> mCallback; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_PresentationIPCService_h diff --git a/dom/presentation/ipc/PresentationParent.cpp b/dom/presentation/ipc/PresentationParent.cpp new file mode 100644 index 000000000..02f60500a --- /dev/null +++ b/dom/presentation/ipc/PresentationParent.cpp @@ -0,0 +1,553 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* 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 "DCPresentationChannelDescription.h" +#include "mozilla/dom/ContentProcessManager.h" +#include "mozilla/ipc/InputStreamUtils.h" +#include "mozilla/Unused.h" +#include "nsIPresentationDeviceManager.h" +#include "nsIPresentationSessionTransport.h" +#include "nsIPresentationSessionTransportBuilder.h" +#include "nsServiceManagerUtils.h" +#include "PresentationBuilderParent.h" +#include "PresentationParent.h" +#include "PresentationService.h" +#include "PresentationSessionInfo.h" + +namespace mozilla { +namespace dom { + +namespace { + +class PresentationTransportBuilderConstructorIPC final : + public nsIPresentationTransportBuilderConstructor +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPRESENTATIONTRANSPORTBUILDERCONSTRUCTOR + + explicit PresentationTransportBuilderConstructorIPC(PresentationParent* aParent) + : mParent(aParent) + { + } + +private: + virtual ~PresentationTransportBuilderConstructorIPC() = default; + + RefPtr<PresentationParent> mParent; +}; + +NS_IMPL_ISUPPORTS(PresentationTransportBuilderConstructorIPC, + nsIPresentationTransportBuilderConstructor) + +NS_IMETHODIMP +PresentationTransportBuilderConstructorIPC::CreateTransportBuilder( + uint8_t aType, + nsIPresentationSessionTransportBuilder** aRetval) +{ + if (NS_WARN_IF(!aRetval)) { + return NS_ERROR_INVALID_ARG; + } + + *aRetval = nullptr; + + if (NS_WARN_IF(aType != nsIPresentationChannelDescription::TYPE_TCP && + aType != nsIPresentationChannelDescription::TYPE_DATACHANNEL)) { + return NS_ERROR_INVALID_ARG; + } + + if (XRE_IsContentProcess()) { + MOZ_ASSERT(false, + "CreateTransportBuilder can only be invoked in parent process."); + return NS_ERROR_FAILURE; + } + + nsCOMPtr<nsIPresentationSessionTransportBuilder> builder; + if (aType == nsIPresentationChannelDescription::TYPE_TCP) { + builder = do_CreateInstance(PRESENTATION_TCP_SESSION_TRANSPORT_CONTRACTID); + } else { + builder = new PresentationBuilderParent(mParent); + } + + if (NS_WARN_IF(!builder)) { + return NS_ERROR_DOM_OPERATION_ERR; + } + + builder.forget(aRetval); + return NS_OK; +} + +} // anonymous namespace + +/* + * Implementation of PresentationParent + */ + +NS_IMPL_ISUPPORTS(PresentationParent, + nsIPresentationAvailabilityListener, + nsIPresentationSessionListener, + nsIPresentationRespondingListener) + +PresentationParent::PresentationParent() +{ + MOZ_COUNT_CTOR(PresentationParent); +} + +/* virtual */ PresentationParent::~PresentationParent() +{ + MOZ_COUNT_DTOR(PresentationParent); +} + +bool +PresentationParent::Init(ContentParentId aContentParentId) +{ + MOZ_ASSERT(!mService); + mService = do_GetService(PRESENTATION_SERVICE_CONTRACTID); + mChildId = aContentParentId; + return NS_WARN_IF(!mService) ? false : true; +} + +void +PresentationParent::ActorDestroy(ActorDestroyReason aWhy) +{ + mActorDestroyed = true; + + for (uint32_t i = 0; i < mSessionIdsAtController.Length(); i++) { + Unused << NS_WARN_IF(NS_FAILED(mService-> + UnregisterSessionListener(mSessionIdsAtController[i], + nsIPresentationService::ROLE_CONTROLLER))); + } + mSessionIdsAtController.Clear(); + + for (uint32_t i = 0; i < mSessionIdsAtReceiver.Length(); i++) { + Unused << NS_WARN_IF(NS_FAILED(mService-> + UnregisterSessionListener(mSessionIdsAtReceiver[i], nsIPresentationService::ROLE_RECEIVER))); + } + mSessionIdsAtReceiver.Clear(); + + for (uint32_t i = 0; i < mWindowIds.Length(); i++) { + Unused << NS_WARN_IF(NS_FAILED(mService-> + UnregisterRespondingListener(mWindowIds[i]))); + } + mWindowIds.Clear(); + + if (!mContentAvailabilityUrls.IsEmpty()) { + mService->UnregisterAvailabilityListener(mContentAvailabilityUrls, this); + } + mService = nullptr; +} + +bool +PresentationParent::RecvPPresentationRequestConstructor( + PPresentationRequestParent* aActor, + const PresentationIPCRequest& aRequest) +{ + PresentationRequestParent* actor = static_cast<PresentationRequestParent*>(aActor); + + nsresult rv = NS_ERROR_FAILURE; + switch (aRequest.type()) { + case PresentationIPCRequest::TStartSessionRequest: + rv = actor->DoRequest(aRequest.get_StartSessionRequest()); + break; + case PresentationIPCRequest::TSendSessionMessageRequest: + rv = actor->DoRequest(aRequest.get_SendSessionMessageRequest()); + break; + case PresentationIPCRequest::TCloseSessionRequest: + rv = actor->DoRequest(aRequest.get_CloseSessionRequest()); + break; + case PresentationIPCRequest::TTerminateSessionRequest: + rv = actor->DoRequest(aRequest.get_TerminateSessionRequest()); + break; + case PresentationIPCRequest::TReconnectSessionRequest: + rv = actor->DoRequest(aRequest.get_ReconnectSessionRequest()); + break; + case PresentationIPCRequest::TBuildTransportRequest: + rv = actor->DoRequest(aRequest.get_BuildTransportRequest()); + break; + default: + MOZ_CRASH("Unknown PresentationIPCRequest type"); + } + + return NS_WARN_IF(NS_FAILED(rv)) ? false : true; +} + +PPresentationRequestParent* +PresentationParent::AllocPPresentationRequestParent( + const PresentationIPCRequest& aRequest) +{ + MOZ_ASSERT(mService); + RefPtr<PresentationRequestParent> actor = new PresentationRequestParent(mService, mChildId); + return actor.forget().take(); +} + +bool +PresentationParent::DeallocPPresentationRequestParent( + PPresentationRequestParent* aActor) +{ + RefPtr<PresentationRequestParent> actor = + dont_AddRef(static_cast<PresentationRequestParent*>(aActor)); + return true; +} + +PPresentationBuilderParent* +PresentationParent::AllocPPresentationBuilderParent(const nsString& aSessionId, + const uint8_t& aRole) +{ + NS_NOTREACHED("We should never be manually allocating AllocPPresentationBuilderParent actors"); + return nullptr; +} + +bool +PresentationParent::DeallocPPresentationBuilderParent( + PPresentationBuilderParent* aActor) +{ + return true; +} + +bool +PresentationParent::Recv__delete__() +{ + return true; +} + +bool +PresentationParent::RecvRegisterAvailabilityHandler( + nsTArray<nsString>&& aAvailabilityUrls) +{ + MOZ_ASSERT(mService); + + Unused << NS_WARN_IF(NS_FAILED(mService->RegisterAvailabilityListener( + aAvailabilityUrls, + this))); + mContentAvailabilityUrls.AppendElements(aAvailabilityUrls); + return true; +} + +bool +PresentationParent::RecvUnregisterAvailabilityHandler( + nsTArray<nsString>&& aAvailabilityUrls) +{ + MOZ_ASSERT(mService); + + Unused << NS_WARN_IF(NS_FAILED(mService->UnregisterAvailabilityListener( + aAvailabilityUrls, + this))); + for (const auto& url : aAvailabilityUrls) { + mContentAvailabilityUrls.RemoveElement(url); + } + return true; +} + +/* virtual */ bool +PresentationParent::RecvRegisterSessionHandler(const nsString& aSessionId, + const uint8_t& aRole) +{ + MOZ_ASSERT(mService); + + // Validate the accessibility (primarily for receiver side) so that a + // compromised child process can't fake the ID. + if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())-> + IsSessionAccessible(aSessionId, aRole, OtherPid()))) { + return true; + } + + if (nsIPresentationService::ROLE_CONTROLLER == aRole) { + mSessionIdsAtController.AppendElement(aSessionId); + } else { + mSessionIdsAtReceiver.AppendElement(aSessionId); + } + Unused << NS_WARN_IF(NS_FAILED(mService->RegisterSessionListener(aSessionId, aRole, this))); + return true; +} + +/* virtual */ bool +PresentationParent::RecvUnregisterSessionHandler(const nsString& aSessionId, + const uint8_t& aRole) +{ + MOZ_ASSERT(mService); + if (nsIPresentationService::ROLE_CONTROLLER == aRole) { + mSessionIdsAtController.RemoveElement(aSessionId); + } else { + mSessionIdsAtReceiver.RemoveElement(aSessionId); + } + Unused << NS_WARN_IF(NS_FAILED(mService->UnregisterSessionListener(aSessionId, aRole))); + return true; +} + +/* virtual */ bool +PresentationParent::RecvRegisterRespondingHandler(const uint64_t& aWindowId) +{ + MOZ_ASSERT(mService); + + mWindowIds.AppendElement(aWindowId); + Unused << NS_WARN_IF(NS_FAILED(mService->RegisterRespondingListener(aWindowId, this))); + return true; +} + +/* virtual */ bool +PresentationParent::RecvUnregisterRespondingHandler(const uint64_t& aWindowId) +{ + MOZ_ASSERT(mService); + mWindowIds.RemoveElement(aWindowId); + Unused << NS_WARN_IF(NS_FAILED(mService->UnregisterRespondingListener(aWindowId))); + return true; +} + +NS_IMETHODIMP +PresentationParent::NotifyAvailableChange(const nsTArray<nsString>& aAvailabilityUrls, + bool aAvailable) +{ + if (NS_WARN_IF(mActorDestroyed || + !SendNotifyAvailableChange(aAvailabilityUrls, + aAvailable))) { + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +NS_IMETHODIMP +PresentationParent::NotifyStateChange(const nsAString& aSessionId, + uint16_t aState, + nsresult aReason) +{ + if (NS_WARN_IF(mActorDestroyed || + !SendNotifySessionStateChange(nsString(aSessionId), + aState, + aReason))) { + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +NS_IMETHODIMP +PresentationParent::NotifyMessage(const nsAString& aSessionId, + const nsACString& aData, + bool aIsBinary) +{ + if (NS_WARN_IF(mActorDestroyed || + !SendNotifyMessage(nsString(aSessionId), + nsCString(aData), + aIsBinary))) { + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +NS_IMETHODIMP +PresentationParent::NotifySessionConnect(uint64_t aWindowId, + const nsAString& aSessionId) +{ + if (NS_WARN_IF(mActorDestroyed || + !SendNotifySessionConnect(aWindowId, nsString(aSessionId)))) { + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +bool +PresentationParent::RecvNotifyReceiverReady(const nsString& aSessionId, + const uint64_t& aWindowId, + const bool& aIsLoading) +{ + MOZ_ASSERT(mService); + + nsCOMPtr<nsIPresentationTransportBuilderConstructor> constructor = + new PresentationTransportBuilderConstructorIPC(this); + Unused << NS_WARN_IF(NS_FAILED(mService->NotifyReceiverReady(aSessionId, + aWindowId, + aIsLoading, + constructor))); + return true; +} + +bool +PresentationParent::RecvNotifyTransportClosed(const nsString& aSessionId, + const uint8_t& aRole, + const nsresult& aReason) +{ + MOZ_ASSERT(mService); + + Unused << NS_WARN_IF(NS_FAILED(mService->NotifyTransportClosed(aSessionId, aRole, aReason))); + return true; +} + +/* + * Implementation of PresentationRequestParent + */ + +NS_IMPL_ISUPPORTS(PresentationRequestParent, nsIPresentationServiceCallback) + +PresentationRequestParent::PresentationRequestParent(nsIPresentationService* aService, + ContentParentId aContentParentId) + : mService(aService) + , mChildId(aContentParentId) +{ + MOZ_COUNT_CTOR(PresentationRequestParent); +} + +PresentationRequestParent::~PresentationRequestParent() +{ + MOZ_COUNT_DTOR(PresentationRequestParent); +} + +void +PresentationRequestParent::ActorDestroy(ActorDestroyReason aWhy) +{ + mActorDestroyed = true; + mService = nullptr; +} + +nsresult +PresentationRequestParent::DoRequest(const StartSessionRequest& aRequest) +{ + MOZ_ASSERT(mService); + + mSessionId = aRequest.sessionId(); + + nsCOMPtr<nsIDOMEventTarget> eventTarget; + ContentProcessManager* cpm = ContentProcessManager::GetSingleton(); + RefPtr<TabParent> tp = + cpm->GetTopLevelTabParentByProcessAndTabId(mChildId, aRequest.tabId()); + if (tp) { + eventTarget = do_QueryInterface(tp->GetOwnerElement()); + } + + RefPtr<PresentationParent> parent = static_cast<PresentationParent*>(Manager()); + nsCOMPtr<nsIPresentationTransportBuilderConstructor> constructor = + new PresentationTransportBuilderConstructorIPC(parent); + return mService->StartSession(aRequest.urls(), aRequest.sessionId(), + aRequest.origin(), aRequest.deviceId(), + aRequest.windowId(), eventTarget, + aRequest.principal(), this, constructor); +} + +nsresult +PresentationRequestParent::DoRequest(const SendSessionMessageRequest& aRequest) +{ + MOZ_ASSERT(mService); + + // Validate the accessibility (primarily for receiver side) so that a + // compromised child process can't fake the ID. + if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())-> + IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) { + return SendResponse(NS_ERROR_DOM_SECURITY_ERR); + } + + nsresult rv = mService->SendSessionMessage(aRequest.sessionId(), + aRequest.role(), + aRequest.data()); + if (NS_WARN_IF(NS_FAILED(rv))) { + return SendResponse(rv); + } + return SendResponse(NS_OK); +} + +nsresult +PresentationRequestParent::DoRequest(const CloseSessionRequest& aRequest) +{ + MOZ_ASSERT(mService); + + // Validate the accessibility (primarily for receiver side) so that a + // compromised child process can't fake the ID. + if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())-> + IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) { + return SendResponse(NS_ERROR_DOM_SECURITY_ERR); + } + + nsresult rv = mService->CloseSession(aRequest.sessionId(), + aRequest.role(), + aRequest.closedReason()); + if (NS_WARN_IF(NS_FAILED(rv))) { + return SendResponse(rv); + } + return SendResponse(NS_OK); +} + +nsresult +PresentationRequestParent::DoRequest(const TerminateSessionRequest& aRequest) +{ + MOZ_ASSERT(mService); + + // Validate the accessibility (primarily for receiver side) so that a + // compromised child process can't fake the ID. + if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())-> + IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) { + return SendResponse(NS_ERROR_DOM_SECURITY_ERR); + } + + nsresult rv = mService->TerminateSession(aRequest.sessionId(), aRequest.role()); + if (NS_WARN_IF(NS_FAILED(rv))) { + return SendResponse(rv); + } + return SendResponse(NS_OK); +} + +nsresult +PresentationRequestParent::DoRequest(const ReconnectSessionRequest& aRequest) +{ + MOZ_ASSERT(mService); + + // Validate the accessibility (primarily for receiver side) so that a + // compromised child process can't fake the ID. + if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())-> + IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) { + + // NOTE: Return NS_ERROR_DOM_NOT_FOUND_ERR here to match the spec. + // https://w3c.github.io/presentation-api/#reconnecting-to-a-presentation + return SendResponse(NS_ERROR_DOM_NOT_FOUND_ERR); + } + + mSessionId = aRequest.sessionId(); + return mService->ReconnectSession(aRequest.urls(), + aRequest.sessionId(), + aRequest.role(), + this); +} + +nsresult +PresentationRequestParent::DoRequest(const BuildTransportRequest& aRequest) +{ + MOZ_ASSERT(mService); + + // Validate the accessibility (primarily for receiver side) so that a + // compromised child process can't fake the ID. + if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())-> + IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) { + return SendResponse(NS_ERROR_DOM_SECURITY_ERR); + } + + nsresult rv = mService->BuildTransport(aRequest.sessionId(), aRequest.role()); + if (NS_WARN_IF(NS_FAILED(rv))) { + return SendResponse(rv); + } + return SendResponse(NS_OK); +} + +NS_IMETHODIMP +PresentationRequestParent::NotifySuccess(const nsAString& aUrl) +{ + Unused << SendNotifyRequestUrlSelected(nsString(aUrl)); + return SendResponse(NS_OK); +} + +NS_IMETHODIMP +PresentationRequestParent::NotifyError(nsresult aError) +{ + return SendResponse(aError); +} + +nsresult +PresentationRequestParent::SendResponse(nsresult aResult) +{ + if (NS_WARN_IF(mActorDestroyed || !Send__delete__(this, aResult))) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/presentation/ipc/PresentationParent.h b/dom/presentation/ipc/PresentationParent.h new file mode 100644 index 000000000..b038aa216 --- /dev/null +++ b/dom/presentation/ipc/PresentationParent.h @@ -0,0 +1,137 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef mozilla_dom_PresentationParent_h__ +#define mozilla_dom_PresentationParent_h__ + +#include "mozilla/dom/ipc/IdType.h" +#include "mozilla/dom/PPresentationBuilderParent.h" +#include "mozilla/dom/PPresentationParent.h" +#include "mozilla/dom/PPresentationRequestParent.h" +#include "nsIPresentationListener.h" +#include "nsIPresentationService.h" +#include "nsIPresentationSessionTransportBuilder.h" + +namespace mozilla { +namespace dom { + +class PresentationParent final : public PPresentationParent + , public nsIPresentationAvailabilityListener + , public nsIPresentationSessionListener + , public nsIPresentationRespondingListener +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPRESENTATIONAVAILABILITYLISTENER + NS_DECL_NSIPRESENTATIONSESSIONLISTENER + NS_DECL_NSIPRESENTATIONRESPONDINGLISTENER + + PresentationParent(); + + bool Init(ContentParentId aContentParentId); + + bool RegisterTransportBuilder(const nsString& aSessionId, const uint8_t& aRole); + + virtual void ActorDestroy(ActorDestroyReason aWhy) override; + + virtual bool + RecvPPresentationRequestConstructor(PPresentationRequestParent* aActor, + const PresentationIPCRequest& aRequest) override; + + virtual PPresentationRequestParent* + AllocPPresentationRequestParent(const PresentationIPCRequest& aRequest) override; + + virtual bool + DeallocPPresentationRequestParent(PPresentationRequestParent* aActor) override; + + virtual PPresentationBuilderParent* + AllocPPresentationBuilderParent(const nsString& aSessionId, + const uint8_t& aRole) override; + + virtual bool + DeallocPPresentationBuilderParent( + PPresentationBuilderParent* aActor) override; + + virtual bool Recv__delete__() override; + + virtual bool RecvRegisterAvailabilityHandler( + nsTArray<nsString>&& aAvailabilityUrls) override; + + virtual bool RecvUnregisterAvailabilityHandler( + nsTArray<nsString>&& aAvailabilityUrls) override; + + virtual bool RecvRegisterSessionHandler(const nsString& aSessionId, + const uint8_t& aRole) override; + + virtual bool RecvUnregisterSessionHandler(const nsString& aSessionId, + const uint8_t& aRole) override; + + virtual bool RecvRegisterRespondingHandler(const uint64_t& aWindowId) override; + + virtual bool RecvUnregisterRespondingHandler(const uint64_t& aWindowId) override; + + virtual bool RecvNotifyReceiverReady(const nsString& aSessionId, + const uint64_t& aWindowId, + const bool& aIsLoading) override; + + virtual bool RecvNotifyTransportClosed(const nsString& aSessionId, + const uint8_t& aRole, + const nsresult& aReason) override; + +private: + virtual ~PresentationParent(); + + bool mActorDestroyed = false; + nsCOMPtr<nsIPresentationService> mService; + nsTArray<nsString> mSessionIdsAtController; + nsTArray<nsString> mSessionIdsAtReceiver; + nsTArray<uint64_t> mWindowIds; + ContentParentId mChildId; + nsTArray<nsString> mContentAvailabilityUrls; +}; + +class PresentationRequestParent final : public PPresentationRequestParent + , public nsIPresentationServiceCallback +{ + friend class PresentationParent; + +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPRESENTATIONSERVICECALLBACK + + explicit PresentationRequestParent(nsIPresentationService* aService, + ContentParentId aContentParentId); + + virtual void ActorDestroy(ActorDestroyReason aWhy) override; + +private: + virtual ~PresentationRequestParent(); + + nsresult SendResponse(nsresult aResult); + + nsresult DoRequest(const StartSessionRequest& aRequest); + + nsresult DoRequest(const SendSessionMessageRequest& aRequest); + + nsresult DoRequest(const CloseSessionRequest& aRequest); + + nsresult DoRequest(const TerminateSessionRequest& aRequest); + + nsresult DoRequest(const ReconnectSessionRequest& aRequest); + + nsresult DoRequest(const BuildTransportRequest& aRequest); + + bool mActorDestroyed = false; + bool mNeedRegisterBuilder = false; + nsString mSessionId; + nsCOMPtr<nsIPresentationService> mService; + ContentParentId mChildId; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_PresentationParent_h__ |