summaryrefslogtreecommitdiffstats
path: root/dom/presentation/ipc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /dom/presentation/ipc
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--dom/presentation/ipc/PPresentation.ipdl114
-rw-r--r--dom/presentation/ipc/PPresentationBuilder.ipdl34
-rw-r--r--dom/presentation/ipc/PPresentationRequest.ipdl22
-rw-r--r--dom/presentation/ipc/PresentationBuilderChild.cpp172
-rw-r--r--dom/presentation/ipc/PresentationBuilderChild.h47
-rw-r--r--dom/presentation/ipc/PresentationBuilderParent.cpp228
-rw-r--r--dom/presentation/ipc/PresentationBuilderParent.h52
-rw-r--r--dom/presentation/ipc/PresentationChild.cpp173
-rw-r--r--dom/presentation/ipc/PresentationChild.h88
-rw-r--r--dom/presentation/ipc/PresentationContentSessionInfo.cpp98
-rw-r--r--dom/presentation/ipc/PresentationContentSessionInfo.h62
-rw-r--r--dom/presentation/ipc/PresentationIPCService.cpp477
-rw-r--r--dom/presentation/ipc/PresentationIPCService.h71
-rw-r--r--dom/presentation/ipc/PresentationParent.cpp497
-rw-r--r--dom/presentation/ipc/PresentationParent.h133
15 files changed, 2268 insertions, 0 deletions
diff --git a/dom/presentation/ipc/PPresentation.ipdl b/dom/presentation/ipc/PPresentation.ipdl
new file mode 100644
index 0000000000..bfaca8fb57
--- /dev/null
+++ b/dom/presentation/ipc/PPresentation.ipdl
@@ -0,0 +1,114 @@
+/* -*- 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;
+
+include "mozilla/dom/PermissionMessageUtils.h";
+
+using refcounted class nsIPrincipal from "nsIPrincipal.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;
+ nsIPrincipal 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 0000000000..e32b02e8f3
--- /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 0000000000..fa99dfcabb
--- /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 0000000000..d4e1120392
--- /dev/null
+++ b/dom/presentation/ipc/PresentationBuilderChild.cpp
@@ -0,0 +1,172 @@
+/* -*- 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/. */
+
+#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 =
+ nsGlobalWindowInner::GetInnerWindowWithId(windowId);
+ 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;
+}
+
+mozilla::ipc::IPCResult PresentationBuilderChild::RecvOnOffer(
+ const nsString& aSDP) {
+ if (NS_WARN_IF(!mBuilder)) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ RefPtr<DCPresentationChannelDescription> description =
+ new DCPresentationChannelDescription(aSDP);
+
+ if (NS_WARN_IF(NS_FAILED(mBuilder->OnOffer(description)))) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult PresentationBuilderChild::RecvOnAnswer(
+ const nsString& aSDP) {
+ if (NS_WARN_IF(!mBuilder)) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ RefPtr<DCPresentationChannelDescription> description =
+ new DCPresentationChannelDescription(aSDP);
+
+ if (NS_WARN_IF(NS_FAILED(mBuilder->OnAnswer(description)))) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult PresentationBuilderChild::RecvOnIceCandidate(
+ const nsString& aCandidate) {
+ if (NS_WARN_IF(mBuilder && NS_FAILED(mBuilder->OnIceCandidate(aCandidate)))) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ return IPC_OK();
+}
+
+// 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 0000000000..8da43245da
--- /dev/null
+++ b/dom/presentation/ipc/PresentationBuilderChild.h
@@ -0,0 +1,47 @@
+/* -*- 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_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;
+
+ mozilla::ipc::IPCResult RecvOnOffer(const nsString& aSDP);
+
+ mozilla::ipc::IPCResult RecvOnAnswer(const nsString& aSDP);
+
+ mozilla::ipc::IPCResult RecvOnIceCandidate(const nsString& aCandidate);
+
+ 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 0000000000..cc451d7465
--- /dev/null
+++ b/dom/presentation/ipc/PresentationBuilderParent.cpp
@@ -0,0 +1,228 @@
+/* -*- 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/. */
+
+#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(Blob* 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) {}
+
+PresentationBuilderParent::~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;
+}
+
+mozilla::ipc::IPCResult PresentationBuilderParent::RecvSendOffer(
+ const nsString& aSDP) {
+ RefPtr<DCPresentationChannelDescription> description =
+ new DCPresentationChannelDescription(aSDP);
+ if (NS_WARN_IF(!mBuilderListener ||
+ NS_FAILED(mBuilderListener->SendOffer(description)))) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult PresentationBuilderParent::RecvSendAnswer(
+ const nsString& aSDP) {
+ RefPtr<DCPresentationChannelDescription> description =
+ new DCPresentationChannelDescription(aSDP);
+ if (NS_WARN_IF(!mBuilderListener ||
+ NS_FAILED(mBuilderListener->SendAnswer(description)))) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult PresentationBuilderParent::RecvSendIceCandidate(
+ const nsString& aCandidate) {
+ if (NS_WARN_IF(!mBuilderListener ||
+ NS_FAILED(mBuilderListener->SendIceCandidate(aCandidate)))) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult PresentationBuilderParent::RecvClose(
+ const nsresult& aReason) {
+ if (NS_WARN_IF(!mBuilderListener ||
+ NS_FAILED(mBuilderListener->Close(aReason)))) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ return IPC_OK();
+}
+
+// Delegate to nsIPresentationSessionTransportBuilderListener
+mozilla::ipc::IPCResult PresentationBuilderParent::RecvOnSessionTransport() {
+ RefPtr<PresentationBuilderParent> kungFuDeathGrip = this;
+ Unused << NS_WARN_IF(
+ !mBuilderListener ||
+ NS_FAILED(mBuilderListener->OnSessionTransport(mIPCSessionTransport)));
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult PresentationBuilderParent::RecvOnSessionTransportError(
+ const nsresult& aReason) {
+ if (NS_WARN_IF(!mBuilderListener ||
+ NS_FAILED(mBuilderListener->OnError(aReason)))) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ return IPC_OK();
+}
+
+} // namespace dom
+} // namespace mozilla
diff --git a/dom/presentation/ipc/PresentationBuilderParent.h b/dom/presentation/ipc/PresentationBuilderParent.h
new file mode 100644
index 0000000000..6f8e097c16
--- /dev/null
+++ b/dom/presentation/ipc/PresentationBuilderParent.h
@@ -0,0 +1,52 @@
+/* -*- 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_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);
+
+ mozilla::ipc::IPCResult RecvSendOffer(const nsString& aSDP);
+
+ mozilla::ipc::IPCResult RecvSendAnswer(const nsString& aSDP);
+
+ mozilla::ipc::IPCResult RecvSendIceCandidate(const nsString& aCandidate);
+
+ mozilla::ipc::IPCResult RecvClose(const nsresult& aReason);
+
+ virtual void ActorDestroy(ActorDestroyReason aWhy) override;
+
+ mozilla::ipc::IPCResult RecvOnSessionTransport();
+
+ mozilla::ipc::IPCResult RecvOnSessionTransportError(const nsresult& aReason);
+
+ 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 0000000000..77737e2e5e
--- /dev/null
+++ b/dom/presentation/ipc/PresentationChild.cpp
@@ -0,0 +1,173 @@
+/* -*- 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/. */
+
+#include "DCPresentationChannelDescription.h"
+#include "mozilla/StaticPtr.h"
+#include "PresentationBuilderChild.h"
+#include "PresentationChild.h"
+#include "PresentationIPCService.h"
+#include "nsThreadUtils.h"
+
+namespace mozilla {
+namespace 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) {
+ MOZ_ASSERT_UNREACHABLE(
+ "We should never be manually allocating "
+ "PPresentationRequestChild actors");
+ return nullptr;
+}
+
+bool PresentationChild::DeallocPPresentationRequestChild(
+ PPresentationRequestChild* aActor) {
+ delete aActor;
+ return true;
+}
+
+mozilla::ipc::IPCResult PresentationChild::RecvPPresentationBuilderConstructor(
+ PPresentationBuilderChild* aActor, const nsString& aSessionId,
+ const uint8_t& aRole) {
+ // Child will build the session transport
+ PresentationBuilderChild* actor =
+ static_cast<PresentationBuilderChild*>(aActor);
+ if (NS_WARN_IF(NS_FAILED(actor->Init()))) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ return IPC_OK();
+}
+
+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;
+}
+
+mozilla::ipc::IPCResult PresentationChild::RecvNotifyAvailableChange(
+ nsTArray<nsString>&& aAvailabilityUrls, const bool& aAvailable) {
+ if (mService) {
+ Unused << NS_WARN_IF(NS_FAILED(
+ mService->NotifyAvailableChange(aAvailabilityUrls, aAvailable)));
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult 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 IPC_OK();
+}
+
+mozilla::ipc::IPCResult 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 IPC_OK();
+}
+
+mozilla::ipc::IPCResult PresentationChild::RecvNotifySessionConnect(
+ const uint64_t& aWindowId, const nsString& aSessionId) {
+ if (mService) {
+ Unused << NS_WARN_IF(
+ NS_FAILED(mService->NotifySessionConnect(aWindowId, aSessionId)));
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult 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 IPC_OK();
+}
+
+/*
+ * 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;
+}
+
+mozilla::ipc::IPCResult PresentationRequestChild::Recv__delete__(
+ const nsresult& aResult) {
+ if (mActorDestroyed) {
+ return IPC_OK();
+ }
+
+ if (mCallback) {
+ if (NS_FAILED(aResult)) {
+ Unused << NS_WARN_IF(NS_FAILED(mCallback->NotifyError(aResult)));
+ }
+ }
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult PresentationRequestChild::RecvNotifyRequestUrlSelected(
+ const nsString& aUrl) {
+ Unused << NS_WARN_IF(NS_FAILED(mCallback->NotifySuccess(aUrl)));
+ return IPC_OK();
+}
+
+} // namespace dom
+} // namespace mozilla
diff --git a/dom/presentation/ipc/PresentationChild.h b/dom/presentation/ipc/PresentationChild.h
new file mode 100644
index 0000000000..3c02353350
--- /dev/null
+++ b/dom/presentation/ipc/PresentationChild.h
@@ -0,0 +1,88 @@
+/* -*- 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_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;
+
+ PPresentationRequestChild* AllocPPresentationRequestChild(
+ const PresentationIPCRequest& aRequest);
+
+ bool DeallocPPresentationRequestChild(PPresentationRequestChild* aActor);
+
+ mozilla::ipc::IPCResult RecvPPresentationBuilderConstructor(
+ PPresentationBuilderChild* aActor, const nsString& aSessionId,
+ const uint8_t& aRole) override;
+
+ PPresentationBuilderChild* AllocPPresentationBuilderChild(
+ const nsString& aSessionId, const uint8_t& aRole);
+
+ bool DeallocPPresentationBuilderChild(PPresentationBuilderChild* aActor);
+
+ mozilla::ipc::IPCResult RecvNotifyAvailableChange(
+ nsTArray<nsString>&& aAvailabilityUrls, const bool& aAvailable);
+
+ mozilla::ipc::IPCResult RecvNotifySessionStateChange(
+ const nsString& aSessionId, const uint16_t& aState,
+ const nsresult& aReason);
+
+ mozilla::ipc::IPCResult RecvNotifyMessage(const nsString& aSessionId,
+ const nsCString& aData,
+ const bool& aIsBinary);
+
+ mozilla::ipc::IPCResult RecvNotifySessionConnect(const uint64_t& aWindowId,
+ const nsString& aSessionId);
+
+ mozilla::ipc::IPCResult RecvNotifyCloseSessionTransport(
+ const nsString& aSessionId, const uint8_t& aRole,
+ const nsresult& aReason);
+
+ 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;
+
+ mozilla::ipc::IPCResult Recv__delete__(const nsresult& aResult);
+
+ mozilla::ipc::IPCResult RecvNotifyRequestUrlSelected(const nsString& aUrl);
+
+ 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 0000000000..8190aedbf3
--- /dev/null
+++ b/dom/presentation/ipc/PresentationContentSessionInfo.cpp
@@ -0,0 +1,98 @@
+/* -*- 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/. */
+
+#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(Blob* 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 0000000000..7f15da1859
--- /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"
+
+// XXX Avoid including this here by moving function bodies to the cpp file
+#include "nsIPresentationService.h"
+#include "nsXULAppAPI.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(Blob* aBlob);
+
+ nsresult Close(nsresult aReason);
+
+ private:
+ virtual ~PresentationContentSessionInfo() = default;
+
+ 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 0000000000..c99ce1c2ae
--- /dev/null
+++ b/dom/presentation/ipc/PresentationIPCService.cpp
@@ -0,0 +1,477 @@
+/* -*- 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/. */
+
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/PermissionMessageUtils.h"
+#include "mozilla/dom/PPresentation.h"
+#include "mozilla/dom/BrowserParent.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"
+
+namespace mozilla {
+namespace dom {
+
+namespace {
+
+PresentationChild* sPresentationChild;
+
+} // namespace
+
+NS_IMPL_ISUPPORTS(PresentationIPCService, nsIPresentationService,
+ nsIPresentationAvailabilityListener)
+
+PresentationIPCService::PresentationIPCService() {
+ ContentChild* contentChild = ContentChild::GetSingleton();
+ if (NS_WARN_IF(!contentChild || contentChild->IsShuttingDown())) {
+ 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,
+ EventTarget* aEventTarget, nsIPrincipal* aPrincipal,
+ nsIPresentationServiceCallback* aCallback,
+ nsIPresentationTransportBuilderConstructor* aBuilderConstructor) {
+ if (aWindowId != 0) {
+ AddRespondingSessionId(aWindowId, aSessionId,
+ nsIPresentationService::ROLE_CONTROLLER);
+ }
+
+ nsPIDOMWindowInner* window =
+ nsGlobalWindowInner::GetInnerWindowWithId(aWindowId);
+ TabId tabId = BrowserParent::GetTabIdFrom(window->GetDocShell());
+
+ SendRequest(
+ aCallback,
+ StartSessionRequest(aUrls, nsString(aSessionId), nsString(aOrigin),
+ nsString(aDeviceId), aWindowId, tabId, aPrincipal));
+ return NS_OK;
+}
+
+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);
+ }
+
+ SendRequest(nullptr, SendSessionMessageRequest(nsString(aSessionId), aRole,
+ nsString(aData)));
+ return NS_OK;
+}
+
+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, Blob* 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());
+
+ SendRequest(nullptr,
+ CloseSessionRequest(nsString(aSessionId), aRole, aClosedReason));
+
+ 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());
+
+ SendRequest(nullptr, TerminateSessionRequest(nsString(aSessionId), aRole));
+
+ 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;
+ }
+
+ SendRequest(aCallback,
+ ReconnectSessionRequest(aUrls, nsString(aSessionId), aRole));
+ return NS_OK;
+}
+
+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;
+ }
+
+ SendRequest(nullptr, BuildTransportRequest(nsString(aSessionId), aRole));
+ return NS_OK;
+}
+
+void PresentationIPCService::SendRequest(
+ nsIPresentationServiceCallback* aCallback,
+ const PresentationIPCRequest& aRequest) {
+ if (sPresentationChild) {
+ PresentationRequestChild* actor = new PresentationRequestChild(aCallback);
+ Unused << NS_WARN_IF(
+ !sPresentationChild->SendPPresentationRequestConstructor(actor,
+ aRequest));
+ }
+}
+
+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, RefPtr{aListener});
+ return NS_OK;
+ }
+
+ mSessionListeners.Put(aSessionId, RefPtr{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, RefPtr{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, std::move(info));
+ } else {
+ mSessionInfoAtReceiver.Put(aSessionId, std::move(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) {
+ UpdateWindowIdBySessionIdInternal(aSessionId, aRole, aWindowId);
+ return NS_OK;
+}
+
+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) {
+ mAvailabilityManager.DoNotifyAvailableChange(aAvailabilityUrls, aAvailable);
+ return NS_OK;
+}
+
+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(
+ "dom::PresentationIPCService::UntrackSessionInfo",
+ [windowId]() -> void {
+ PRES_DEBUG("Attempt to close window[%" PRIu64 "]\n", windowId);
+
+ if (auto* window =
+ nsGlobalWindowInner::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);
+}
+
+} // namespace dom
+} // namespace mozilla
diff --git a/dom/presentation/ipc/PresentationIPCService.h b/dom/presentation/ipc/PresentationIPCService.h
new file mode 100644
index 0000000000..9b80209a52
--- /dev/null
+++ b/dom/presentation/ipc/PresentationIPCService.h
@@ -0,0 +1,71 @@
+/* -*- 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_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();
+ void 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 0000000000..8d643bd8b3
--- /dev/null
+++ b/dom/presentation/ipc/PresentationParent.cpp
@@ -0,0 +1,497 @@
+/* -*- 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/. */
+
+#include "DCPresentationChannelDescription.h"
+#include "mozilla/dom/BrowserParent.h"
+#include "mozilla/dom/ContentProcessManager.h"
+#include "mozilla/dom/Element.h"
+#include "mozilla/ipc/InputStreamUtils.h"
+#include "mozilla/Unused.h"
+#include "nsComponentManagerUtils.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() = default;
+
+/* virtual */ PresentationParent::~PresentationParent() = default;
+
+bool PresentationParent::Init(ContentParentId aContentParentId) {
+ MOZ_ASSERT(!mService);
+ mService = do_GetService(PRESENTATION_SERVICE_CONTRACTID);
+ mChildId = aContentParentId;
+ return !NS_WARN_IF(!mService);
+}
+
+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;
+}
+
+mozilla::ipc::IPCResult 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");
+ }
+
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ return IPC_OK();
+}
+
+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) {
+ MOZ_ASSERT_UNREACHABLE(
+ "We should never be manually allocating "
+ "AllocPPresentationBuilderParent actors");
+ return nullptr;
+}
+
+bool PresentationParent::DeallocPPresentationBuilderParent(
+ PPresentationBuilderParent* aActor) {
+ return true;
+}
+
+mozilla::ipc::IPCResult PresentationParent::Recv__delete__() {
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult PresentationParent::RecvRegisterAvailabilityHandler(
+ nsTArray<nsString>&& aAvailabilityUrls) {
+ MOZ_ASSERT(mService);
+
+ Unused << NS_WARN_IF(NS_FAILED(
+ mService->RegisterAvailabilityListener(aAvailabilityUrls, this)));
+ mContentAvailabilityUrls.AppendElements(aAvailabilityUrls);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult 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 IPC_OK();
+}
+
+/* virtual */ mozilla::ipc::IPCResult
+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 IPC_OK();
+ }
+
+ if (nsIPresentationService::ROLE_CONTROLLER == aRole) {
+ mSessionIdsAtController.AppendElement(aSessionId);
+ } else {
+ mSessionIdsAtReceiver.AppendElement(aSessionId);
+ }
+ Unused << NS_WARN_IF(
+ NS_FAILED(mService->RegisterSessionListener(aSessionId, aRole, this)));
+ return IPC_OK();
+}
+
+/* virtual */ mozilla::ipc::IPCResult
+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 IPC_OK();
+}
+
+/* virtual */ mozilla::ipc::IPCResult
+PresentationParent::RecvRegisterRespondingHandler(const uint64_t& aWindowId) {
+ MOZ_ASSERT(mService);
+
+ mWindowIds.AppendElement(aWindowId);
+ Unused << NS_WARN_IF(
+ NS_FAILED(mService->RegisterRespondingListener(aWindowId, this)));
+ return IPC_OK();
+}
+
+/* virtual */ mozilla::ipc::IPCResult
+PresentationParent::RecvUnregisterRespondingHandler(const uint64_t& aWindowId) {
+ MOZ_ASSERT(mService);
+ mWindowIds.RemoveElement(aWindowId);
+ Unused << NS_WARN_IF(
+ NS_FAILED(mService->UnregisterRespondingListener(aWindowId)));
+ return IPC_OK();
+}
+
+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;
+}
+
+mozilla::ipc::IPCResult 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 IPC_OK();
+}
+
+mozilla::ipc::IPCResult 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 IPC_OK();
+}
+
+/*
+ * Implementation of PresentationRequestParent
+ */
+
+NS_IMPL_ISUPPORTS(PresentationRequestParent, nsIPresentationServiceCallback)
+
+PresentationRequestParent::PresentationRequestParent(
+ nsIPresentationService* aService, ContentParentId aContentParentId)
+ : mService(aService), mChildId(aContentParentId) {}
+
+PresentationRequestParent::~PresentationRequestParent() = default;
+
+void PresentationRequestParent::ActorDestroy(ActorDestroyReason aWhy) {
+ mActorDestroyed = true;
+ mService = nullptr;
+}
+
+nsresult PresentationRequestParent::DoRequest(
+ const StartSessionRequest& aRequest) {
+ MOZ_ASSERT(mService);
+
+ mSessionId = aRequest.sessionId();
+
+ RefPtr<EventTarget> eventTarget;
+ ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
+ RefPtr<BrowserParent> tp = cpm->GetTopLevelBrowserParentByProcessAndTabId(
+ mChildId, aRequest.tabId());
+ if (tp) {
+ eventTarget = 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 0000000000..c50d374923
--- /dev/null
+++ b/dom/presentation/ipc/PresentationParent.h
@@ -0,0 +1,133 @@
+/* -*- 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_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"
+
+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 mozilla::ipc::IPCResult RecvPPresentationRequestConstructor(
+ PPresentationRequestParent* aActor,
+ const PresentationIPCRequest& aRequest) override;
+
+ PPresentationRequestParent* AllocPPresentationRequestParent(
+ const PresentationIPCRequest& aRequest);
+
+ bool DeallocPPresentationRequestParent(PPresentationRequestParent* aActor);
+
+ PPresentationBuilderParent* AllocPPresentationBuilderParent(
+ const nsString& aSessionId, const uint8_t& aRole);
+
+ bool DeallocPPresentationBuilderParent(PPresentationBuilderParent* aActor);
+
+ virtual mozilla::ipc::IPCResult Recv__delete__() override;
+
+ mozilla::ipc::IPCResult RecvRegisterAvailabilityHandler(
+ nsTArray<nsString>&& aAvailabilityUrls);
+
+ mozilla::ipc::IPCResult RecvUnregisterAvailabilityHandler(
+ nsTArray<nsString>&& aAvailabilityUrls);
+
+ mozilla::ipc::IPCResult RecvRegisterSessionHandler(const nsString& aSessionId,
+ const uint8_t& aRole);
+
+ mozilla::ipc::IPCResult RecvUnregisterSessionHandler(
+ const nsString& aSessionId, const uint8_t& aRole);
+
+ mozilla::ipc::IPCResult RecvRegisterRespondingHandler(
+ const uint64_t& aWindowId);
+
+ mozilla::ipc::IPCResult RecvUnregisterRespondingHandler(
+ const uint64_t& aWindowId);
+
+ mozilla::ipc::IPCResult RecvNotifyReceiverReady(const nsString& aSessionId,
+ const uint64_t& aWindowId,
+ const bool& aIsLoading);
+
+ mozilla::ipc::IPCResult RecvNotifyTransportClosed(const nsString& aSessionId,
+ const uint8_t& aRole,
+ const nsresult& aReason);
+
+ 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__