tor-browser

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

Tickler.cpp (6362B)


      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 "Tickler.h"
      7 
      8 #ifdef MOZ_USE_WIFI_TICKLER
      9 #  include "nsComponentManagerUtils.h"
     10 #  include "nsINamed.h"
     11 #  include "nsIPrefService.h"
     12 #  include "nsServiceManagerUtils.h"
     13 #  include "nsThreadUtils.h"
     14 #  include "prnetdb.h"
     15 #  include "nsXULAppAPI.h"
     16 #  include "nsIPrefService.h"
     17 #  include "nsIPrefBranch.h"
     18 
     19 #  include "mozilla/java/GeckoAppShellWrappers.h"
     20 #  include "mozilla/jni/Utils.h"
     21 #  include "nsXULAppAPI.h"
     22 
     23 namespace mozilla {
     24 namespace net {
     25 
     26 NS_IMPL_ISUPPORTS(Tickler, nsISupportsWeakReference, Tickler)
     27 
     28 Tickler::Tickler()
     29    : mLock("Tickler::mLock"),
     30      mActive(false),
     31      mCanceled(false),
     32      mEnabled(false),
     33      mDelay(16),
     34      mDuration(TimeDuration::FromMilliseconds(400)),
     35      mFD(nullptr) {
     36  MOZ_ASSERT(NS_IsMainThread());
     37 }
     38 
     39 Tickler::~Tickler() {
     40  // non main thread uses of the tickler should hold weak
     41  // references to it if they must hold a reference at all
     42  MOZ_ASSERT(NS_IsMainThread());
     43 
     44  if (mThread) {
     45    mThread->AsyncShutdown();
     46    mThread = nullptr;
     47  }
     48 
     49  if (mTimer) mTimer->Cancel();
     50  if (mFD) PR_Close(mFD);
     51 }
     52 
     53 nsresult Tickler::Init() {
     54  if (!XRE_IsParentProcess()) {
     55    return NS_ERROR_FAILURE;
     56  }
     57 
     58  MOZ_ASSERT(NS_IsMainThread());
     59  MOZ_ASSERT(!mTimer);
     60  MOZ_ASSERT(!mActive);
     61  MOZ_ASSERT(!mThread);
     62  MOZ_ASSERT(!mFD);
     63 
     64  if (jni::IsAvailable()) {
     65    java::GeckoAppShell::EnableNetworkNotifications();
     66  }
     67 
     68  mFD = PR_OpenUDPSocket(PR_AF_INET);
     69  if (!mFD) return NS_ERROR_FAILURE;
     70 
     71  // make sure new socket has a ttl of 1
     72  // failure is not fatal.
     73  PRSocketOptionData opt;
     74  opt.option = PR_SockOpt_IpTimeToLive;
     75  opt.value.ip_ttl = 1;
     76  PR_SetSocketOption(mFD, &opt);
     77 
     78  nsresult rv = NS_NewNamedThread("wifi tickler", getter_AddRefs(mThread));
     79  if (NS_FAILED(rv)) return rv;
     80 
     81  nsCOMPtr<nsITimer> tmpTimer = NS_NewTimer(mThread);
     82  if (!tmpTimer) return NS_ERROR_OUT_OF_MEMORY;
     83 
     84  mTimer.swap(tmpTimer);
     85 
     86  mAddr.inet.family = PR_AF_INET;
     87  mAddr.inet.port = PR_htons(4886);
     88  mAddr.inet.ip = 0;
     89 
     90  return NS_OK;
     91 }
     92 
     93 void Tickler::Tickle() {
     94  MutexAutoLock lock(mLock);
     95  MOZ_ASSERT(mThread);
     96  mLastTickle = TimeStamp::Now();
     97  if (!mActive) MaybeStartTickler();
     98 }
     99 
    100 void Tickler::PostCheckTickler() {
    101  mLock.AssertCurrentThreadOwns();
    102  mThread->Dispatch(NewRunnableMethod("net::Tickler::CheckTickler", this,
    103                                      &Tickler::CheckTickler),
    104                    NS_DISPATCH_NORMAL);
    105  return;
    106 }
    107 
    108 void Tickler::MaybeStartTicklerUnlocked() {
    109  MutexAutoLock lock(mLock);
    110  MaybeStartTickler();
    111 }
    112 
    113 void Tickler::MaybeStartTickler() {
    114  mLock.AssertCurrentThreadOwns();
    115  if (!NS_IsMainThread()) {
    116    NS_DispatchToMainThread(
    117        NewRunnableMethod("net::Tickler::MaybeStartTicklerUnlocked", this,
    118                          &Tickler::MaybeStartTicklerUnlocked));
    119    return;
    120  }
    121 
    122  if (!mPrefs) mPrefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
    123  if (mPrefs) {
    124    int32_t val;
    125    bool boolVal;
    126 
    127    if (NS_SUCCEEDED(
    128            mPrefs->GetBoolPref("network.tickle-wifi.enabled", &boolVal)))
    129      mEnabled = boolVal;
    130 
    131    if (NS_SUCCEEDED(
    132            mPrefs->GetIntPref("network.tickle-wifi.duration", &val))) {
    133      if (val < 1) val = 1;
    134      if (val > 100000) val = 100000;
    135      mDuration = TimeDuration::FromMilliseconds(val);
    136    }
    137 
    138    if (NS_SUCCEEDED(mPrefs->GetIntPref("network.tickle-wifi.delay", &val))) {
    139      if (val < 1) val = 1;
    140      if (val > 1000) val = 1000;
    141      mDelay = static_cast<uint32_t>(val);
    142    }
    143  }
    144 
    145  PostCheckTickler();
    146 }
    147 
    148 void Tickler::CheckTickler() {
    149  MutexAutoLock lock(mLock);
    150  MOZ_ASSERT(mThread == NS_GetCurrentThread());
    151 
    152  bool shouldRun =
    153      (!mCanceled) && ((TimeStamp::Now() - mLastTickle) <= mDuration);
    154 
    155  if ((shouldRun && mActive) || (!shouldRun && !mActive))
    156    return;  // no change in state
    157 
    158  if (mActive)
    159    StopTickler();
    160  else
    161    StartTickler();
    162 }
    163 
    164 void Tickler::Cancel() {
    165  MutexAutoLock lock(mLock);
    166  MOZ_ASSERT(NS_IsMainThread());
    167  mCanceled = true;
    168  if (mThread) PostCheckTickler();
    169 }
    170 
    171 void Tickler::StopTickler() {
    172  mLock.AssertCurrentThreadOwns();
    173  MOZ_ASSERT(mThread == NS_GetCurrentThread());
    174  MOZ_ASSERT(mTimer);
    175  MOZ_ASSERT(mActive);
    176 
    177  mTimer->Cancel();
    178  mActive = false;
    179 }
    180 
    181 class TicklerTimer final : public nsITimerCallback, public nsINamed {
    182  NS_DECL_THREADSAFE_ISUPPORTS
    183  NS_DECL_NSITIMERCALLBACK
    184 
    185  explicit TicklerTimer(Tickler* aTickler) {
    186    mTickler = do_GetWeakReference(aTickler);
    187  }
    188 
    189  // nsINamed
    190  NS_IMETHOD GetName(nsACString& aName) override {
    191    aName.AssignLiteral("TicklerTimer");
    192    return NS_OK;
    193  }
    194 
    195 private:
    196  ~TicklerTimer() {}
    197 
    198  nsWeakPtr mTickler;
    199 };
    200 
    201 void Tickler::StartTickler() {
    202  mLock.AssertCurrentThreadOwns();
    203  MOZ_ASSERT(mThread == NS_GetCurrentThread());
    204  MOZ_ASSERT(!mActive);
    205  MOZ_ASSERT(mTimer);
    206 
    207  auto tickler = MakeRefPtr<TicklerTimer>(this);
    208  if (NS_SUCCEEDED(mTimer->InitWithCallback(tickler, mEnabled ? mDelay : 1000,
    209                                            nsITimer::TYPE_REPEATING_SLACK)))
    210    mActive = true;
    211 }
    212 
    213 // argument should be in network byte order
    214 void Tickler::SetIPV4Address(uint32_t address) { mAddr.inet.ip = address; }
    215 
    216 // argument should be in network byte order
    217 void Tickler::SetIPV4Port(uint16_t port) { mAddr.inet.port = port; }
    218 
    219 NS_IMPL_ISUPPORTS(TicklerTimer, nsITimerCallback, nsINamed)
    220 
    221 NS_IMETHODIMP TicklerTimer::Notify(nsITimer* timer) {
    222  RefPtr<Tickler> tickler = do_QueryReferent(mTickler);
    223  if (!tickler) return NS_ERROR_FAILURE;
    224  MutexAutoLock lock(tickler->mLock);
    225 
    226  if (!tickler->mFD) {
    227    tickler->StopTickler();
    228    return NS_ERROR_FAILURE;
    229  }
    230 
    231  if (tickler->mCanceled ||
    232      ((TimeStamp::Now() - tickler->mLastTickle) > tickler->mDuration)) {
    233    tickler->StopTickler();
    234    return NS_OK;
    235  }
    236 
    237  if (!tickler->mEnabled) return NS_OK;
    238 
    239  PR_SendTo(tickler->mFD, "", 0, 0, &tickler->mAddr, 0);
    240  return NS_OK;
    241 }
    242 
    243 }  // namespace net
    244 }  // namespace mozilla
    245 
    246 #else  // not defined MOZ_USE_WIFI_TICKLER
    247 
    248 namespace mozilla {
    249 namespace net {
    250 NS_IMPL_ISUPPORTS0(Tickler)
    251 }  // namespace net
    252 }  // namespace mozilla
    253 
    254 #endif  // defined MOZ_USE_WIFI_TICKLER