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

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

mercurial