Tickler.cpp 5.9 KB

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