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