netwerk/base/src/Tickler.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/. */
     6 #include "Tickler.h"
     8 #ifdef MOZ_USE_WIFI_TICKLER
     9 #include "nsComponentManagerUtils.h"
    10 #include "nsIPrefBranch.h"
    11 #include "nsIPrefService.h"
    12 #include "nsServiceManagerUtils.h"
    13 #include "nsThreadUtils.h"
    14 #include "prnetdb.h"
    16 #include "AndroidBridge.h"
    18 namespace mozilla {
    19 namespace net {
    21 NS_IMPL_ISUPPORTS(Tickler, nsISupportsWeakReference, Tickler)
    23 Tickler::Tickler()
    24     : mLock("Tickler::mLock")
    25     , mActive(false)
    26     , mCanceled(false)
    27     , mEnabled(false)
    28     , mDelay(16)
    29     , mDuration(TimeDuration::FromMilliseconds(400))
    30     , mFD(nullptr)
    31 {
    32   MOZ_ASSERT(NS_IsMainThread());
    33 }
    35 class TicklerThreadDestructor  : public nsRunnable
    36 {
    37 public:
    38   explicit TicklerThreadDestructor(nsIThread *aThread)
    39     : mThread(aThread) { }
    41   NS_IMETHOD Run() MOZ_OVERRIDE
    42   {
    43     MOZ_ASSERT(NS_IsMainThread());
    44     if (mThread)
    45       mThread->Shutdown();
    46     return NS_OK;
    47   }
    49 private:
    50   ~TicklerThreadDestructor() { }
    51   nsCOMPtr<nsIThread> mThread;
    52 };
    54 Tickler::~Tickler()
    55 {
    56   // non main thread uses of the tickler should hold weak
    57   // references to it if they must hold a reference at all
    58   MOZ_ASSERT(NS_IsMainThread());
    60   // Shutting down a thread can spin the event loop - which is a surprising
    61   // thing to do from a dtor. Running it on its own event is safer.
    62   nsRefPtr<nsIRunnable> event = new TicklerThreadDestructor(mThread);
    63   if (NS_FAILED(NS_DispatchToCurrentThread(event))) {
    64     mThread->Shutdown();
    65   }
    66   mThread = nullptr;
    68   if (mTimer)
    69     mTimer->Cancel();
    70   if (mFD)
    71     PR_Close(mFD);
    72 }
    74 nsresult
    75 Tickler::Init()
    76 {
    77   MOZ_ASSERT(NS_IsMainThread());
    78   MOZ_ASSERT(!mTimer);
    79   MOZ_ASSERT(!mActive);
    80   MOZ_ASSERT(!mThread);
    81   MOZ_ASSERT(!mFD);
    83   if (AndroidBridge::HasEnv()) {
    84       mozilla::widget::android::GeckoAppShell::EnableNetworkNotifications();
    85   }
    87   mFD = PR_OpenUDPSocket(PR_AF_INET);
    88   if (!mFD)
    89     return NS_ERROR_FAILURE;
    91   // make sure new socket has a ttl of 1
    92   // failure is not fatal.
    93   PRSocketOptionData opt;
    94   opt.option = PR_SockOpt_IpTimeToLive;
    95   opt.value.ip_ttl = 1;
    96   PR_SetSocketOption(mFD, &opt);
    98   nsresult rv = NS_NewNamedThread("wifi tickler",
    99                                   getter_AddRefs(mThread));
   100   if (NS_FAILED(rv))
   101     return rv;
   103   nsCOMPtr<nsITimer> tmpTimer(do_CreateInstance(NS_TIMER_CONTRACTID, &rv));
   104   if (NS_FAILED(rv))
   105     return rv;
   107   rv = tmpTimer->SetTarget(mThread);
   108   if (NS_FAILED(rv))
   109     return rv;
   111   mTimer.swap(tmpTimer);
   113   mAddr.inet.family = PR_AF_INET;
   114   mAddr.inet.port = PR_htons (4886);
   115   mAddr.inet.ip = 0;
   117   return NS_OK;
   118 }
   120 void Tickler::Tickle()
   121 {
   122   MutexAutoLock lock(mLock);
   123   MOZ_ASSERT(mThread);
   124   mLastTickle = TimeStamp::Now();
   125   if (!mActive)
   126     MaybeStartTickler();
   127 }
   129 void Tickler::PostCheckTickler()
   130 {
   131   mLock.AssertCurrentThreadOwns();
   132   mThread->Dispatch(NS_NewRunnableMethod(this, &Tickler::CheckTickler),
   133                     NS_DISPATCH_NORMAL);
   134   return;
   135 }
   137 void Tickler::MaybeStartTicklerUnlocked()
   138 {
   139   MutexAutoLock lock(mLock);
   140   MaybeStartTickler();
   141 }
   143 void Tickler::MaybeStartTickler()
   144 {
   145   mLock.AssertCurrentThreadOwns();
   146   if (!NS_IsMainThread()) {
   147     NS_DispatchToMainThread(
   148       NS_NewRunnableMethod(this, &Tickler::MaybeStartTicklerUnlocked),
   149       NS_DISPATCH_NORMAL);
   150     return;
   151   }
   153   if (!mPrefs)
   154     mPrefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
   155   if (mPrefs) {
   156     int32_t val;
   157     bool boolVal;
   159     if (NS_SUCCEEDED(mPrefs->GetBoolPref("network.tickle-wifi.enabled", &boolVal)))
   160       mEnabled = boolVal;
   162     if (NS_SUCCEEDED(mPrefs->GetIntPref("network.tickle-wifi.duration", &val))) {
   163       if (val < 1)
   164         val = 1;
   165       if (val > 100000)
   166         val = 100000;
   167       mDuration = TimeDuration::FromMilliseconds(val);
   168     }
   170     if (NS_SUCCEEDED(mPrefs->GetIntPref("network.tickle-wifi.delay", &val))) {
   171       if (val < 1)
   172         val = 1;
   173       if (val > 1000)
   174         val = 1000;
   175       mDelay = static_cast<uint32_t>(val);
   176     }
   177   }
   179   PostCheckTickler();
   180 }
   182 void Tickler::CheckTickler()
   183 {
   184   MutexAutoLock lock(mLock);
   185   MOZ_ASSERT(mThread == NS_GetCurrentThread());
   187   bool shouldRun = (!mCanceled) &&
   188     ((TimeStamp::Now() - mLastTickle) <= mDuration);
   190   if ((shouldRun && mActive) || (!shouldRun && !mActive))
   191     return; // no change in state
   193   if (mActive)
   194     StopTickler();
   195   else
   196     StartTickler();
   197 }
   199 void Tickler::Cancel()
   200 {
   201   MutexAutoLock lock(mLock);
   202   MOZ_ASSERT(NS_IsMainThread());
   203   mCanceled = true;
   204   if (mThread)
   205     PostCheckTickler();
   206 }
   208 void Tickler::StopTickler()
   209 {
   210   mLock.AssertCurrentThreadOwns();
   211   MOZ_ASSERT(mThread == NS_GetCurrentThread());
   212   MOZ_ASSERT(mTimer);
   213   MOZ_ASSERT(mActive);
   215   mTimer->Cancel();
   216   mActive = false;
   217 }
   219 class TicklerTimer MOZ_FINAL : public nsITimerCallback
   220 {
   221   NS_DECL_THREADSAFE_ISUPPORTS
   222   NS_DECL_NSITIMERCALLBACK
   224   TicklerTimer(Tickler *aTickler)
   225   {
   226     mTickler = do_GetWeakReference(aTickler);
   227   }
   229   ~TicklerTimer() {};
   231 private:
   232   nsWeakPtr mTickler;
   233 };
   235 void Tickler::StartTickler()
   236 {
   237   mLock.AssertCurrentThreadOwns();
   238   MOZ_ASSERT(mThread == NS_GetCurrentThread());
   239   MOZ_ASSERT(!mActive);
   240   MOZ_ASSERT(mTimer);
   242   if (NS_SUCCEEDED(mTimer->InitWithCallback(new TicklerTimer(this),
   243                                             mEnabled ? mDelay : 1000,
   244                                             nsITimer::TYPE_REPEATING_SLACK)))
   245     mActive = true;
   246 }
   248 // argument should be in network byte order
   249 void Tickler::SetIPV4Address(uint32_t address)
   250 {
   251   mAddr.inet.ip = address;
   252 }
   254 // argument should be in network byte order
   255 void Tickler::SetIPV4Port(uint16_t port)
   256 {
   257   mAddr.inet.port = port;
   258 }
   260 NS_IMPL_ISUPPORTS(TicklerTimer, nsITimerCallback)
   262 NS_IMETHODIMP TicklerTimer::Notify(nsITimer *timer)
   263 {
   264   nsRefPtr<Tickler> tickler = do_QueryReferent(mTickler);
   265   if (!tickler)
   266     return NS_ERROR_FAILURE;
   267   MutexAutoLock lock(tickler->mLock);
   269   if (!tickler->mFD) {
   270     tickler->StopTickler();
   271     return NS_ERROR_FAILURE;
   272   }
   274   if (tickler->mCanceled ||
   275       ((TimeStamp::Now() - tickler->mLastTickle) > tickler->mDuration)) {
   276     tickler->StopTickler();
   277     return NS_OK;
   278   }
   280   if (!tickler->mEnabled)
   281     return NS_OK;
   283   PR_SendTo(tickler->mFD, "", 0, 0, &tickler->mAddr, 0);
   284   return NS_OK;
   285 }
   287 } // namespace mozilla::net
   288 } // namespace mozilla
   290 #else // not defined MOZ_USE_WIFI_TICKLER
   292 namespace mozilla {
   293 namespace net {
   294 NS_IMPL_ISUPPORTS0(Tickler)
   295 } // namespace mozilla::net
   296 } // namespace mozilla
   298 #endif // defined MOZ_USE_WIFI_TICKLER

mercurial