tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

BroadcastChannelService.cpp (5349B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      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 "BroadcastChannelService.h"
      8 
      9 #include "BroadcastChannelParent.h"
     10 #include "mozilla/dom/BlobImpl.h"
     11 #include "mozilla/dom/File.h"
     12 #include "mozilla/dom/IPCBlobUtils.h"
     13 #include "mozilla/ipc/BackgroundParent.h"
     14 
     15 #ifdef XP_WIN
     16 #  undef PostMessage
     17 #endif
     18 
     19 namespace mozilla {
     20 
     21 using namespace ipc;
     22 
     23 namespace dom {
     24 
     25 namespace {
     26 
     27 BroadcastChannelService* sInstance = nullptr;
     28 
     29 ClonedMessageData CloneClonedMessageData(const ClonedMessageData& aOther) {
     30  auto cloneData = SerializedStructuredCloneBuffer{};
     31  cloneData.data.initScope(aOther.data().data.scope());
     32  const bool res = cloneData.data.Append(aOther.data().data);
     33  MOZ_RELEASE_ASSERT(res, "out of memory");
     34  return {std::move(cloneData), aOther.blobs(), aOther.inputStreams(),
     35          aOther.identifiers()};
     36 }
     37 
     38 MessageData CloneMessageData(const MessageData& aOther) {
     39  switch (aOther.data().type()) {
     40    case MessageDataType::TClonedMessageData:
     41      return {aOther.agentClusterId(),
     42              CloneClonedMessageData(aOther.data().get_ClonedMessageData())};
     43    case MessageDataType::TRefMessageData:
     44      return {aOther.agentClusterId(), aOther.data().get_RefMessageData()};
     45    default:
     46      MOZ_CRASH("Unexpected MessageDataType type");
     47  }
     48 }
     49 
     50 }  // namespace
     51 
     52 BroadcastChannelService::BroadcastChannelService() {
     53  AssertIsOnBackgroundThread();
     54 
     55  // sInstance is a raw BroadcastChannelService*.
     56  MOZ_ASSERT(!sInstance);
     57  sInstance = this;
     58 }
     59 
     60 BroadcastChannelService::~BroadcastChannelService() {
     61  AssertIsOnBackgroundThread();
     62  MOZ_ASSERT(sInstance == this);
     63  MOZ_ASSERT(mAgents.Count() == 0);
     64 
     65  sInstance = nullptr;
     66 }
     67 
     68 // static
     69 already_AddRefed<BroadcastChannelService>
     70 BroadcastChannelService::GetOrCreate() {
     71  AssertIsOnBackgroundThread();
     72 
     73  RefPtr<BroadcastChannelService> instance = sInstance;
     74  if (!instance) {
     75    instance = new BroadcastChannelService();
     76  }
     77  return instance.forget();
     78 }
     79 
     80 void BroadcastChannelService::RegisterActor(
     81    BroadcastChannelParent* aParent, const nsAString& aOriginChannelKey) {
     82  AssertIsOnBackgroundThread();
     83  MOZ_ASSERT(aParent);
     84 
     85  auto* const parents = mAgents.GetOrInsertNew(aOriginChannelKey);
     86 
     87  MOZ_ASSERT(!parents->Contains(aParent));
     88  parents->AppendElement(aParent);
     89 }
     90 
     91 void BroadcastChannelService::UnregisterActor(
     92    BroadcastChannelParent* aParent, const nsAString& aOriginChannelKey) {
     93  AssertIsOnBackgroundThread();
     94  MOZ_ASSERT(aParent);
     95 
     96  if (auto entry = mAgents.Lookup(aOriginChannelKey)) {
     97    entry.Data()->RemoveElement(aParent);
     98    // remove the entry if the array is now empty
     99    if (entry.Data()->IsEmpty()) {
    100      entry.Remove();
    101    }
    102  } else {
    103    MOZ_CRASH("Invalid state");
    104  }
    105 }
    106 
    107 void BroadcastChannelService::PostMessage(BroadcastChannelParent* aParent,
    108                                          const MessageData& aData,
    109                                          const nsAString& aOriginChannelKey) {
    110  AssertIsOnBackgroundThread();
    111  MOZ_ASSERT(aParent);
    112 
    113  nsTArray<BroadcastChannelParent*>* parents;
    114  if (!mAgents.Get(aOriginChannelKey, &parents)) {
    115    MOZ_CRASH("Invalid state");
    116  }
    117 
    118  // We need to keep the array alive for the life-time of this operation.
    119  nsTArray<RefPtr<BlobImpl>> blobImpls;
    120  if (aData.data().type() == MessageDataType::TClonedMessageData) {
    121    const nsTArray<IPCBlob>& blobs =
    122        aData.data().get_ClonedMessageData().blobs();
    123    if (!blobs.IsEmpty()) {
    124      blobImpls.SetCapacity(blobs.Length());
    125 
    126      for (uint32_t i = 0, len = blobs.Length(); i < len; ++i) {
    127        RefPtr<BlobImpl> impl = IPCBlobUtils::Deserialize(blobs[i]);
    128 
    129        MOZ_ASSERT(impl);
    130        blobImpls.AppendElement(impl);
    131      }
    132    }
    133  }
    134 
    135  uint32_t selectedActorsOnSamePid = 0;
    136 
    137  // For each parent actor, we notify the message.
    138  for (uint32_t i = 0; i < parents->Length(); ++i) {
    139    BroadcastChannelParent* parent = parents->ElementAt(i);
    140    MOZ_ASSERT(parent);
    141 
    142    if (parent == aParent) {
    143      continue;
    144    }
    145 
    146    if (parent->OtherChildID() == aParent->OtherChildID()) {
    147      ++selectedActorsOnSamePid;
    148    }
    149 
    150    // We need to have a copy of the data for this parent.
    151    MessageData newData = CloneMessageData(aData);
    152    MOZ_ASSERT(newData.data().type() == aData.data().type());
    153 
    154    if (!blobImpls.IsEmpty()) {
    155      nsTArray<IPCBlob>& newBlobImpls =
    156          newData.data().get_ClonedMessageData().blobs();
    157      MOZ_ASSERT(blobImpls.Length() == newBlobImpls.Length());
    158 
    159      // Serialize Blob objects for this message.
    160      for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) {
    161        nsresult rv = IPCBlobUtils::Serialize(blobImpls[i], newBlobImpls[i]);
    162        if (NS_WARN_IF(NS_FAILED(rv))) {
    163          return;
    164        }
    165      }
    166    }
    167 
    168    (void)parent->SendNotify(newData);
    169  }
    170 
    171  // If this is a refMessageData, we need to know when it can be released.
    172  if (aData.data().type() == MessageDataType::TRefMessageData) {
    173    (void)aParent->SendRefMessageDelivered(
    174        aData.data().get_RefMessageData().uuid(), selectedActorsOnSamePid);
    175  }
    176 }
    177 
    178 }  // namespace dom
    179 }  // namespace mozilla