summaryrefslogtreecommitdiffstats
path: root/dom/presentation/ipc
diff options
context:
space:
mode:
Diffstat (limited to 'dom/presentation/ipc')
-rw-r--r--dom/presentation/ipc/PPresentation.ipdl112
-rw-r--r--dom/presentation/ipc/PPresentationBuilder.ipdl34
-rw-r--r--dom/presentation/ipc/PPresentationRequest.ipdl22
-rw-r--r--dom/presentation/ipc/PresentationBuilderChild.cpp184
-rw-r--r--dom/presentation/ipc/PresentationBuilderChild.h48
-rw-r--r--dom/presentation/ipc/PresentationBuilderParent.cpp267
-rw-r--r--dom/presentation/ipc/PresentationBuilderParent.h52
-rw-r--r--dom/presentation/ipc/PresentationChild.cpp198
-rw-r--r--dom/presentation/ipc/PresentationChild.h101
-rw-r--r--dom/presentation/ipc/PresentationContentSessionInfo.cpp109
-rw-r--r--dom/presentation/ipc/PresentationContentSessionInfo.h62
-rw-r--r--dom/presentation/ipc/PresentationIPCService.cpp538
-rw-r--r--dom/presentation/ipc/PresentationIPCService.h75
-rw-r--r--dom/presentation/ipc/PresentationParent.cpp553
-rw-r--r--dom/presentation/ipc/PresentationParent.h137
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__