tor-browser

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

ConnectionWorker.cpp (6487B)


      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 "ConnectionWorker.h"
      8 
      9 #include "mozilla/Hal.h"
     10 #include "mozilla/dom/WorkerPrivate.h"
     11 #include "mozilla/dom/WorkerRef.h"
     12 #include "mozilla/dom/WorkerRunnable.h"
     13 #include "mozilla/dom/WorkerScope.h"
     14 
     15 namespace mozilla::dom::network {
     16 
     17 class ConnectionProxy final : public hal::NetworkObserver {
     18 public:
     19  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ConnectionProxy)
     20 
     21  static already_AddRefed<ConnectionProxy> Create(
     22      WorkerPrivate* aWorkerPrivate, ConnectionWorker* aConnection) {
     23    RefPtr<ConnectionProxy> proxy = new ConnectionProxy(aConnection);
     24 
     25    RefPtr<StrongWorkerRef> workerRef = StrongWorkerRef::Create(
     26        aWorkerPrivate, "ConnectionProxy", [proxy]() { proxy->Shutdown(); });
     27    if (NS_WARN_IF(!workerRef)) {
     28      return nullptr;
     29    }
     30 
     31    proxy->mWorkerRef = new ThreadSafeWorkerRef(workerRef);
     32    return proxy.forget();
     33  }
     34 
     35  ThreadSafeWorkerRef* WorkerRef() const { return mWorkerRef; }
     36 
     37  // For IObserver - main-thread only.
     38  void Notify(const hal::NetworkInformation& aNetworkInfo) override;
     39 
     40  void Shutdown();
     41 
     42  void Update(ConnectionType aType, bool aIsWifi, uint32_t aDHCPGateway) {
     43    MOZ_ASSERT(mConnection);
     44    MOZ_ASSERT(IsCurrentThreadRunningWorker());
     45    mConnection->Update(aType, aIsWifi, aDHCPGateway, true);
     46  }
     47 
     48 private:
     49  explicit ConnectionProxy(ConnectionWorker* aConnection)
     50      : mConnection(aConnection) {}
     51 
     52  ~ConnectionProxy() = default;
     53 
     54  // Raw pointer because the ConnectionWorker keeps alive the proxy.
     55  // This is touched only on the worker-thread and it's nullified when the
     56  // shutdown procedure starts.
     57  ConnectionWorker* mConnection;
     58 
     59  RefPtr<ThreadSafeWorkerRef> mWorkerRef;
     60 };
     61 
     62 namespace {
     63 
     64 // This class initializes the hal observer on the main-thread.
     65 class InitializeRunnable : public WorkerMainThreadRunnable {
     66 private:
     67  // raw pointer because this is a sync runnable.
     68  ConnectionProxy* mProxy;
     69  hal::NetworkInformation& mNetworkInfo;
     70 
     71 public:
     72  InitializeRunnable(WorkerPrivate* aWorkerPrivate, ConnectionProxy* aProxy,
     73                     hal::NetworkInformation& aNetworkInfo)
     74      : WorkerMainThreadRunnable(aWorkerPrivate,
     75                                 "ConnectionWorker :: Initialize"_ns),
     76        mProxy(aProxy),
     77        mNetworkInfo(aNetworkInfo) {
     78    MOZ_ASSERT(aProxy);
     79    aWorkerPrivate->AssertIsOnWorkerThread();
     80  }
     81 
     82  bool MainThreadRun() override {
     83    MOZ_ASSERT(NS_IsMainThread());
     84    hal::RegisterNetworkObserver(mProxy);
     85    hal::GetCurrentNetworkInformation(&mNetworkInfo);
     86    return true;
     87  }
     88 };
     89 
     90 // This class turns down the hal observer on the main-thread.
     91 class ShutdownRunnable : public WorkerMainThreadRunnable {
     92 private:
     93  // raw pointer because this is a sync runnable.
     94  ConnectionProxy* mProxy;
     95 
     96 public:
     97  ShutdownRunnable(WorkerPrivate* aWorkerPrivate, ConnectionProxy* aProxy)
     98      : WorkerMainThreadRunnable(aWorkerPrivate,
     99                                 "ConnectionWorker :: Shutdown"_ns),
    100        mProxy(aProxy) {
    101    MOZ_ASSERT(aProxy);
    102    aWorkerPrivate->AssertIsOnWorkerThread();
    103  }
    104 
    105  bool MainThreadRun() override {
    106    MOZ_ASSERT(NS_IsMainThread());
    107    hal::UnregisterNetworkObserver(mProxy);
    108    return true;
    109  }
    110 };
    111 
    112 class NotifyRunnable final : public WorkerThreadRunnable {
    113 private:
    114  RefPtr<ConnectionProxy> mProxy;
    115 
    116  const ConnectionType mConnectionType;
    117  const bool mIsWifi;
    118  const uint32_t mDHCPGateway;
    119 
    120 public:
    121  NotifyRunnable(WorkerPrivate* aWorkerPrivate, ConnectionProxy* aProxy,
    122                 ConnectionType aType, bool aIsWifi, uint32_t aDHCPGateway)
    123      : WorkerThreadRunnable("NotifyRunnable"),
    124        mProxy(aProxy),
    125        mConnectionType(aType),
    126        mIsWifi(aIsWifi),
    127        mDHCPGateway(aDHCPGateway) {
    128    MOZ_ASSERT(aProxy);
    129    MOZ_ASSERT(NS_IsMainThread());
    130  }
    131 
    132  bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
    133    aWorkerPrivate->AssertIsOnWorkerThread();
    134    mProxy->Update(mConnectionType, mIsWifi, mDHCPGateway);
    135    return true;
    136  }
    137 };
    138 
    139 }  // anonymous namespace
    140 
    141 /* static */
    142 already_AddRefed<ConnectionWorker> ConnectionWorker::Create(
    143    WorkerPrivate* aWorkerPrivate, ErrorResult& aRv) {
    144  bool shouldResistFingerprinting =
    145      aWorkerPrivate->ShouldResistFingerprinting(RFPTarget::NetworkConnection);
    146  RefPtr<ConnectionWorker> c = new ConnectionWorker(shouldResistFingerprinting);
    147  c->mProxy = ConnectionProxy::Create(aWorkerPrivate, c);
    148  if (!c->mProxy) {
    149    aRv.ThrowTypeError("The Worker thread is shutting down.");
    150    return nullptr;
    151  }
    152 
    153  hal::NetworkInformation networkInfo;
    154  RefPtr<InitializeRunnable> runnable =
    155      new InitializeRunnable(aWorkerPrivate, c->mProxy, networkInfo);
    156 
    157  runnable->Dispatch(aWorkerPrivate, Canceling, aRv);
    158  if (NS_WARN_IF(aRv.Failed())) {
    159    return nullptr;
    160  }
    161 
    162  c->Update(static_cast<ConnectionType>(networkInfo.type()),
    163            networkInfo.isWifi(), networkInfo.dhcpGateway(), false);
    164  return c.forget();
    165 }
    166 
    167 ConnectionWorker::ConnectionWorker(bool aShouldResistFingerprinting)
    168    : Connection(nullptr, aShouldResistFingerprinting) {
    169  MOZ_ASSERT(IsCurrentThreadRunningWorker());
    170 }
    171 
    172 ConnectionWorker::~ConnectionWorker() { Shutdown(); }
    173 
    174 void ConnectionWorker::ShutdownInternal() {
    175  MOZ_ASSERT(IsCurrentThreadRunningWorker());
    176  mProxy->Shutdown();
    177 }
    178 
    179 void ConnectionProxy::Notify(const hal::NetworkInformation& aNetworkInfo) {
    180  MOZ_ASSERT(NS_IsMainThread());
    181 
    182  RefPtr<NotifyRunnable> runnable =
    183      new NotifyRunnable(mWorkerRef->Private(), this,
    184                         static_cast<ConnectionType>(aNetworkInfo.type()),
    185                         aNetworkInfo.isWifi(), aNetworkInfo.dhcpGateway());
    186  runnable->Dispatch(mWorkerRef->Private());
    187 }
    188 
    189 void ConnectionProxy::Shutdown() {
    190  MOZ_ASSERT(IsCurrentThreadRunningWorker());
    191 
    192  // Already shut down.
    193  if (!mConnection) {
    194    return;
    195  }
    196 
    197  mConnection = nullptr;
    198 
    199  RefPtr<ShutdownRunnable> runnable =
    200      new ShutdownRunnable(mWorkerRef->Private(), this);
    201 
    202  ErrorResult rv;
    203  // This runnable _must_ be executed.
    204  runnable->Dispatch(mWorkerRef->Private(), Killing, rv);
    205  if (NS_WARN_IF(rv.Failed())) {
    206    rv.SuppressException();
    207  }
    208 
    209  mWorkerRef = nullptr;
    210 }
    211 
    212 }  // namespace mozilla::dom::network