tor-browser

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

GMPStorageChild.cpp (6820B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "GMPStorageChild.h"
      7 
      8 #include "GMPChild.h"
      9 #include "base/task.h"
     10 #include "gmp-storage.h"
     11 
     12 #define ON_GMP_THREAD() (mPlugin->GMPMessageLoop() == MessageLoop::current())
     13 
     14 #define CALL_ON_GMP_THREAD(_func, ...)                        \
     15  do {                                                        \
     16    if (ON_GMP_THREAD()) {                                    \
     17      _func(__VA_ARGS__);                                     \
     18    } else {                                                  \
     19      mPlugin->GMPMessageLoop()->PostTask(                    \
     20          dont_add_new_uses_of_this::NewRunnableMethod(       \
     21              this, &GMPStorageChild::_func, ##__VA_ARGS__)); \
     22    }                                                         \
     23  } while (false)
     24 
     25 namespace mozilla::gmp {
     26 
     27 static nsTArray<uint8_t> ToArray(const uint8_t* aData, uint32_t aDataSize) {
     28  nsTArray<uint8_t> data;
     29  data.AppendElements(aData, aDataSize);
     30  return data;
     31 }
     32 
     33 GMPRecordImpl::GMPRecordImpl(GMPStorageChild* aOwner, const nsCString& aName,
     34                             GMPRecordClient* aClient)
     35    : mName(aName), mClient(aClient), mOwner(aOwner) {}
     36 
     37 GMPErr GMPRecordImpl::Open() { return mOwner->Open(this); }
     38 
     39 void GMPRecordImpl::OpenComplete(GMPErr aStatus) {
     40  mClient->OpenComplete(aStatus);
     41 }
     42 
     43 GMPErr GMPRecordImpl::Read() { return mOwner->Read(this); }
     44 
     45 void GMPRecordImpl::ReadComplete(GMPErr aStatus, const uint8_t* aBytes,
     46                                 uint32_t aLength) {
     47  mClient->ReadComplete(aStatus, aBytes, aLength);
     48 }
     49 
     50 GMPErr GMPRecordImpl::Write(const uint8_t* aData, uint32_t aDataSize) {
     51  return mOwner->Write(this, aData, aDataSize);
     52 }
     53 
     54 void GMPRecordImpl::WriteComplete(GMPErr aStatus) {
     55  mClient->WriteComplete(aStatus);
     56 }
     57 
     58 GMPErr GMPRecordImpl::Close() {
     59  RefPtr<GMPRecordImpl> kungfuDeathGrip(this);
     60  // Delete our self reference.
     61  Release();
     62  mOwner->Close(this->Name());
     63  return GMPNoErr;
     64 }
     65 
     66 GMPStorageChild::GMPStorageChild(GMPChild* aPlugin)
     67    : mMonitor("GMPStorageChild"), mPlugin(aPlugin), mShutdown(false) {
     68  MOZ_ASSERT(ON_GMP_THREAD());
     69 }
     70 
     71 GMPErr GMPStorageChild::CreateRecord(const nsCString& aRecordName,
     72                                     GMPRecord** aOutRecord,
     73                                     GMPRecordClient* aClient) {
     74  MonitorAutoLock lock(mMonitor);
     75 
     76  if (mShutdown) {
     77    NS_WARNING("GMPStorage used after it's been shutdown!");
     78    return GMPClosedErr;
     79  }
     80 
     81  MOZ_ASSERT(aRecordName.Length() && aOutRecord);
     82 
     83  if (HasRecord(aRecordName)) {
     84    return GMPRecordInUse;
     85  }
     86 
     87  RefPtr<GMPRecordImpl> record(new GMPRecordImpl(this, aRecordName, aClient));
     88  mRecords.InsertOrUpdate(aRecordName, RefPtr{record});  // Addrefs
     89 
     90  // The GMPRecord holds a self reference until the GMP calls Close() on
     91  // it. This means the object is always valid (even if neutered) while
     92  // the GMP expects it to be.
     93  record.forget(aOutRecord);
     94 
     95  return GMPNoErr;
     96 }
     97 
     98 bool GMPStorageChild::HasRecord(const nsCString& aRecordName) {
     99  mMonitor.AssertCurrentThreadOwns();
    100  return mRecords.Contains(aRecordName);
    101 }
    102 
    103 already_AddRefed<GMPRecordImpl> GMPStorageChild::GetRecord(
    104    const nsCString& aRecordName) {
    105  MonitorAutoLock lock(mMonitor);
    106  RefPtr<GMPRecordImpl> record;
    107  mRecords.Get(aRecordName, getter_AddRefs(record));
    108  return record.forget();
    109 }
    110 
    111 GMPErr GMPStorageChild::Open(GMPRecordImpl* aRecord) {
    112  MonitorAutoLock lock(mMonitor);
    113 
    114  if (mShutdown) {
    115    NS_WARNING("GMPStorage used after it's been shutdown!");
    116    return GMPClosedErr;
    117  }
    118 
    119  if (!HasRecord(aRecord->Name())) {
    120    // Trying to re-open a record that has already been closed.
    121    return GMPClosedErr;
    122  }
    123 
    124  CALL_ON_GMP_THREAD(SendOpen, aRecord->Name());
    125 
    126  return GMPNoErr;
    127 }
    128 
    129 GMPErr GMPStorageChild::Read(GMPRecordImpl* aRecord) {
    130  MonitorAutoLock lock(mMonitor);
    131 
    132  if (mShutdown) {
    133    NS_WARNING("GMPStorage used after it's been shutdown!");
    134    return GMPClosedErr;
    135  }
    136 
    137  if (!HasRecord(aRecord->Name())) {
    138    // Record not opened.
    139    return GMPClosedErr;
    140  }
    141 
    142  CALL_ON_GMP_THREAD(SendRead, aRecord->Name());
    143 
    144  return GMPNoErr;
    145 }
    146 
    147 GMPErr GMPStorageChild::Write(GMPRecordImpl* aRecord, const uint8_t* aData,
    148                              uint32_t aDataSize) {
    149  if (aDataSize > GMP_MAX_RECORD_SIZE) {
    150    return GMPQuotaExceededErr;
    151  }
    152 
    153  MonitorAutoLock lock(mMonitor);
    154 
    155  if (mShutdown) {
    156    NS_WARNING("GMPStorage used after it's been shutdown!");
    157    return GMPClosedErr;
    158  }
    159 
    160  if (!HasRecord(aRecord->Name())) {
    161    // Record not opened.
    162    return GMPClosedErr;
    163  }
    164 
    165  CALL_ON_GMP_THREAD(SendWrite, aRecord->Name(), ToArray(aData, aDataSize));
    166 
    167  return GMPNoErr;
    168 }
    169 
    170 GMPErr GMPStorageChild::Close(const nsCString& aRecordName) {
    171  MonitorAutoLock lock(mMonitor);
    172 
    173  if (!HasRecord(aRecordName)) {
    174    // Already closed.
    175    return GMPClosedErr;
    176  }
    177 
    178  mRecords.Remove(aRecordName);
    179 
    180  if (!mShutdown) {
    181    CALL_ON_GMP_THREAD(SendClose, aRecordName);
    182  }
    183 
    184  return GMPNoErr;
    185 }
    186 
    187 mozilla::ipc::IPCResult GMPStorageChild::RecvOpenComplete(
    188    const nsCString& aRecordName, const GMPErr& aStatus) {
    189  // We don't need a lock to read |mShutdown| since it is only changed in
    190  // the GMP thread.
    191  if (mShutdown) {
    192    return IPC_OK();
    193  }
    194  RefPtr<GMPRecordImpl> record = GetRecord(aRecordName);
    195  if (!record) {
    196    // Not fatal.
    197    return IPC_OK();
    198  }
    199  record->OpenComplete(aStatus);
    200  return IPC_OK();
    201 }
    202 
    203 mozilla::ipc::IPCResult GMPStorageChild::RecvReadComplete(
    204    const nsCString& aRecordName, const GMPErr& aStatus,
    205    nsTArray<uint8_t>&& aBytes) {
    206  if (mShutdown) {
    207    return IPC_OK();
    208  }
    209  RefPtr<GMPRecordImpl> record = GetRecord(aRecordName);
    210  if (!record) {
    211    // Not fatal.
    212    return IPC_OK();
    213  }
    214  record->ReadComplete(aStatus, aBytes.Elements(), aBytes.Length());
    215  return IPC_OK();
    216 }
    217 
    218 mozilla::ipc::IPCResult GMPStorageChild::RecvWriteComplete(
    219    const nsCString& aRecordName, const GMPErr& aStatus) {
    220  if (mShutdown) {
    221    return IPC_OK();
    222  }
    223  RefPtr<GMPRecordImpl> record = GetRecord(aRecordName);
    224  if (!record) {
    225    // Not fatal.
    226    return IPC_OK();
    227  }
    228  record->WriteComplete(aStatus);
    229  return IPC_OK();
    230 }
    231 
    232 mozilla::ipc::IPCResult GMPStorageChild::RecvShutdown() {
    233  // Block any new storage requests, and thus any messages back to the
    234  // parent. We don't delete any objects here, as that may invalidate
    235  // GMPRecord pointers held by the GMP.
    236  MonitorAutoLock lock(mMonitor);
    237  mShutdown = true;
    238  return IPC_OK();
    239 }
    240 
    241 }  // namespace mozilla::gmp
    242 
    243 // avoid redefined macro in unified build
    244 #undef ON_GMP_THREAD
    245 #undef CALL_ON_GMP_THREAD