LCOV - code coverage report
Current view: top level - dom/presentation - PresentationSessionInfo.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 611 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 81 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim:set ts=2 sw=2 sts=2 et cindent: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/dom/ContentParent.h"
       8             : #include "mozilla/dom/HTMLIFrameElementBinding.h"
       9             : #include "mozilla/dom/TabParent.h"
      10             : #include "mozilla/Logging.h"
      11             : #include "mozilla/Move.h"
      12             : #include "mozilla/Preferences.h"
      13             : #include "mozilla/Services.h"
      14             : #include "nsContentUtils.h"
      15             : #include "nsGlobalWindow.h"
      16             : #include "nsIDocShell.h"
      17             : #include "nsFrameLoader.h"
      18             : #include "nsIMutableArray.h"
      19             : #include "nsINetAddr.h"
      20             : #include "nsISocketTransport.h"
      21             : #include "nsISupportsPrimitives.h"
      22             : #include "nsNetCID.h"
      23             : #include "nsServiceManagerUtils.h"
      24             : #include "nsThreadUtils.h"
      25             : #include "PresentationLog.h"
      26             : #include "PresentationService.h"
      27             : #include "PresentationSessionInfo.h"
      28             : 
      29             : #ifdef MOZ_WIDGET_ANDROID
      30             : #include "nsIPresentationNetworkHelper.h"
      31             : #endif // MOZ_WIDGET_ANDROID
      32             : 
      33             : #ifdef MOZ_WIDGET_GONK
      34             : #include "nsINetworkInterface.h"
      35             : #include "nsINetworkManager.h"
      36             : #endif
      37             : 
      38             : using namespace mozilla;
      39             : using namespace mozilla::dom;
      40             : using namespace mozilla::services;
      41             : 
      42             : /*
      43             :  * Implementation of PresentationChannelDescription
      44             :  */
      45             : 
      46             : namespace mozilla {
      47             : namespace dom {
      48             : 
      49             : #ifdef MOZ_WIDGET_ANDROID
      50             : 
      51             : namespace {
      52             : 
      53             : class PresentationNetworkHelper final : public nsIPresentationNetworkHelperListener
      54             : {
      55             : public:
      56             :   NS_DECL_ISUPPORTS
      57             :   NS_DECL_NSIPRESENTATIONNETWORKHELPERLISTENER
      58             : 
      59             :   using Function = nsresult(PresentationControllingInfo::*)(const nsACString&);
      60             : 
      61             :   explicit PresentationNetworkHelper(PresentationControllingInfo* aInfo,
      62             :                                      const Function& aFunc);
      63             : 
      64             :   nsresult GetWifiIPAddress();
      65             : 
      66             : private:
      67             :   ~PresentationNetworkHelper() = default;
      68             : 
      69             :   RefPtr<PresentationControllingInfo> mInfo;
      70             :   Function mFunc;
      71             : };
      72             : 
      73             : NS_IMPL_ISUPPORTS(PresentationNetworkHelper,
      74             :                   nsIPresentationNetworkHelperListener)
      75             : 
      76             : PresentationNetworkHelper::PresentationNetworkHelper(PresentationControllingInfo* aInfo,
      77             :                                                      const Function& aFunc)
      78             :   : mInfo(aInfo)
      79             :   , mFunc(aFunc)
      80             : {
      81             :   MOZ_ASSERT(aInfo);
      82             :   MOZ_ASSERT(aFunc);
      83             : }
      84             : 
      85             : nsresult
      86             : PresentationNetworkHelper::GetWifiIPAddress()
      87             : {
      88             :   nsresult rv;
      89             : 
      90             :   nsCOMPtr<nsIPresentationNetworkHelper> networkHelper =
      91             :     do_GetService(PRESENTATION_NETWORK_HELPER_CONTRACTID, &rv);
      92             :   if (NS_WARN_IF(NS_FAILED(rv))) {
      93             :     return rv;
      94             :   }
      95             : 
      96             :   return networkHelper->GetWifiIPAddress(this);
      97             : }
      98             : 
      99             : NS_IMETHODIMP
     100             : PresentationNetworkHelper::OnError(const nsACString & aReason)
     101             : {
     102             :   PRES_ERROR("PresentationNetworkHelper::OnError: %s",
     103             :     nsPromiseFlatCString(aReason).get());
     104             :   return NS_OK;
     105             : }
     106             : 
     107             : NS_IMETHODIMP
     108             : PresentationNetworkHelper::OnGetWifiIPAddress(const nsACString& aIPAddress)
     109             : {
     110             :   MOZ_ASSERT(mInfo);
     111             :   MOZ_ASSERT(mFunc);
     112             : 
     113             :   NS_DispatchToMainThread(
     114             :     NewRunnableMethod<nsCString>("dom::PresentationNetworkHelper::OnGetWifiIPAddress",
     115             :                                  mInfo,
     116             :                                  mFunc,
     117             :                                  aIPAddress));
     118             :   return NS_OK;
     119             : }
     120             : 
     121             : } // anonymous namespace
     122             : 
     123             : #endif // MOZ_WIDGET_ANDROID
     124             : 
     125             : class TCPPresentationChannelDescription final : public nsIPresentationChannelDescription
     126             : {
     127             : public:
     128             :   NS_DECL_ISUPPORTS
     129             :   NS_DECL_NSIPRESENTATIONCHANNELDESCRIPTION
     130             : 
     131           0 :   TCPPresentationChannelDescription(const nsACString& aAddress,
     132             :                                     uint16_t aPort)
     133           0 :     : mAddress(aAddress)
     134           0 :     , mPort(aPort)
     135             :   {
     136           0 :   }
     137             : 
     138             : private:
     139           0 :   ~TCPPresentationChannelDescription() {}
     140             : 
     141             :   nsCString mAddress;
     142             :   uint16_t mPort;
     143             : };
     144             : 
     145             : } // namespace dom
     146             : } // namespace mozilla
     147             : 
     148           0 : NS_IMPL_ISUPPORTS(TCPPresentationChannelDescription, nsIPresentationChannelDescription)
     149             : 
     150             : NS_IMETHODIMP
     151           0 : TCPPresentationChannelDescription::GetType(uint8_t* aRetVal)
     152             : {
     153           0 :   if (NS_WARN_IF(!aRetVal)) {
     154           0 :     return NS_ERROR_INVALID_POINTER;
     155             :   }
     156             : 
     157           0 :   *aRetVal = nsIPresentationChannelDescription::TYPE_TCP;
     158           0 :   return NS_OK;
     159             : }
     160             : 
     161             : NS_IMETHODIMP
     162           0 : TCPPresentationChannelDescription::GetTcpAddress(nsIArray** aRetVal)
     163             : {
     164           0 :   if (NS_WARN_IF(!aRetVal)) {
     165           0 :     return NS_ERROR_INVALID_POINTER;
     166             :   }
     167             : 
     168           0 :   nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID);
     169           0 :   if (NS_WARN_IF(!array)) {
     170           0 :     return NS_ERROR_OUT_OF_MEMORY;
     171             :   }
     172             : 
     173             :   // TODO bug 1228504 Take all IP addresses in PresentationChannelDescription
     174             :   // into account. And at the first stage Presentation API is only exposed on
     175             :   // Firefox OS where the first IP appears enough for most scenarios.
     176           0 :   nsCOMPtr<nsISupportsCString> address = do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
     177           0 :   if (NS_WARN_IF(!address)) {
     178           0 :     return NS_ERROR_OUT_OF_MEMORY;
     179             :   }
     180           0 :   address->SetData(mAddress);
     181             : 
     182           0 :   array->AppendElement(address, false);
     183           0 :   array.forget(aRetVal);
     184             : 
     185           0 :   return NS_OK;
     186             : }
     187             : 
     188             : NS_IMETHODIMP
     189           0 : TCPPresentationChannelDescription::GetTcpPort(uint16_t* aRetVal)
     190             : {
     191           0 :   if (NS_WARN_IF(!aRetVal)) {
     192           0 :     return NS_ERROR_INVALID_POINTER;
     193             :   }
     194             : 
     195           0 :   *aRetVal = mPort;
     196           0 :   return NS_OK;
     197             : }
     198             : 
     199             : NS_IMETHODIMP
     200           0 : TCPPresentationChannelDescription::GetDataChannelSDP(nsAString& aDataChannelSDP)
     201             : {
     202           0 :   aDataChannelSDP.Truncate();
     203           0 :   return NS_OK;
     204             : }
     205             : 
     206             : /*
     207             :  * Implementation of PresentationSessionInfo
     208             :  */
     209             : 
     210           0 : NS_IMPL_ISUPPORTS(PresentationSessionInfo,
     211             :                   nsIPresentationSessionTransportCallback,
     212             :                   nsIPresentationControlChannelListener,
     213             :                   nsIPresentationSessionTransportBuilderListener);
     214             : 
     215             : /* virtual */ nsresult
     216           0 : PresentationSessionInfo::Init(nsIPresentationControlChannel* aControlChannel)
     217             : {
     218           0 :   SetControlChannel(aControlChannel);
     219           0 :   return NS_OK;
     220             : }
     221             : 
     222             : /* virtual */ void
     223           0 : PresentationSessionInfo::Shutdown(nsresult aReason)
     224             : {
     225           0 :   PRES_DEBUG("%s:id[%s], reason[%" PRIx32 "], role[%d]\n", __func__,
     226             :              NS_ConvertUTF16toUTF8(mSessionId).get(), static_cast<uint32_t>(aReason),
     227             :              mRole);
     228             : 
     229           0 :   NS_WARNING_ASSERTION(NS_SUCCEEDED(aReason), "bad reason");
     230             : 
     231             :   // Close the control channel if any.
     232           0 :   if (mControlChannel) {
     233           0 :     Unused << NS_WARN_IF(NS_FAILED(mControlChannel->Disconnect(aReason)));
     234             :   }
     235             : 
     236             :   // Close the data transport channel if any.
     237           0 :   if (mTransport) {
     238             :     // |mIsTransportReady| will be unset once |NotifyTransportClosed| is called.
     239           0 :     Unused << NS_WARN_IF(NS_FAILED(mTransport->Close(aReason)));
     240             :   }
     241             : 
     242           0 :   mIsResponderReady = false;
     243           0 :   mIsOnTerminating = false;
     244             : 
     245           0 :   ResetBuilder();
     246           0 : }
     247             : 
     248             : nsresult
     249           0 : PresentationSessionInfo::SetListener(nsIPresentationSessionListener* aListener)
     250             : {
     251           0 :   mListener = aListener;
     252             : 
     253           0 :   if (mListener) {
     254             :     // Enable data notification for the transport channel if it's available.
     255           0 :     if (mTransport) {
     256           0 :       nsresult rv = mTransport->EnableDataNotification();
     257           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
     258           0 :         return rv;
     259             :       }
     260             :     }
     261             : 
     262             :     // The transport might become ready, or might become un-ready again, before
     263             :     // the listener has registered. So notify the listener of the state change.
     264           0 :     return mListener->NotifyStateChange(mSessionId, mState, mReason);
     265             :   }
     266             : 
     267           0 :   return NS_OK;
     268             : }
     269             : 
     270             : nsresult
     271           0 : PresentationSessionInfo::Send(const nsAString& aData)
     272             : {
     273           0 :   if (NS_WARN_IF(!IsSessionReady())) {
     274           0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
     275             :   }
     276             : 
     277           0 :   if (NS_WARN_IF(!mTransport)) {
     278           0 :     return NS_ERROR_NOT_AVAILABLE;
     279             :   }
     280             : 
     281           0 :   return mTransport->Send(aData);
     282             : }
     283             : 
     284             : nsresult
     285           0 : PresentationSessionInfo::SendBinaryMsg(const nsACString& aData)
     286             : {
     287           0 :   if (NS_WARN_IF(!IsSessionReady())) {
     288           0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
     289             :   }
     290             : 
     291           0 :   if (NS_WARN_IF(!mTransport)) {
     292           0 :     return NS_ERROR_NOT_AVAILABLE;
     293             :   }
     294             : 
     295           0 :   return mTransport->SendBinaryMsg(aData);
     296             : }
     297             : 
     298             : nsresult
     299           0 : PresentationSessionInfo::SendBlob(nsIDOMBlob* aBlob)
     300             : {
     301           0 :   if (NS_WARN_IF(!IsSessionReady())) {
     302           0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
     303             :   }
     304             : 
     305           0 :   if (NS_WARN_IF(!mTransport)) {
     306           0 :     return NS_ERROR_NOT_AVAILABLE;
     307             :   }
     308             : 
     309           0 :   return mTransport->SendBlob(aBlob);
     310             : }
     311             : 
     312             : nsresult
     313           0 : PresentationSessionInfo::Close(nsresult aReason,
     314             :                                uint32_t aState)
     315             : {
     316             :   // Do nothing if session is already terminated.
     317           0 :   if (nsIPresentationSessionListener::STATE_TERMINATED == mState) {
     318           0 :     return NS_OK;
     319             :   }
     320             : 
     321           0 :   SetStateWithReason(aState, aReason);
     322             : 
     323           0 :   switch (aState) {
     324             :     case nsIPresentationSessionListener::STATE_CLOSED: {
     325           0 :       Shutdown(aReason);
     326           0 :       break;
     327             :     }
     328             :     case nsIPresentationSessionListener::STATE_TERMINATED: {
     329           0 :       if (!mControlChannel) {
     330           0 :         nsCOMPtr<nsIPresentationControlChannel> ctrlChannel;
     331           0 :         nsresult rv = mDevice->EstablishControlChannel(getter_AddRefs(ctrlChannel));
     332           0 :         if (NS_FAILED(rv)) {
     333           0 :           Shutdown(rv);
     334           0 :           return rv;
     335             :         }
     336             : 
     337           0 :         SetControlChannel(ctrlChannel);
     338           0 :         return rv;
     339             :       }
     340             : 
     341           0 :       ContinueTermination();
     342           0 :       return NS_OK;
     343             :     }
     344             :   }
     345             : 
     346           0 :   return NS_OK;
     347             : }
     348             : 
     349             : nsresult
     350           0 : PresentationSessionInfo::OnTerminate(nsIPresentationControlChannel* aControlChannel)
     351             : {
     352           0 :   mIsOnTerminating = true; // Mark for terminating transport channel
     353           0 :   SetStateWithReason(nsIPresentationSessionListener::STATE_TERMINATED, NS_OK);
     354           0 :   SetControlChannel(aControlChannel);
     355             : 
     356           0 :   return NS_OK;
     357             : }
     358             : 
     359             : nsresult
     360           0 : PresentationSessionInfo::ReplySuccess()
     361             : {
     362           0 :   SetStateWithReason(nsIPresentationSessionListener::STATE_CONNECTED, NS_OK);
     363           0 :   return NS_OK;
     364             : }
     365             : 
     366             : nsresult
     367           0 : PresentationSessionInfo::ReplyError(nsresult aError)
     368             : {
     369           0 :   Shutdown(aError);
     370             : 
     371             :   // Remove itself since it never succeeds.
     372           0 :   return UntrackFromService();
     373             : }
     374             : 
     375             : /* virtual */ nsresult
     376           0 : PresentationSessionInfo::UntrackFromService()
     377             : {
     378             :   nsCOMPtr<nsIPresentationService> service =
     379           0 :     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
     380           0 :   if (NS_WARN_IF(!service)) {
     381           0 :     return NS_ERROR_NOT_AVAILABLE;
     382             :   }
     383           0 :   static_cast<PresentationService*>(service.get())->UntrackSessionInfo(mSessionId, mRole);
     384             : 
     385           0 :   return NS_OK;
     386             : }
     387             : 
     388             : nsPIDOMWindowInner*
     389           0 : PresentationSessionInfo::GetWindow()
     390             : {
     391             :   nsCOMPtr<nsIPresentationService> service =
     392           0 :   do_GetService(PRESENTATION_SERVICE_CONTRACTID);
     393           0 :   if (NS_WARN_IF(!service)) {
     394           0 :     return nullptr;
     395             :   }
     396           0 :   uint64_t windowId = 0;
     397           0 :   if (NS_WARN_IF(NS_FAILED(service->GetWindowIdBySessionId(mSessionId,
     398             :                                                            mRole,
     399             :                                                            &windowId)))) {
     400           0 :     return nullptr;
     401             :   }
     402             : 
     403           0 :   auto window = nsGlobalWindow::GetInnerWindowWithId(windowId);
     404           0 :   if (!window) {
     405           0 :     return nullptr;
     406             :   }
     407             : 
     408           0 :   return window->AsInner();
     409             : }
     410             : 
     411             : /* virtual */ bool
     412           0 : PresentationSessionInfo::IsAccessible(base::ProcessId aProcessId)
     413             : {
     414             :   // No restriction by default.
     415           0 :   return true;
     416             : }
     417             : 
     418             : void
     419           0 : PresentationSessionInfo::ContinueTermination()
     420             : {
     421           0 :   MOZ_ASSERT(NS_IsMainThread());
     422           0 :   MOZ_ASSERT(mControlChannel);
     423             : 
     424           0 :   if (NS_WARN_IF(NS_FAILED(mControlChannel->Terminate(mSessionId)))
     425           0 :       || mIsOnTerminating) {
     426           0 :     Shutdown(NS_OK);
     427             :   }
     428           0 : }
     429             : 
     430             : // nsIPresentationSessionTransportCallback
     431             : NS_IMETHODIMP
     432           0 : PresentationSessionInfo::NotifyTransportReady()
     433             : {
     434           0 :   PRES_DEBUG("%s:id[%s], role[%d], state[%d]\n", __func__,
     435             :              NS_ConvertUTF16toUTF8(mSessionId).get(), mRole, mState);
     436             : 
     437           0 :   MOZ_ASSERT(NS_IsMainThread());
     438             : 
     439           0 :   if (mState != nsIPresentationSessionListener::STATE_CONNECTING &&
     440           0 :       mState != nsIPresentationSessionListener::STATE_CONNECTED) {
     441           0 :     return NS_OK;
     442             :   }
     443             : 
     444           0 :   mIsTransportReady = true;
     445             : 
     446             :   // Established RTCDataChannel implies responder is ready.
     447           0 :   if (mTransportType == nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
     448           0 :     mIsResponderReady = true;
     449             :   }
     450             : 
     451             :   // At sender side, session might not be ready at this point (waiting for
     452             :   // receiver's answer). Yet at receiver side, session must be ready at this
     453             :   // point since the data transport channel is created after the receiver page
     454             :   // is ready for presentation use.
     455           0 :   if (IsSessionReady()) {
     456           0 :     return ReplySuccess();
     457             :   }
     458             : 
     459           0 :   return NS_OK;
     460             : }
     461             : 
     462             : NS_IMETHODIMP
     463           0 : PresentationSessionInfo::NotifyTransportClosed(nsresult aReason)
     464             : {
     465           0 :   PRES_DEBUG("%s:id[%s], reason[%" PRIx32 "], role[%d]\n", __func__,
     466             :              NS_ConvertUTF16toUTF8(mSessionId).get(), static_cast<uint32_t>(aReason),
     467             :              mRole);
     468             : 
     469           0 :   MOZ_ASSERT(NS_IsMainThread());
     470             : 
     471             :   // Nullify |mTransport| here so it won't try to re-close |mTransport| in
     472             :   // potential subsequent |Shutdown| calls.
     473           0 :   mTransport = nullptr;
     474             : 
     475           0 :   if (NS_WARN_IF(!IsSessionReady() &&
     476             :                  mState == nsIPresentationSessionListener::STATE_CONNECTING)) {
     477             :     // It happens before the session is ready. Reply the callback.
     478           0 :     return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
     479             :   }
     480             : 
     481             :   // Unset |mIsTransportReady| here so it won't affect |IsSessionReady()| above.
     482           0 :   mIsTransportReady = false;
     483             : 
     484           0 :   if (mState == nsIPresentationSessionListener::STATE_CONNECTED) {
     485             :     // The transport channel is closed unexpectedly (not caused by a |Close| call).
     486           0 :     SetStateWithReason(nsIPresentationSessionListener::STATE_CLOSED, aReason);
     487             :   }
     488             : 
     489           0 :   Shutdown(aReason);
     490             : 
     491           0 :   if (mState == nsIPresentationSessionListener::STATE_TERMINATED) {
     492             :     // Directly untrack the session info from the service.
     493           0 :     return UntrackFromService();
     494             :   }
     495             : 
     496           0 :   return NS_OK;
     497             : }
     498             : 
     499             : NS_IMETHODIMP
     500           0 : PresentationSessionInfo::NotifyData(const nsACString& aData, bool aIsBinary)
     501             : {
     502           0 :   MOZ_ASSERT(NS_IsMainThread());
     503             : 
     504           0 :   if (NS_WARN_IF(!IsSessionReady())) {
     505           0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
     506             :   }
     507             : 
     508           0 :   if (NS_WARN_IF(!mListener)) {
     509           0 :     return NS_ERROR_NOT_AVAILABLE;
     510             :   }
     511             : 
     512           0 :   return mListener->NotifyMessage(mSessionId, aData, aIsBinary);
     513             : }
     514             : 
     515             : // nsIPresentationSessionTransportBuilderListener
     516             : NS_IMETHODIMP
     517           0 : PresentationSessionInfo::OnSessionTransport(nsIPresentationSessionTransport* aTransport)
     518             : {
     519           0 :   PRES_DEBUG("%s:id[%s], role[%d], state[%d]\n", __func__,
     520             :              NS_ConvertUTF16toUTF8(mSessionId).get(), mRole, mState);
     521             : 
     522           0 :   ResetBuilder();
     523             : 
     524           0 :   if (mState != nsIPresentationSessionListener::STATE_CONNECTING) {
     525           0 :     return NS_ERROR_FAILURE;
     526             :   }
     527             : 
     528           0 :   if (NS_WARN_IF(!aTransport)) {
     529           0 :     return NS_ERROR_INVALID_ARG;
     530             :   }
     531             : 
     532           0 :   mTransport = aTransport;
     533             : 
     534           0 :   nsresult rv = mTransport->SetCallback(this);
     535           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     536           0 :     return rv;
     537             :   }
     538             : 
     539           0 :   if (mListener) {
     540           0 :     mTransport->EnableDataNotification();
     541             :   }
     542             : 
     543           0 :   return NS_OK;
     544             : }
     545             : 
     546             : NS_IMETHODIMP
     547           0 : PresentationSessionInfo::OnError(nsresult aReason)
     548             : {
     549           0 :   PRES_DEBUG("%s:id[%s], reason[%" PRIx32 "], role[%d]\n", __func__,
     550             :              NS_ConvertUTF16toUTF8(mSessionId).get(), static_cast<uint32_t>(aReason),
     551             :              mRole);
     552             : 
     553           0 :   ResetBuilder();
     554           0 :   return ReplyError(aReason);
     555             : }
     556             : 
     557             : NS_IMETHODIMP
     558           0 : PresentationSessionInfo::SendOffer(nsIPresentationChannelDescription* aOffer)
     559             : {
     560           0 :   return mControlChannel->SendOffer(aOffer);
     561             : }
     562             : 
     563             : NS_IMETHODIMP
     564           0 : PresentationSessionInfo::SendAnswer(nsIPresentationChannelDescription* aAnswer)
     565             : {
     566           0 :   return mControlChannel->SendAnswer(aAnswer);
     567             : }
     568             : 
     569             : NS_IMETHODIMP
     570           0 : PresentationSessionInfo::SendIceCandidate(const nsAString& candidate)
     571             : {
     572           0 :   return mControlChannel->SendIceCandidate(candidate);
     573             : }
     574             : 
     575             : NS_IMETHODIMP
     576           0 : PresentationSessionInfo::Close(nsresult reason)
     577             : {
     578           0 :   return mControlChannel->Disconnect(reason);
     579             : }
     580             : 
     581             : /**
     582             :  * Implementation of PresentationControllingInfo
     583             :  *
     584             :  * During presentation session establishment, the sender expects the following
     585             :  * after trying to establish the control channel: (The order between step 3 and
     586             :  * 4 is not guaranteed.)
     587             :  * 1. |Init| is called to open a socket |mServerSocket| for data transport
     588             :  *    channel.
     589             :  * 2. |NotifyConnected| of |nsIPresentationControlChannelListener| is called to
     590             :  *    indicate the control channel is ready to use. Then send the offer to the
     591             :  *    receiver via the control channel.
     592             :  * 3.1 |OnSocketAccepted| of |nsIServerSocketListener| is called to indicate the
     593             :  *     data transport channel is connected. Then initialize |mTransport|.
     594             :  * 3.2 |NotifyTransportReady| of |nsIPresentationSessionTransportCallback| is
     595             :  *     called.
     596             :  * 4. |OnAnswer| of |nsIPresentationControlChannelListener| is called to
     597             :  *    indicate the receiver is ready. Close the control channel since it's no
     598             :  *    longer needed.
     599             :  * 5. Once both step 3 and 4 are done, the presentation session is ready to use.
     600             :  *    So notify the listener of CONNECTED state.
     601             :  */
     602             : 
     603           0 : NS_IMPL_ISUPPORTS_INHERITED(PresentationControllingInfo,
     604             :                             PresentationSessionInfo,
     605             :                             nsIServerSocketListener)
     606             : 
     607             : nsresult
     608           0 : PresentationControllingInfo::Init(nsIPresentationControlChannel* aControlChannel)
     609             : {
     610           0 :   PresentationSessionInfo::Init(aControlChannel);
     611             : 
     612             :   // Initialize |mServerSocket| for bootstrapping the data transport channel and
     613             :   // use |this| as the listener.
     614           0 :   mServerSocket = do_CreateInstance(NS_SERVERSOCKET_CONTRACTID);
     615           0 :   if (NS_WARN_IF(!mServerSocket)) {
     616           0 :     return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
     617             :   }
     618             : 
     619           0 :   nsresult rv = mServerSocket->Init(-1, false, -1);
     620           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     621           0 :     return rv;
     622             :   }
     623             : 
     624           0 :   rv = mServerSocket->AsyncListen(this);
     625           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     626           0 :     return rv;
     627             :   }
     628             : 
     629             :   int32_t port;
     630           0 :   rv = mServerSocket->GetPort(&port);
     631           0 :   if (!NS_WARN_IF(NS_FAILED(rv))) {
     632           0 :     PRES_DEBUG("%s:ServerSocket created.port[%d]\n",__func__, port);
     633             :   }
     634             : 
     635           0 :   return NS_OK;
     636             : }
     637             : 
     638             : void
     639           0 : PresentationControllingInfo::Shutdown(nsresult aReason)
     640             : {
     641           0 :   PresentationSessionInfo::Shutdown(aReason);
     642             : 
     643             :   // Close the server socket if any.
     644           0 :   if (mServerSocket) {
     645           0 :     Unused << NS_WARN_IF(NS_FAILED(mServerSocket->Close()));
     646           0 :     mServerSocket = nullptr;
     647             :   }
     648           0 : }
     649             : 
     650             : nsresult
     651           0 : PresentationControllingInfo::GetAddress()
     652             : {
     653             : #if defined(MOZ_WIDGET_GONK)
     654             :   nsCOMPtr<nsINetworkManager> networkManager =
     655             :     do_GetService("@mozilla.org/network/manager;1");
     656             :   if (NS_WARN_IF(!networkManager)) {
     657             :     return NS_ERROR_NOT_AVAILABLE;
     658             :   }
     659             : 
     660             :   nsCOMPtr<nsINetworkInfo> activeNetworkInfo;
     661             :   networkManager->GetActiveNetworkInfo(getter_AddRefs(activeNetworkInfo));
     662             :   if (NS_WARN_IF(!activeNetworkInfo)) {
     663             :     return NS_ERROR_FAILURE;
     664             :   }
     665             : 
     666             :   char16_t** ips = nullptr;
     667             :   uint32_t* prefixes = nullptr;
     668             :   uint32_t count = 0;
     669             :   activeNetworkInfo->GetAddresses(&ips, &prefixes, &count);
     670             :   if (NS_WARN_IF(!count)) {
     671             :     NS_Free(prefixes);
     672             :     NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, ips);
     673             :     return NS_ERROR_FAILURE;
     674             :   }
     675             : 
     676             :   // TODO bug 1228504 Take all IP addresses in PresentationChannelDescription
     677             :   // into account. And at the first stage Presentation API is only exposed on
     678             :   // Firefox OS where the first IP appears enough for most scenarios.
     679             : 
     680             :   nsAutoString ip;
     681             :   ip.Assign(ips[0]);
     682             : 
     683             :   // On Android platform, the IP address is retrieved from a callback function.
     684             :   // To make consistent code sequence, following function call is dispatched
     685             :   // into main thread instead of calling it directly.
     686             :   NS_DispatchToMainThread(
     687             :     NewRunnableMethod<nsCString>(
     688             :       "dom::PresentationControllingInfo::OnGetAddress",
     689             :       this,
     690             :       &PresentationControllingInfo::OnGetAddress,
     691             :       NS_ConvertUTF16toUTF8(ip)));
     692             : 
     693             :   NS_Free(prefixes);
     694             :   NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, ips);
     695             : 
     696             : #elif defined(MOZ_WIDGET_ANDROID)
     697             :   RefPtr<PresentationNetworkHelper> networkHelper =
     698             :     new PresentationNetworkHelper(this,
     699             :                                   &PresentationControllingInfo::OnGetAddress);
     700             :   nsresult rv = networkHelper->GetWifiIPAddress();
     701             :   if (NS_WARN_IF(NS_FAILED(rv))) {
     702             :     return rv;
     703             :   }
     704             : 
     705             : #else
     706           0 :   nsCOMPtr<nsINetworkInfoService> networkInfo = do_GetService(NETWORKINFOSERVICE_CONTRACT_ID);
     707           0 :   MOZ_ASSERT(networkInfo);
     708             : 
     709           0 :   nsresult rv = networkInfo->ListNetworkAddresses(this);
     710             : 
     711           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     712           0 :     return rv;
     713             :   }
     714             : #endif
     715             : 
     716           0 :   return NS_OK;
     717             : }
     718             : 
     719             : nsresult
     720           0 : PresentationControllingInfo::OnGetAddress(const nsACString& aAddress)
     721             : {
     722           0 :   MOZ_ASSERT(NS_IsMainThread());
     723             : 
     724           0 :   if (NS_WARN_IF(!mServerSocket)) {
     725           0 :     return NS_ERROR_FAILURE;
     726             :   }
     727           0 :   if (NS_WARN_IF(!mControlChannel)) {
     728           0 :     return NS_ERROR_FAILURE;
     729             :   }
     730             : 
     731             :   // Prepare and send the offer.
     732             :   int32_t port;
     733           0 :   nsresult rv = mServerSocket->GetPort(&port);
     734           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     735           0 :     return rv;
     736             :   }
     737             : 
     738             :   RefPtr<TCPPresentationChannelDescription> description =
     739           0 :     new TCPPresentationChannelDescription(aAddress, static_cast<uint16_t>(port));
     740           0 :   return mControlChannel->SendOffer(description);
     741             : }
     742             : 
     743             : // nsIPresentationControlChannelListener
     744             : NS_IMETHODIMP
     745           0 : PresentationControllingInfo::OnIceCandidate(const nsAString& aCandidate)
     746             : {
     747           0 :   if (mTransportType != nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
     748           0 :     return NS_ERROR_FAILURE;
     749             :   }
     750             : 
     751             :   nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder>
     752           0 :     builder = do_QueryInterface(mBuilder);
     753             : 
     754           0 :   if (NS_WARN_IF(!builder)) {
     755           0 :     return NS_ERROR_FAILURE;
     756             :   }
     757             : 
     758           0 :   return builder->OnIceCandidate(aCandidate);
     759             : }
     760             : 
     761             : NS_IMETHODIMP
     762           0 : PresentationControllingInfo::OnOffer(nsIPresentationChannelDescription* aDescription)
     763             : {
     764           0 :   MOZ_ASSERT(false, "Sender side should not receive offer.");
     765             :   return NS_ERROR_FAILURE;
     766             : }
     767             : 
     768             : NS_IMETHODIMP
     769           0 : PresentationControllingInfo::OnAnswer(nsIPresentationChannelDescription* aDescription)
     770             : {
     771           0 :   if (mTransportType == nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
     772             :     nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder>
     773           0 :       builder = do_QueryInterface(mBuilder);
     774             : 
     775           0 :     if (NS_WARN_IF(!builder)) {
     776           0 :       return NS_ERROR_FAILURE;
     777             :     }
     778             : 
     779           0 :     return builder->OnAnswer(aDescription);
     780             :   }
     781             : 
     782           0 :   mIsResponderReady = true;
     783             : 
     784             :   // Close the control channel since it's no longer needed.
     785           0 :   nsresult rv = mControlChannel->Disconnect(NS_OK);
     786           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     787           0 :     return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
     788             :   }
     789             : 
     790             :   // Session might not be ready at this moment (waiting for the establishment of
     791             :   // the data transport channel).
     792           0 :   if (IsSessionReady()){
     793           0 :     return ReplySuccess();
     794             :   }
     795             : 
     796           0 :   return NS_OK;
     797             : }
     798             : 
     799             : NS_IMETHODIMP
     800           0 : PresentationControllingInfo::NotifyConnected()
     801             : {
     802           0 :   PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
     803             :              NS_ConvertUTF16toUTF8(mSessionId).get(), mRole);
     804             : 
     805           0 :   MOZ_ASSERT(NS_IsMainThread());
     806             : 
     807           0 :   switch (mState) {
     808             :     case nsIPresentationSessionListener::STATE_CONNECTING: {
     809           0 :       if (mIsReconnecting) {
     810           0 :         return ContinueReconnect();
     811             :       }
     812             : 
     813           0 :       nsresult rv = mControlChannel->Launch(GetSessionId(), GetUrl());
     814           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
     815           0 :         return rv;
     816             :       }
     817           0 :       Unused << NS_WARN_IF(NS_FAILED(BuildTransport()));
     818           0 :       break;
     819             :     }
     820             :     case nsIPresentationSessionListener::STATE_TERMINATED: {
     821           0 :       ContinueTermination();
     822           0 :       break;
     823             :     }
     824             :     default:
     825           0 :       break;
     826             :   }
     827             : 
     828           0 :   return NS_OK;
     829             : }
     830             : 
     831             : NS_IMETHODIMP
     832           0 : PresentationControllingInfo::NotifyReconnected()
     833             : {
     834           0 :   PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
     835             :              NS_ConvertUTF16toUTF8(mSessionId).get(), mRole);
     836             : 
     837           0 :   MOZ_ASSERT(NS_IsMainThread());
     838             : 
     839           0 :   if (NS_WARN_IF(mState != nsIPresentationSessionListener::STATE_CONNECTING)) {
     840           0 :     return NS_ERROR_FAILURE;
     841             :   }
     842             : 
     843           0 :   return NotifyReconnectResult(NS_OK);
     844             : }
     845             : 
     846             : nsresult
     847           0 : PresentationControllingInfo::BuildTransport()
     848             : {
     849           0 :   MOZ_ASSERT(NS_IsMainThread());
     850             : 
     851           0 :   if (mState != nsIPresentationSessionListener::STATE_CONNECTING) {
     852           0 :     return NS_OK;
     853             :   }
     854             : 
     855           0 :   if (NS_WARN_IF(!mBuilderConstructor)) {
     856           0 :     return NS_ERROR_NOT_AVAILABLE;
     857             :   }
     858             : 
     859           0 :   if (!Preferences::GetBool("dom.presentation.session_transport.data_channel.enable")) {
     860             :     // Build TCP session transport
     861           0 :     return GetAddress();
     862             :   }
     863             :   /**
     864             :    * Generally transport is maintained by the chrome process. However, data
     865             :    * channel should be live with the DOM , which implies RTCDataChannel in an OOP
     866             :    * page should be establish in the content process.
     867             :    *
     868             :    * |mBuilderConstructor| is responsible for creating a builder, which is for
     869             :    * building a data channel transport.
     870             :    *
     871             :    * In the OOP case, |mBuilderConstructor| would create a builder which is
     872             :    * an object of |PresentationBuilderParent|. So, |BuildDataChannelTransport|
     873             :    * triggers an IPC call to make content process establish a RTCDataChannel
     874             :    * transport.
     875             :    */
     876             : 
     877           0 :   mTransportType = nsIPresentationChannelDescription::TYPE_DATACHANNEL;
     878           0 :   if (NS_WARN_IF(NS_FAILED(
     879             :     mBuilderConstructor->CreateTransportBuilder(mTransportType,
     880             :                                                 getter_AddRefs(mBuilder))))) {
     881           0 :     return NS_ERROR_NOT_AVAILABLE;
     882             :   }
     883             : 
     884             :   nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder>
     885           0 :     dataChannelBuilder(do_QueryInterface(mBuilder));
     886           0 :   if (NS_WARN_IF(!dataChannelBuilder)) {
     887           0 :     return NS_ERROR_NOT_AVAILABLE;
     888             :   }
     889             : 
     890             :   // OOP window would be set from content process
     891           0 :   nsPIDOMWindowInner* window = GetWindow();
     892             : 
     893           0 :   nsresult rv = dataChannelBuilder->
     894           0 :          BuildDataChannelTransport(nsIPresentationService::ROLE_CONTROLLER,
     895             :                                    window,
     896           0 :                                    this);
     897           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     898           0 :     return rv;
     899             :   }
     900             : 
     901           0 :   return NS_OK;
     902             : }
     903             : 
     904             : NS_IMETHODIMP
     905           0 : PresentationControllingInfo::NotifyDisconnected(nsresult aReason)
     906             : {
     907           0 :   PRES_DEBUG("%s:id[%s], reason[%" PRIx32 "], role[%d]\n", __func__,
     908             :              NS_ConvertUTF16toUTF8(mSessionId).get(), static_cast<uint32_t>(aReason),
     909             :              mRole);
     910             : 
     911           0 :   MOZ_ASSERT(NS_IsMainThread());
     912             : 
     913           0 :   if (mTransportType == nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
     914             :     nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder>
     915           0 :       builder = do_QueryInterface(mBuilder);
     916           0 :     if (builder) {
     917           0 :       Unused << NS_WARN_IF(NS_FAILED(builder->NotifyDisconnected(aReason)));
     918             :     }
     919             :   }
     920             : 
     921             :   // Unset control channel here so it won't try to re-close it in potential
     922             :   // subsequent |Shutdown| calls.
     923           0 :   SetControlChannel(nullptr);
     924             : 
     925           0 :   if (NS_WARN_IF(NS_FAILED(aReason) || !mIsResponderReady)) {
     926             :     // The presentation session instance may already exist.
     927             :     // Change the state to CLOSED if it is not terminated.
     928           0 :     if (nsIPresentationSessionListener::STATE_TERMINATED != mState) {
     929           0 :       SetStateWithReason(nsIPresentationSessionListener::STATE_CLOSED, aReason);
     930             :     }
     931             : 
     932             :     // If |aReason| is NS_OK, it implies that the user closes the connection
     933             :     // before becomming connected. No need to call |ReplyError| in this case.
     934           0 :     if (NS_FAILED(aReason)) {
     935           0 :       if (mIsReconnecting) {
     936           0 :         NotifyReconnectResult(NS_ERROR_DOM_OPERATION_ERR);
     937             :       }
     938             :       // Reply error for an abnormal close.
     939           0 :       return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
     940             :     }
     941           0 :     Shutdown(aReason);
     942             :   }
     943             : 
     944             :   // This is the case for reconnecting a connection which is in
     945             :   // connecting state and |mTransport| is not ready.
     946           0 :   if (mDoReconnectAfterClose && !mTransport) {
     947           0 :     mDoReconnectAfterClose = false;
     948           0 :     return Reconnect(mReconnectCallback);
     949             :   }
     950             : 
     951           0 :   return NS_OK;
     952             : }
     953             : 
     954             : // nsIServerSocketListener
     955             : NS_IMETHODIMP
     956           0 : PresentationControllingInfo::OnSocketAccepted(nsIServerSocket* aServerSocket,
     957             :                                             nsISocketTransport* aTransport)
     958             : {
     959             :   int32_t port;
     960           0 :   nsresult rv = aTransport->GetPort(&port);
     961           0 :   if (!NS_WARN_IF(NS_FAILED(rv))) {
     962           0 :     PRES_DEBUG("%s:receive from port[%d]\n",__func__, port);
     963             :   }
     964             : 
     965           0 :   MOZ_ASSERT(NS_IsMainThread());
     966             : 
     967           0 :   if (NS_WARN_IF(!mBuilderConstructor)) {
     968           0 :     return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
     969             :   }
     970             : 
     971             :   // Initialize session transport builder and use |this| as the callback.
     972           0 :   nsCOMPtr<nsIPresentationTCPSessionTransportBuilder> builder;
     973           0 :   if (NS_SUCCEEDED(mBuilderConstructor->CreateTransportBuilder(
     974             :                      nsIPresentationChannelDescription::TYPE_TCP,
     975             :                      getter_AddRefs(mBuilder)))) {
     976           0 :     builder = do_QueryInterface(mBuilder);
     977             :   }
     978             : 
     979           0 :   if (NS_WARN_IF(!builder)) {
     980           0 :     return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
     981             :   }
     982             : 
     983           0 :   mTransportType = nsIPresentationChannelDescription::TYPE_TCP;
     984           0 :   return builder->BuildTCPSenderTransport(aTransport, this);
     985             : }
     986             : 
     987             : NS_IMETHODIMP
     988           0 : PresentationControllingInfo::OnStopListening(nsIServerSocket* aServerSocket,
     989             :                                            nsresult aStatus)
     990             : {
     991           0 :   PRES_DEBUG("controller %s:status[%" PRIx32 "]\n",__func__,
     992             :              static_cast<uint32_t>(aStatus));
     993             : 
     994           0 :   MOZ_ASSERT(NS_IsMainThread());
     995             : 
     996           0 :   if (aStatus == NS_BINDING_ABORTED) { // The server socket was manually closed.
     997           0 :     return NS_OK;
     998             :   }
     999             : 
    1000           0 :   Shutdown(aStatus);
    1001             : 
    1002           0 :   if (NS_WARN_IF(!IsSessionReady())) {
    1003             :     // It happens before the session is ready. Reply the callback.
    1004           0 :     return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
    1005             :   }
    1006             : 
    1007             :   // It happens after the session is ready. Change the state to CLOSED.
    1008           0 :   SetStateWithReason(nsIPresentationSessionListener::STATE_CLOSED, aStatus);
    1009             : 
    1010           0 :   return NS_OK;
    1011             : }
    1012             : 
    1013             : /**
    1014             :  * The steps to reconnect a session are summarized below:
    1015             :  * 1. Change |mState| to CONNECTING.
    1016             :  * 2. Check whether |mControlChannel| is existed or not. Usually we have to
    1017             :  *    create a new control cahnnel.
    1018             :  * 3.1 |mControlChannel| is null, which means we have to create a new one.
    1019             :  *     |EstablishControlChannel| is called to create a new control channel.
    1020             :  *     At this point, |mControlChannel| is not able to use yet. Set
    1021             :  *     |mIsReconnecting| to true and wait until |NotifyConnected|.
    1022             :  * 3.2 |mControlChannel| is not null and is avaliable.
    1023             :  *     We can just call |ContinueReconnect| to send reconnect command.
    1024             :  * 4. |NotifyReconnected| of |nsIPresentationControlChannelListener| is called
    1025             :  *    to indicate the receiver is ready for reconnecting.
    1026             :  * 5. Once both step 3 and 4 are done, the rest is to build a new data
    1027             :  *    transport channel by following the same steps as starting a
    1028             :  *    new session.
    1029             :  */
    1030             : 
    1031             : nsresult
    1032           0 : PresentationControllingInfo::Reconnect(nsIPresentationServiceCallback* aCallback)
    1033             : {
    1034           0 :   PRES_DEBUG("%s:id[%s], role[%d], state[%d]\n", __func__,
    1035             :              NS_ConvertUTF16toUTF8(mSessionId).get(), mRole, mState);
    1036             : 
    1037           0 :   if (!aCallback) {
    1038           0 :     return NS_ERROR_INVALID_ARG;
    1039             :   }
    1040             : 
    1041           0 :   mReconnectCallback = aCallback;
    1042             : 
    1043           0 :   if (NS_WARN_IF(mState == nsIPresentationSessionListener::STATE_TERMINATED)) {
    1044           0 :     return NotifyReconnectResult(NS_ERROR_DOM_INVALID_STATE_ERR);
    1045             :   }
    1046             : 
    1047             :   // If |mState| is not CLOSED, we have to close the connection before
    1048             :   // reconnecting. The process to reconnect will be continued after
    1049             :   // |NotifyDisconnected| or |NotifyTransportClosed| is invoked.
    1050           0 :   if (mState == nsIPresentationSessionListener::STATE_CONNECTING ||
    1051           0 :       mState == nsIPresentationSessionListener::STATE_CONNECTED) {
    1052           0 :     mDoReconnectAfterClose = true;
    1053           0 :     return Close(NS_OK, nsIPresentationSessionListener::STATE_CLOSED);
    1054             :   }
    1055             : 
    1056             :   // Make sure |mState| is closed at this point.
    1057           0 :   MOZ_ASSERT(mState == nsIPresentationSessionListener::STATE_CLOSED);
    1058             : 
    1059           0 :   mState = nsIPresentationSessionListener::STATE_CONNECTING;
    1060           0 :   mIsReconnecting = true;
    1061             : 
    1062           0 :   nsresult rv = NS_OK;
    1063           0 :   if (!mControlChannel) {
    1064           0 :     nsCOMPtr<nsIPresentationControlChannel> ctrlChannel;
    1065           0 :     rv = mDevice->EstablishControlChannel(getter_AddRefs(ctrlChannel));
    1066           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1067           0 :       return NotifyReconnectResult(NS_ERROR_DOM_OPERATION_ERR);
    1068             :     }
    1069             : 
    1070           0 :     rv = Init(ctrlChannel);
    1071           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1072           0 :       return NotifyReconnectResult(NS_ERROR_DOM_OPERATION_ERR);
    1073             :     }
    1074             :   } else {
    1075           0 :     return ContinueReconnect();
    1076             :   }
    1077             : 
    1078           0 :   return NS_OK;
    1079             : }
    1080             : 
    1081             : nsresult
    1082           0 : PresentationControllingInfo::ContinueReconnect()
    1083             : {
    1084           0 :   MOZ_ASSERT(NS_IsMainThread());
    1085           0 :   MOZ_ASSERT(mControlChannel);
    1086             : 
    1087           0 :   mIsReconnecting = false;
    1088           0 :   if (NS_WARN_IF(NS_FAILED(mControlChannel->Reconnect(mSessionId, GetUrl())))) {
    1089           0 :     return NotifyReconnectResult(NS_ERROR_DOM_OPERATION_ERR);
    1090             :   }
    1091             : 
    1092           0 :   return NS_OK;
    1093             : }
    1094             : 
    1095             : // nsIListNetworkAddressesListener
    1096             : NS_IMETHODIMP
    1097           0 : PresentationControllingInfo::OnListedNetworkAddresses(const char** aAddressArray,
    1098             :                                                       uint32_t aAddressArraySize)
    1099             : {
    1100           0 :   if (!aAddressArraySize) {
    1101           0 :     return OnListNetworkAddressesFailed();
    1102             :   }
    1103             : 
    1104             :   // TODO bug 1228504 Take all IP addresses in PresentationChannelDescription
    1105             :   // into account. And at the first stage Presentation API is only exposed on
    1106             :   // Firefox OS where the first IP appears enough for most scenarios.
    1107             : 
    1108           0 :   nsAutoCString ip;
    1109           0 :   ip.Assign(aAddressArray[0]);
    1110             : 
    1111             :   // On Firefox desktop, the IP address is retrieved from a callback function.
    1112             :   // To make consistent code sequence, following function call is dispatched
    1113             :   // into main thread instead of calling it directly.
    1114           0 :   NS_DispatchToMainThread(NewRunnableMethod<nsCString>(
    1115             :     "dom::PresentationControllingInfo::OnGetAddress",
    1116             :     this,
    1117             :     &PresentationControllingInfo::OnGetAddress,
    1118           0 :     ip));
    1119             : 
    1120           0 :   return NS_OK;
    1121             : }
    1122             : 
    1123             : NS_IMETHODIMP
    1124           0 : PresentationControllingInfo::OnListNetworkAddressesFailed()
    1125             : {
    1126           0 :   PRES_ERROR("PresentationControllingInfo:OnListNetworkAddressesFailed");
    1127             : 
    1128             :   // In 1-UA case, transport channel can still be established
    1129             :   // on loopback interface even if no network address available.
    1130           0 :   NS_DispatchToMainThread(NewRunnableMethod<nsCString>(
    1131             :     "dom::PresentationControllingInfo::OnGetAddress",
    1132             :     this,
    1133             :     &PresentationControllingInfo::OnGetAddress,
    1134           0 :     "127.0.0.1"));
    1135             : 
    1136           0 :   return NS_OK;
    1137             : }
    1138             : 
    1139             : nsresult
    1140           0 : PresentationControllingInfo::NotifyReconnectResult(nsresult aStatus)
    1141             : {
    1142           0 :   if (!mReconnectCallback) {
    1143           0 :     MOZ_ASSERT(false, "mReconnectCallback can not be null here.");
    1144             :     return NS_ERROR_FAILURE;
    1145             :   }
    1146             : 
    1147           0 :   mIsReconnecting = false;
    1148             :   nsCOMPtr<nsIPresentationServiceCallback> callback =
    1149           0 :     mReconnectCallback.forget();
    1150           0 :   if (NS_FAILED(aStatus)) {
    1151           0 :     return callback->NotifyError(aStatus);
    1152             :   }
    1153             : 
    1154           0 :   return callback->NotifySuccess(GetUrl());
    1155             : }
    1156             : 
    1157             : // nsIPresentationSessionTransportCallback
    1158             : NS_IMETHODIMP
    1159           0 : PresentationControllingInfo::NotifyTransportReady()
    1160             : {
    1161           0 :   return PresentationSessionInfo::NotifyTransportReady();
    1162             : }
    1163             : 
    1164             : NS_IMETHODIMP
    1165           0 : PresentationControllingInfo::NotifyTransportClosed(nsresult aReason)
    1166             : {
    1167           0 :   if (!mDoReconnectAfterClose) {
    1168           0 :     return PresentationSessionInfo::NotifyTransportClosed(aReason);;
    1169             :   }
    1170             : 
    1171           0 :   MOZ_ASSERT(mState == nsIPresentationSessionListener::STATE_CLOSED);
    1172             : 
    1173           0 :   mTransport = nullptr;
    1174           0 :   mIsTransportReady = false;
    1175           0 :   mDoReconnectAfterClose = false;
    1176           0 :   return Reconnect(mReconnectCallback);
    1177             : }
    1178             : 
    1179             : NS_IMETHODIMP
    1180           0 : PresentationControllingInfo::NotifyData(const nsACString& aData, bool aIsBinary)
    1181             : {
    1182           0 :   return PresentationSessionInfo::NotifyData(aData, aIsBinary);
    1183             : }
    1184             : 
    1185             : /**
    1186             :  * Implementation of PresentationPresentingInfo
    1187             :  *
    1188             :  * During presentation session establishment, the receiver expects the following
    1189             :  * after trying to launch the app by notifying "presentation-launch-receiver":
    1190             :  * (The order between step 2 and 3 is not guaranteed.)
    1191             :  * 1. |Observe| of |nsIObserver| is called with "presentation-receiver-launched".
    1192             :  *    Then start listen to document |STATE_TRANSFERRING| event.
    1193             :  * 2. |NotifyResponderReady| is called to indicate the receiver page is ready
    1194             :  *    for presentation use.
    1195             :  * 3. |OnOffer| of |nsIPresentationControlChannelListener| is called.
    1196             :  * 4. Once both step 2 and 3 are done, establish the data transport channel and
    1197             :  *    send the answer. (The control channel will be closed by the sender once it
    1198             :  *    receives the answer.)
    1199             :  * 5. |NotifyTransportReady| of |nsIPresentationSessionTransportCallback| is
    1200             :  *    called. The presentation session is ready to use, so notify the listener
    1201             :  *    of CONNECTED state.
    1202             :  */
    1203             : 
    1204           0 : NS_IMPL_ISUPPORTS_INHERITED(PresentationPresentingInfo,
    1205             :                             PresentationSessionInfo,
    1206             :                             nsITimerCallback)
    1207             : 
    1208             : nsresult
    1209           0 : PresentationPresentingInfo::Init(nsIPresentationControlChannel* aControlChannel)
    1210             : {
    1211           0 :   PresentationSessionInfo::Init(aControlChannel);
    1212             : 
    1213             :   // Add a timer to prevent waiting indefinitely in case the receiver page fails
    1214             :   // to become ready.
    1215             :   nsresult rv;
    1216             :   int32_t timeout =
    1217           0 :     Preferences::GetInt("presentation.receiver.loading.timeout", 10000);
    1218           0 :   mTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
    1219           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1220           0 :     return rv;
    1221             :   }
    1222           0 :   rv = mTimer->InitWithCallback(this, timeout, nsITimer::TYPE_ONE_SHOT);
    1223           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1224           0 :     return rv;
    1225             :   }
    1226             : 
    1227           0 :   return NS_OK;
    1228             : }
    1229             : 
    1230             : void
    1231           0 : PresentationPresentingInfo::Shutdown(nsresult aReason)
    1232             : {
    1233           0 :   PresentationSessionInfo::Shutdown(aReason);
    1234             : 
    1235           0 :   if (mTimer) {
    1236           0 :     mTimer->Cancel();
    1237             :   }
    1238             : 
    1239           0 :   mLoadingCallback = nullptr;
    1240           0 :   mRequesterDescription = nullptr;
    1241           0 :   mPendingCandidates.Clear();
    1242           0 :   mPromise = nullptr;
    1243           0 :   mHasFlushPendingEvents = false;
    1244           0 : }
    1245             : 
    1246             : // nsIPresentationSessionTransportBuilderListener
    1247             : NS_IMETHODIMP
    1248           0 : PresentationPresentingInfo::OnSessionTransport(nsIPresentationSessionTransport* aTransport)
    1249             : {
    1250           0 :   nsresult rv = PresentationSessionInfo::OnSessionTransport(aTransport);
    1251             : 
    1252           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1253           0 :     return rv;
    1254             :   }
    1255             : 
    1256             :   // The session transport is managed by content process
    1257           0 :   if (NS_WARN_IF(!aTransport)) {
    1258           0 :     return NS_ERROR_INVALID_ARG;
    1259             :   }
    1260             : 
    1261             :   // send answer for TCP session transport
    1262           0 :   if (mTransportType == nsIPresentationChannelDescription::TYPE_TCP) {
    1263             :     // Prepare and send the answer.
    1264             :     // In the current implementation of |PresentationSessionTransport|,
    1265             :     // |GetSelfAddress| cannot return the real info when it's initialized via
    1266             :     // |buildTCPReceiverTransport|. Yet this deficiency only affects the channel
    1267             :     // description for the answer, which is not actually checked at requester side.
    1268           0 :     nsCOMPtr<nsINetAddr> selfAddr;
    1269           0 :     rv = mTransport->GetSelfAddress(getter_AddRefs(selfAddr));
    1270           0 :     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "GetSelfAddress failed");
    1271             : 
    1272           0 :     nsCString address;
    1273           0 :     uint16_t port = 0;
    1274           0 :     if (NS_SUCCEEDED(rv)) {
    1275           0 :       selfAddr->GetAddress(address);
    1276           0 :       selfAddr->GetPort(&port);
    1277             :     }
    1278             :     nsCOMPtr<nsIPresentationChannelDescription> description =
    1279           0 :       new TCPPresentationChannelDescription(address, port);
    1280             : 
    1281           0 :     return mControlChannel->SendAnswer(description);
    1282             :   }
    1283             : 
    1284           0 :   return NS_OK;
    1285             : }
    1286             : 
    1287             : // Delegate the pending offer and ICE candidates to builder.
    1288             : NS_IMETHODIMP
    1289           0 : PresentationPresentingInfo::FlushPendingEvents(nsIPresentationDataChannelSessionTransportBuilder* builder)
    1290             : {
    1291           0 :   if (NS_WARN_IF(!builder)) {
    1292           0 :     return NS_ERROR_FAILURE;
    1293             :   }
    1294             : 
    1295           0 :   mHasFlushPendingEvents = true;
    1296             : 
    1297           0 :   if (mRequesterDescription) {
    1298           0 :     builder->OnOffer(mRequesterDescription);
    1299             :   }
    1300           0 :   mRequesterDescription = nullptr;
    1301             : 
    1302           0 :   for (size_t i = 0; i < mPendingCandidates.Length(); ++i) {
    1303           0 :     builder->OnIceCandidate(mPendingCandidates[i]);
    1304             :   }
    1305           0 :   mPendingCandidates.Clear();
    1306           0 :   return NS_OK;
    1307             : }
    1308             : 
    1309             : nsresult
    1310           0 : PresentationPresentingInfo::InitTransportAndSendAnswer()
    1311             : {
    1312           0 :   MOZ_ASSERT(NS_IsMainThread());
    1313           0 :   MOZ_ASSERT(mState == nsIPresentationSessionListener::STATE_CONNECTING);
    1314             : 
    1315           0 :   uint8_t type = 0;
    1316           0 :   nsresult rv = mRequesterDescription->GetType(&type);
    1317           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1318           0 :     return rv;
    1319             :   }
    1320             : 
    1321           0 :   if (NS_WARN_IF(!mBuilderConstructor)) {
    1322           0 :     return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
    1323             :   }
    1324             : 
    1325           0 :   if (NS_WARN_IF(NS_FAILED(
    1326             :     mBuilderConstructor->CreateTransportBuilder(type,
    1327             :                                                 getter_AddRefs(mBuilder))))) {
    1328           0 :     return NS_ERROR_NOT_AVAILABLE;
    1329             :   }
    1330             : 
    1331           0 :   if (type == nsIPresentationChannelDescription::TYPE_TCP) {
    1332             :     // Establish a data transport channel |mTransport| to the sender and use
    1333             :     // |this| as the callback.
    1334             :     nsCOMPtr<nsIPresentationTCPSessionTransportBuilder> builder =
    1335           0 :       do_QueryInterface(mBuilder);
    1336           0 :     if (NS_WARN_IF(!builder)) {
    1337           0 :       return NS_ERROR_NOT_AVAILABLE;
    1338             :     }
    1339             : 
    1340           0 :     mTransportType = nsIPresentationChannelDescription::TYPE_TCP;
    1341           0 :     return builder->BuildTCPReceiverTransport(mRequesterDescription, this);
    1342             :   }
    1343             : 
    1344           0 :   if (type == nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
    1345           0 :     if (!Preferences::GetBool("dom.presentation.session_transport.data_channel.enable")) {
    1346           0 :       return NS_ERROR_NOT_IMPLEMENTED;
    1347             :     }
    1348             :     /**
    1349             :      * Generally transport is maintained by the chrome process. However, data
    1350             :      * channel should be live with the DOM , which implies RTCDataChannel in an OOP
    1351             :      * page should be establish in the content process.
    1352             :      *
    1353             :      * |mBuilderConstructor| is responsible for creating a builder, which is for
    1354             :      * building a data channel transport.
    1355             :      *
    1356             :      * In the OOP case, |mBuilderConstructor| would create a builder which is
    1357             :      * an object of |PresentationBuilderParent|. So, |BuildDataChannelTransport|
    1358             :      * triggers an IPC call to make content process establish a RTCDataChannel
    1359             :      * transport.
    1360             :      */
    1361             : 
    1362           0 :     mTransportType = nsIPresentationChannelDescription::TYPE_DATACHANNEL;
    1363             : 
    1364             :     nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder> dataChannelBuilder =
    1365           0 :       do_QueryInterface(mBuilder);
    1366           0 :     if (NS_WARN_IF(!dataChannelBuilder)) {
    1367           0 :       return NS_ERROR_NOT_AVAILABLE;
    1368             :     }
    1369             : 
    1370           0 :     nsPIDOMWindowInner* window = GetWindow();
    1371             : 
    1372           0 :     rv = dataChannelBuilder->
    1373           0 :            BuildDataChannelTransport(nsIPresentationService::ROLE_RECEIVER,
    1374             :                                      window,
    1375           0 :                                      this);
    1376           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1377           0 :       return rv;
    1378             :     }
    1379             : 
    1380           0 :     rv = FlushPendingEvents(dataChannelBuilder);
    1381           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1382           0 :       return rv;
    1383             :     }
    1384             : 
    1385           0 :     return NS_OK;
    1386             :   }
    1387             : 
    1388           0 :   MOZ_ASSERT(false, "Unknown nsIPresentationChannelDescription type!");
    1389             :   return NS_ERROR_UNEXPECTED;
    1390             : }
    1391             : 
    1392             : nsresult
    1393           0 : PresentationPresentingInfo::UntrackFromService()
    1394             : {
    1395             :   // Remove the OOP responding info (if it has never been used).
    1396           0 :   if (mContentParent) {
    1397           0 :     Unused << NS_WARN_IF(!static_cast<ContentParent*>(mContentParent.get())->SendNotifyPresentationReceiverCleanUp(mSessionId));
    1398             :   }
    1399             : 
    1400             :   // Receiver device might need clean up after session termination.
    1401           0 :   if (mDevice) {
    1402           0 :     mDevice->Disconnect();
    1403             :   }
    1404           0 :   mDevice = nullptr;
    1405             : 
    1406             :   // Remove the session info (and the in-process responding info if there's any).
    1407             :   nsCOMPtr<nsIPresentationService> service =
    1408           0 :     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
    1409           0 :   if (NS_WARN_IF(!service)) {
    1410           0 :     return NS_ERROR_NOT_AVAILABLE;
    1411             :   }
    1412           0 :   static_cast<PresentationService*>(service.get())->UntrackSessionInfo(mSessionId, mRole);
    1413             : 
    1414           0 :   return NS_OK;
    1415             : }
    1416             : 
    1417             : bool
    1418           0 : PresentationPresentingInfo::IsAccessible(base::ProcessId aProcessId)
    1419             : {
    1420             :   // Only the specific content process should access the responder info.
    1421           0 :   return (mContentParent) ?
    1422           0 :           aProcessId == static_cast<ContentParent*>(mContentParent.get())->OtherPid() :
    1423           0 :           false;
    1424             : }
    1425             : 
    1426             : nsresult
    1427           0 : PresentationPresentingInfo::NotifyResponderReady()
    1428             : {
    1429           0 :   PRES_DEBUG("%s:id[%s], role[%d], state[%d]\n", __func__,
    1430             :              NS_ConvertUTF16toUTF8(mSessionId).get(), mRole, mState);
    1431             : 
    1432           0 :   if (mTimer) {
    1433           0 :     mTimer->Cancel();
    1434           0 :     mTimer = nullptr;
    1435             :   }
    1436             : 
    1437           0 :   mIsResponderReady = true;
    1438             : 
    1439             :   // Initialize |mTransport| and send the answer to the sender if sender's
    1440             :   // description is already offered.
    1441           0 :   if (mRequesterDescription) {
    1442           0 :     nsresult rv = InitTransportAndSendAnswer();
    1443           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1444           0 :       return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
    1445             :     }
    1446             :   }
    1447             : 
    1448           0 :   return NS_OK;
    1449             : }
    1450             : 
    1451             : nsresult
    1452           0 : PresentationPresentingInfo::NotifyResponderFailure()
    1453             : {
    1454           0 :   PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
    1455             :              NS_ConvertUTF16toUTF8(mSessionId).get(), mRole);
    1456             : 
    1457           0 :   if (mTimer) {
    1458           0 :     mTimer->Cancel();
    1459           0 :     mTimer = nullptr;
    1460             :   }
    1461             : 
    1462           0 :   return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
    1463             : }
    1464             : 
    1465             : nsresult
    1466           0 : PresentationPresentingInfo::DoReconnect()
    1467             : {
    1468           0 :   PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
    1469             :              NS_ConvertUTF16toUTF8(mSessionId).get(), mRole);
    1470             : 
    1471           0 :   MOZ_ASSERT(mState == nsIPresentationSessionListener::STATE_CLOSED);
    1472             : 
    1473           0 :   SetStateWithReason(nsIPresentationSessionListener::STATE_CONNECTING, NS_OK);
    1474             : 
    1475           0 :   return NotifyResponderReady();
    1476             : }
    1477             : 
    1478             : // nsIPresentationControlChannelListener
    1479             : NS_IMETHODIMP
    1480           0 : PresentationPresentingInfo::OnOffer(nsIPresentationChannelDescription* aDescription)
    1481             : {
    1482           0 :   if (NS_WARN_IF(mHasFlushPendingEvents)) {
    1483           0 :     return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
    1484             :   }
    1485             : 
    1486           0 :   if (NS_WARN_IF(!aDescription)) {
    1487           0 :     return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
    1488             :   }
    1489             : 
    1490           0 :   mRequesterDescription = aDescription;
    1491             : 
    1492             :   // Initialize |mTransport| and send the answer to the sender if the receiver
    1493             :   // page is ready for presentation use.
    1494           0 :   if (mIsResponderReady) {
    1495           0 :     nsresult rv = InitTransportAndSendAnswer();
    1496           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1497           0 :       return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
    1498             :     }
    1499             :   }
    1500             : 
    1501           0 :   return NS_OK;
    1502             : }
    1503             : 
    1504             : NS_IMETHODIMP
    1505           0 : PresentationPresentingInfo::OnAnswer(nsIPresentationChannelDescription* aDescription)
    1506             : {
    1507           0 :   MOZ_ASSERT(false, "Receiver side should not receive answer.");
    1508             :   return NS_ERROR_FAILURE;
    1509             : }
    1510             : 
    1511             : NS_IMETHODIMP
    1512           0 : PresentationPresentingInfo::OnIceCandidate(const nsAString& aCandidate)
    1513             : {
    1514           0 :   if (!mBuilder && !mHasFlushPendingEvents) {
    1515           0 :     mPendingCandidates.AppendElement(nsString(aCandidate));
    1516           0 :     return NS_OK;
    1517             :   }
    1518             : 
    1519           0 :   if (NS_WARN_IF(!mBuilder && mHasFlushPendingEvents)) {
    1520           0 :     return NS_ERROR_FAILURE;
    1521             :   }
    1522             : 
    1523             :   nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder>
    1524           0 :     builder = do_QueryInterface(mBuilder);
    1525             : 
    1526           0 :   return builder->OnIceCandidate(aCandidate);
    1527             : }
    1528             : 
    1529             : NS_IMETHODIMP
    1530           0 : PresentationPresentingInfo::NotifyConnected()
    1531             : {
    1532           0 :   PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
    1533             :              NS_ConvertUTF16toUTF8(mSessionId).get(), mRole);
    1534             : 
    1535           0 :   if (nsIPresentationSessionListener::STATE_TERMINATED == mState) {
    1536           0 :     ContinueTermination();
    1537             :   }
    1538             : 
    1539           0 :   return NS_OK;
    1540             : }
    1541             : 
    1542             : NS_IMETHODIMP
    1543           0 : PresentationPresentingInfo::NotifyReconnected()
    1544             : {
    1545           0 :   MOZ_ASSERT(false, "NotifyReconnected should not be called at receiver side.");
    1546             :   return NS_OK;
    1547             : }
    1548             : 
    1549             : NS_IMETHODIMP
    1550           0 : PresentationPresentingInfo::NotifyDisconnected(nsresult aReason)
    1551             : {
    1552           0 :   PRES_DEBUG("%s:id[%s], reason[%" PRIx32 "], role[%d]\n", __func__,
    1553             :              NS_ConvertUTF16toUTF8(mSessionId).get(), static_cast<uint32_t>(aReason),
    1554             :              mRole);
    1555             : 
    1556           0 :   MOZ_ASSERT(NS_IsMainThread());
    1557             : 
    1558           0 :   if (mTransportType == nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
    1559             :     nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder>
    1560           0 :       builder = do_QueryInterface(mBuilder);
    1561           0 :     if (builder) {
    1562           0 :       Unused << NS_WARN_IF(NS_FAILED(builder->NotifyDisconnected(aReason)));
    1563             :     }
    1564             :   }
    1565             : 
    1566             :   // Unset control channel here so it won't try to re-close it in potential
    1567             :   // subsequent |Shutdown| calls.
    1568           0 :   SetControlChannel(nullptr);
    1569             : 
    1570           0 :   if (NS_WARN_IF(NS_FAILED(aReason))) {
    1571             :     // The presentation session instance may already exist.
    1572             :     // Change the state to TERMINATED since it never succeeds.
    1573           0 :     SetStateWithReason(nsIPresentationSessionListener::STATE_TERMINATED, aReason);
    1574             : 
    1575             :     // Reply error for an abnormal close.
    1576           0 :     return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
    1577             :   }
    1578             : 
    1579           0 :   return NS_OK;
    1580             : }
    1581             : 
    1582             : // nsITimerCallback
    1583             : NS_IMETHODIMP
    1584           0 : PresentationPresentingInfo::Notify(nsITimer* aTimer)
    1585             : {
    1586           0 :   MOZ_ASSERT(NS_IsMainThread());
    1587           0 :   NS_WARNING("The receiver page fails to become ready before timeout.");
    1588             : 
    1589           0 :   mTimer = nullptr;
    1590           0 :   return ReplyError(NS_ERROR_DOM_TIMEOUT_ERR);
    1591             : }
    1592             : 
    1593             : // PromiseNativeHandler
    1594             : void
    1595           0 : PresentationPresentingInfo::ResolvedCallback(JSContext* aCx,
    1596             :                                              JS::Handle<JS::Value> aValue)
    1597             : {
    1598           0 :   MOZ_ASSERT(NS_IsMainThread());
    1599             : 
    1600           0 :   if (NS_WARN_IF(!aValue.isObject())) {
    1601           0 :     ReplyError(NS_ERROR_DOM_OPERATION_ERR);
    1602           0 :     return;
    1603             :   }
    1604             : 
    1605           0 :   JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
    1606           0 :   if (NS_WARN_IF(!obj)) {
    1607           0 :     ReplyError(NS_ERROR_DOM_OPERATION_ERR);
    1608           0 :     return;
    1609             :   }
    1610             : 
    1611             :   // Start to listen to document state change event |STATE_TRANSFERRING|.
    1612             :   // Use Element to support both HTMLIFrameElement and nsXULElement.
    1613           0 :   Element* frame = nullptr;
    1614           0 :   nsresult rv = UNWRAP_OBJECT(Element, &obj, frame);
    1615           0 :   if (NS_WARN_IF(!frame)) {
    1616           0 :     ReplyError(NS_ERROR_DOM_OPERATION_ERR);
    1617           0 :     return;
    1618             :   }
    1619             : 
    1620           0 :   nsCOMPtr<nsIFrameLoaderOwner> owner = do_QueryInterface((nsIFrameLoaderOwner*) frame);
    1621           0 :   if (NS_WARN_IF(!owner)) {
    1622           0 :     ReplyError(NS_ERROR_DOM_OPERATION_ERR);
    1623           0 :     return;
    1624             :   }
    1625             : 
    1626           0 :   nsCOMPtr<nsIFrameLoader> frameLoader = owner->GetFrameLoader();
    1627           0 :   if (NS_WARN_IF(!frameLoader)) {
    1628           0 :     ReplyError(NS_ERROR_DOM_OPERATION_ERR);
    1629           0 :     return;
    1630             :   }
    1631             : 
    1632           0 :   RefPtr<TabParent> tabParent = TabParent::GetFrom(frameLoader);
    1633           0 :   if (tabParent) {
    1634             :     // OOP frame
    1635             :     // Notify the content process that a receiver page has launched, so it can
    1636             :     // start monitoring the loading progress.
    1637           0 :     mContentParent = tabParent->Manager();
    1638           0 :     Unused << NS_WARN_IF(!static_cast<ContentParent*>(mContentParent.get())->SendNotifyPresentationReceiverLaunched(tabParent, mSessionId));
    1639             :   } else {
    1640             :     // In-process frame
    1641           0 :     nsCOMPtr<nsIDocShell> docShell;
    1642           0 :     rv = frameLoader->GetDocShell(getter_AddRefs(docShell));
    1643           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1644           0 :       ReplyError(NS_ERROR_DOM_OPERATION_ERR);
    1645           0 :       return;
    1646             :     }
    1647             : 
    1648             :     // Keep an eye on the loading progress of the receiver page.
    1649           0 :     mLoadingCallback = new PresentationResponderLoadingCallback(mSessionId);
    1650           0 :     rv = mLoadingCallback->Init(docShell);
    1651           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1652           0 :       ReplyError(NS_ERROR_DOM_OPERATION_ERR);
    1653           0 :       return;
    1654             :     }
    1655             :   }
    1656             : }
    1657             : 
    1658             : void
    1659           0 : PresentationPresentingInfo::RejectedCallback(JSContext* aCx,
    1660             :                                              JS::Handle<JS::Value> aValue)
    1661             : {
    1662           0 :   MOZ_ASSERT(NS_IsMainThread());
    1663           0 :   NS_WARNING("Launching the receiver page has been rejected.");
    1664             : 
    1665           0 :   if (mTimer) {
    1666           0 :     mTimer->Cancel();
    1667           0 :     mTimer = nullptr;
    1668             :   }
    1669             : 
    1670           0 :   ReplyError(NS_ERROR_DOM_OPERATION_ERR);
    1671           0 : }

Generated by: LCOV version 1.13