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/. */
8 #ifdef MOZ_USE_WIFI_TICKLER
9 # include "nsComponentManagerUtils.h"
10 # include "nsINamed.h"
11 # include "nsServiceManagerUtils.h"
12 # include "nsThreadUtils.h"
15 # include "mozilla/java/GeckoAppShellWrappers.h"
16 # include "mozilla/jni/Utils.h"
21 NS_IMPL_ISUPPORTS(Tickler
, nsISupportsWeakReference
, Tickler
)
24 : mLock("Tickler::mLock"),
29 mDuration(TimeDuration::FromMilliseconds(400)),
31 MOZ_ASSERT(NS_IsMainThread());
35 // non main thread uses of the tickler should hold weak
36 // references to it if they must hold a reference at all
37 MOZ_ASSERT(NS_IsMainThread());
40 mThread
->AsyncShutdown();
44 if (mTimer
) mTimer
->Cancel();
45 if (mFD
) PR_Close(mFD
);
48 nsresult
Tickler::Init() {
49 if (!XRE_IsParentProcess()) {
50 return NS_ERROR_FAILURE
;
53 MOZ_ASSERT(NS_IsMainThread());
59 if (jni::IsAvailable()) {
60 java::GeckoAppShell::EnableNetworkNotifications();
63 mFD
= PR_OpenUDPSocket(PR_AF_INET
);
64 if (!mFD
) return NS_ERROR_FAILURE
;
66 // make sure new socket has a ttl of 1
67 // failure is not fatal.
68 PRSocketOptionData opt
;
69 opt
.option
= PR_SockOpt_IpTimeToLive
;
71 PR_SetSocketOption(mFD
, &opt
);
73 nsresult rv
= NS_NewNamedThread("wifi tickler", getter_AddRefs(mThread
));
74 if (NS_FAILED(rv
)) return rv
;
76 nsCOMPtr
<nsITimer
> tmpTimer
= NS_NewTimer(mThread
);
77 if (!tmpTimer
) return NS_ERROR_OUT_OF_MEMORY
;
79 mTimer
.swap(tmpTimer
);
81 mAddr
.inet
.family
= PR_AF_INET
;
82 mAddr
.inet
.port
= PR_htons(4886);
88 void Tickler::Tickle() {
89 MutexAutoLock
lock(mLock
);
91 mLastTickle
= TimeStamp::Now();
92 if (!mActive
) MaybeStartTickler();
95 void Tickler::PostCheckTickler() {
96 mLock
.AssertCurrentThreadOwns();
97 mThread
->Dispatch(NewRunnableMethod("net::Tickler::CheckTickler", this,
98 &Tickler::CheckTickler
),
103 void Tickler::MaybeStartTicklerUnlocked() {
104 MutexAutoLock
lock(mLock
);
108 void Tickler::MaybeStartTickler() {
109 mLock
.AssertCurrentThreadOwns();
110 if (!NS_IsMainThread()) {
111 NS_DispatchToMainThread(
112 NewRunnableMethod("net::Tickler::MaybeStartTicklerUnlocked", this,
113 &Tickler::MaybeStartTicklerUnlocked
));
117 if (!mPrefs
) mPrefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
123 mPrefs
->GetBoolPref("network.tickle-wifi.enabled", &boolVal
)))
127 mPrefs
->GetIntPref("network.tickle-wifi.duration", &val
))) {
128 if (val
< 1) val
= 1;
129 if (val
> 100000) val
= 100000;
130 mDuration
= TimeDuration::FromMilliseconds(val
);
133 if (NS_SUCCEEDED(mPrefs
->GetIntPref("network.tickle-wifi.delay", &val
))) {
134 if (val
< 1) val
= 1;
135 if (val
> 1000) val
= 1000;
136 mDelay
= static_cast<uint32_t>(val
);
143 void Tickler::CheckTickler() {
144 MutexAutoLock
lock(mLock
);
145 MOZ_ASSERT(mThread
== NS_GetCurrentThread());
148 (!mCanceled
) && ((TimeStamp::Now() - mLastTickle
) <= mDuration
);
150 if ((shouldRun
&& mActive
) || (!shouldRun
&& !mActive
))
151 return; // no change in state
159 void Tickler::Cancel() {
160 MutexAutoLock
lock(mLock
);
161 MOZ_ASSERT(NS_IsMainThread());
163 if (mThread
) PostCheckTickler();
166 void Tickler::StopTickler() {
167 mLock
.AssertCurrentThreadOwns();
168 MOZ_ASSERT(mThread
== NS_GetCurrentThread());
176 class TicklerTimer final
: public nsITimerCallback
, public nsINamed
{
177 NS_DECL_THREADSAFE_ISUPPORTS
178 NS_DECL_NSITIMERCALLBACK
180 explicit TicklerTimer(Tickler
* aTickler
) {
181 mTickler
= do_GetWeakReference(aTickler
);
185 NS_IMETHOD
GetName(nsACString
& aName
) override
{
186 aName
.AssignLiteral("TicklerTimer");
196 void Tickler::StartTickler() {
197 mLock
.AssertCurrentThreadOwns();
198 MOZ_ASSERT(mThread
== NS_GetCurrentThread());
199 MOZ_ASSERT(!mActive
);
202 if (NS_SUCCEEDED(mTimer
->InitWithCallback(new TicklerTimer(this),
203 mEnabled
? mDelay
: 1000,
204 nsITimer::TYPE_REPEATING_SLACK
)))
208 // argument should be in network byte order
209 void Tickler::SetIPV4Address(uint32_t address
) { mAddr
.inet
.ip
= address
; }
211 // argument should be in network byte order
212 void Tickler::SetIPV4Port(uint16_t port
) { mAddr
.inet
.port
= port
; }
214 NS_IMPL_ISUPPORTS(TicklerTimer
, nsITimerCallback
, nsINamed
)
216 NS_IMETHODIMP
TicklerTimer::Notify(nsITimer
* timer
) {
217 RefPtr
<Tickler
> tickler
= do_QueryReferent(mTickler
);
218 if (!tickler
) return NS_ERROR_FAILURE
;
219 MutexAutoLock
lock(tickler
->mLock
);
222 tickler
->StopTickler();
223 return NS_ERROR_FAILURE
;
226 if (tickler
->mCanceled
||
227 ((TimeStamp::Now() - tickler
->mLastTickle
) > tickler
->mDuration
)) {
228 tickler
->StopTickler();
232 if (!tickler
->mEnabled
) return NS_OK
;
234 PR_SendTo(tickler
->mFD
, "", 0, 0, &tickler
->mAddr
, 0);
239 } // namespace mozilla
241 #else // not defined MOZ_USE_WIFI_TICKLER
245 NS_IMPL_ISUPPORTS0(Tickler
)
247 } // namespace mozilla
249 #endif // defined MOZ_USE_WIFI_TICKLER