RilSocket.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
  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 "RilSocket.h"
  6. #include <fcntl.h>
  7. #include "mozilla/dom/workers/Workers.h"
  8. #include "mozilla/ipc/UnixSocketConnector.h"
  9. #include "mozilla/RefPtr.h"
  10. #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, MOZ_COUNT_DTOR
  11. #include "nsXULAppAPI.h"
  12. #include "RilSocketConsumer.h"
  13. #include "mozilla/Unused.h"
  14. static const size_t MAX_READ_SIZE = 1 << 16;
  15. namespace mozilla {
  16. namespace ipc {
  17. USING_WORKERS_NAMESPACE
  18. //
  19. // RilSocketIO
  20. //
  21. class RilSocketIO final : public ConnectionOrientedSocketIO
  22. {
  23. public:
  24. class ConnectTask;
  25. class DelayedConnectTask;
  26. class ReceiveTask;
  27. RilSocketIO(WorkerCrossThreadDispatcher* aDispatcher,
  28. MessageLoop* aConsumerLoop,
  29. MessageLoop* aIOLoop,
  30. RilSocket* aRilSocket,
  31. UnixSocketConnector* aConnector);
  32. ~RilSocketIO();
  33. RilSocket* GetRilSocket();
  34. DataSocket* GetDataSocket();
  35. // Delayed-task handling
  36. //
  37. void SetDelayedConnectTask(CancelableRunnable* aTask);
  38. void ClearDelayedConnectTask();
  39. void CancelDelayedConnectTask();
  40. // Methods for |DataSocket|
  41. //
  42. nsresult QueryReceiveBuffer(UnixSocketIOBuffer** aBuffer) override;
  43. void ConsumeBuffer() override;
  44. void DiscardBuffer() override;
  45. // Methods for |SocketIOBase|
  46. //
  47. SocketBase* GetSocketBase() override;
  48. bool IsShutdownOnConsumerThread() const override;
  49. bool IsShutdownOnIOThread() const override;
  50. void ShutdownOnConsumerThread() override;
  51. void ShutdownOnIOThread() override;
  52. private:
  53. /**
  54. * Cross-thread dispatcher for the RIL worker
  55. */
  56. RefPtr<WorkerCrossThreadDispatcher> mDispatcher;
  57. /**
  58. * Consumer pointer. Non-thread safe RefPtr, so should only be manipulated
  59. * directly from consumer thread. All non-consumer-thread accesses should
  60. * happen with mIO as container.
  61. */
  62. RefPtr<RilSocket> mRilSocket;
  63. /**
  64. * If true, do not requeue whatever task we're running
  65. */
  66. bool mShuttingDownOnIOThread;
  67. /**
  68. * Task member for delayed connect task. Should only be access on consumer
  69. * thread.
  70. */
  71. CancelableRunnable* mDelayedConnectTask;
  72. /**
  73. * I/O buffer for received data
  74. */
  75. UniquePtr<UnixSocketRawData> mBuffer;
  76. };
  77. RilSocketIO::RilSocketIO(WorkerCrossThreadDispatcher* aDispatcher,
  78. MessageLoop* aConsumerLoop,
  79. MessageLoop* aIOLoop,
  80. RilSocket* aRilSocket,
  81. UnixSocketConnector* aConnector)
  82. : ConnectionOrientedSocketIO(aConsumerLoop, aIOLoop, aConnector)
  83. , mDispatcher(aDispatcher)
  84. , mRilSocket(aRilSocket)
  85. , mShuttingDownOnIOThread(false)
  86. , mDelayedConnectTask(nullptr)
  87. {
  88. MOZ_ASSERT(mDispatcher);
  89. MOZ_ASSERT(mRilSocket);
  90. MOZ_COUNT_CTOR_INHERITED(RilSocketIO, ConnectionOrientedSocketIO);
  91. }
  92. RilSocketIO::~RilSocketIO()
  93. {
  94. MOZ_ASSERT(IsConsumerThread());
  95. MOZ_ASSERT(IsShutdownOnConsumerThread());
  96. MOZ_COUNT_DTOR_INHERITED(RilSocketIO, ConnectionOrientedSocketIO);
  97. }
  98. RilSocket*
  99. RilSocketIO::GetRilSocket()
  100. {
  101. return mRilSocket.get();
  102. }
  103. DataSocket*
  104. RilSocketIO::GetDataSocket()
  105. {
  106. return mRilSocket.get();
  107. }
  108. void
  109. RilSocketIO::SetDelayedConnectTask(CancelableRunnable* aTask)
  110. {
  111. MOZ_ASSERT(IsConsumerThread());
  112. mDelayedConnectTask = aTask;
  113. }
  114. void
  115. RilSocketIO::ClearDelayedConnectTask()
  116. {
  117. MOZ_ASSERT(IsConsumerThread());
  118. mDelayedConnectTask = nullptr;
  119. }
  120. void
  121. RilSocketIO::CancelDelayedConnectTask()
  122. {
  123. MOZ_ASSERT(IsConsumerThread());
  124. if (!mDelayedConnectTask) {
  125. return;
  126. }
  127. mDelayedConnectTask->Cancel();
  128. ClearDelayedConnectTask();
  129. }
  130. // |DataSocketIO|
  131. nsresult
  132. RilSocketIO::QueryReceiveBuffer(UnixSocketIOBuffer** aBuffer)
  133. {
  134. MOZ_ASSERT(aBuffer);
  135. if (!mBuffer) {
  136. mBuffer = MakeUnique<UnixSocketRawData>(MAX_READ_SIZE);
  137. }
  138. *aBuffer = mBuffer.get();
  139. return NS_OK;
  140. }
  141. /**
  142. * |ReceiveTask| transfers data received on the I/O thread
  143. * to an instance of |RilSocket| on the consumer thread.
  144. */
  145. class RilSocketIO::ReceiveTask final : public WorkerTask
  146. {
  147. public:
  148. ReceiveTask(RilSocketIO* aIO, UnixSocketBuffer* aBuffer)
  149. : mIO(aIO)
  150. , mBuffer(aBuffer)
  151. {
  152. MOZ_ASSERT(mIO);
  153. }
  154. bool RunTask(JSContext* aCx) override
  155. {
  156. // Dispatched via WCTD, but still needs to run on the consumer thread
  157. MOZ_ASSERT(mIO->IsConsumerThread());
  158. if (NS_WARN_IF(mIO->IsShutdownOnConsumerThread())) {
  159. // Since we've already explicitly closed and the close
  160. // happened before this, this isn't really an error.
  161. return true;
  162. }
  163. RilSocket* rilSocket = mIO->GetRilSocket();
  164. MOZ_ASSERT(rilSocket);
  165. rilSocket->ReceiveSocketData(aCx, mBuffer);
  166. return true;
  167. }
  168. private:
  169. RilSocketIO* mIO;
  170. UniquePtr<UnixSocketBuffer> mBuffer;
  171. };
  172. void
  173. RilSocketIO::ConsumeBuffer()
  174. {
  175. RefPtr<ReceiveTask> task = new ReceiveTask(this, mBuffer.release());
  176. Unused << NS_WARN_IF(!mDispatcher->PostTask(task));
  177. }
  178. void
  179. RilSocketIO::DiscardBuffer()
  180. {
  181. // Nothing to do.
  182. }
  183. // |SocketIOBase|
  184. SocketBase*
  185. RilSocketIO::GetSocketBase()
  186. {
  187. return GetDataSocket();
  188. }
  189. bool
  190. RilSocketIO::IsShutdownOnConsumerThread() const
  191. {
  192. MOZ_ASSERT(IsConsumerThread());
  193. return mRilSocket == nullptr;
  194. }
  195. bool
  196. RilSocketIO::IsShutdownOnIOThread() const
  197. {
  198. return mShuttingDownOnIOThread;
  199. }
  200. void
  201. RilSocketIO::ShutdownOnConsumerThread()
  202. {
  203. MOZ_ASSERT(IsConsumerThread());
  204. MOZ_ASSERT(!IsShutdownOnConsumerThread());
  205. mRilSocket = nullptr;
  206. }
  207. void
  208. RilSocketIO::ShutdownOnIOThread()
  209. {
  210. MOZ_ASSERT(!IsConsumerThread());
  211. MOZ_ASSERT(!mShuttingDownOnIOThread);
  212. Close(); // will also remove fd from I/O loop
  213. mShuttingDownOnIOThread = true;
  214. }
  215. //
  216. // Socket tasks
  217. //
  218. class RilSocketIO::ConnectTask final
  219. : public SocketIOTask<RilSocketIO>
  220. {
  221. public:
  222. ConnectTask(RilSocketIO* aIO)
  223. : SocketIOTask<RilSocketIO>(aIO)
  224. { }
  225. NS_IMETHOD Run() override
  226. {
  227. MOZ_ASSERT(!GetIO()->IsConsumerThread());
  228. MOZ_ASSERT(!IsCanceled());
  229. GetIO()->Connect();
  230. return NS_OK;
  231. }
  232. };
  233. class RilSocketIO::DelayedConnectTask final
  234. : public SocketIOTask<RilSocketIO>
  235. {
  236. public:
  237. DelayedConnectTask(RilSocketIO* aIO)
  238. : SocketIOTask<RilSocketIO>(aIO)
  239. { }
  240. NS_IMETHOD Run() override
  241. {
  242. MOZ_ASSERT(GetIO()->IsConsumerThread());
  243. if (IsCanceled()) {
  244. return NS_OK;
  245. }
  246. RilSocketIO* io = GetIO();
  247. if (io->IsShutdownOnConsumerThread()) {
  248. return NS_OK;
  249. }
  250. io->ClearDelayedConnectTask();
  251. io->GetIOLoop()->PostTask(MakeAndAddRef<ConnectTask>(io));
  252. return NS_OK;
  253. }
  254. };
  255. //
  256. // RilSocket
  257. //
  258. RilSocket::RilSocket(WorkerCrossThreadDispatcher* aDispatcher,
  259. RilSocketConsumer* aConsumer, int aIndex)
  260. : mIO(nullptr)
  261. , mDispatcher(aDispatcher)
  262. , mConsumer(aConsumer)
  263. , mIndex(aIndex)
  264. {
  265. MOZ_ASSERT(mDispatcher);
  266. MOZ_ASSERT(mConsumer);
  267. MOZ_COUNT_CTOR_INHERITED(RilSocket, ConnectionOrientedSocket);
  268. }
  269. RilSocket::~RilSocket()
  270. {
  271. MOZ_ASSERT(!mIO);
  272. MOZ_COUNT_DTOR_INHERITED(RilSocket, ConnectionOrientedSocket);
  273. }
  274. void
  275. RilSocket::ReceiveSocketData(JSContext* aCx,
  276. UniquePtr<UnixSocketBuffer>& aBuffer)
  277. {
  278. mConsumer->ReceiveSocketData(aCx, mIndex, aBuffer);
  279. }
  280. nsresult
  281. RilSocket::Connect(UnixSocketConnector* aConnector, int aDelayMs,
  282. MessageLoop* aConsumerLoop, MessageLoop* aIOLoop)
  283. {
  284. MOZ_ASSERT(!mIO);
  285. mIO = new RilSocketIO(mDispatcher, aConsumerLoop, aIOLoop, this, aConnector);
  286. SetConnectionStatus(SOCKET_CONNECTING);
  287. if (aDelayMs > 0) {
  288. RefPtr<RilSocketIO::DelayedConnectTask> connectTask =
  289. MakeAndAddRef<RilSocketIO::DelayedConnectTask>(mIO);
  290. mIO->SetDelayedConnectTask(connectTask);
  291. MessageLoop::current()->PostDelayedTask(connectTask.forget(), aDelayMs);
  292. } else {
  293. aIOLoop->PostTask(MakeAndAddRef<RilSocketIO::ConnectTask>(mIO));
  294. }
  295. return NS_OK;
  296. }
  297. nsresult
  298. RilSocket::Connect(UnixSocketConnector* aConnector, int aDelayMs)
  299. {
  300. return Connect(aConnector, aDelayMs,
  301. MessageLoop::current(), XRE_GetIOMessageLoop());
  302. }
  303. // |ConnectionOrientedSocket|
  304. nsresult
  305. RilSocket::PrepareAccept(UnixSocketConnector* aConnector,
  306. MessageLoop* aConsumerLoop,
  307. MessageLoop* aIOLoop,
  308. ConnectionOrientedSocketIO*& aIO)
  309. {
  310. MOZ_CRASH("|RilSocket| does not support accepting connections.");
  311. }
  312. // |DataSocket|
  313. void
  314. RilSocket::SendSocketData(UnixSocketIOBuffer* aBuffer)
  315. {
  316. MOZ_ASSERT(mIO);
  317. MOZ_ASSERT(mIO->IsConsumerThread());
  318. MOZ_ASSERT(!mIO->IsShutdownOnConsumerThread());
  319. mIO->GetIOLoop()->PostTask(
  320. MakeAndAddRef<SocketIOSendTask<RilSocketIO, UnixSocketIOBuffer>>(mIO, aBuffer));
  321. }
  322. // |SocketBase|
  323. void
  324. RilSocket::Close()
  325. {
  326. MOZ_ASSERT(mIO);
  327. MOZ_ASSERT(mIO->IsConsumerThread());
  328. mIO->CancelDelayedConnectTask();
  329. // From this point on, we consider |mIO| as being deleted. We sever
  330. // the relationship here so any future calls to |Connect| will create
  331. // a new I/O object.
  332. mIO->ShutdownOnConsumerThread();
  333. mIO->GetIOLoop()->PostTask(MakeAndAddRef<SocketIOShutdownTask>(mIO));
  334. mIO = nullptr;
  335. NotifyDisconnect();
  336. }
  337. void
  338. RilSocket::OnConnectSuccess()
  339. {
  340. mConsumer->OnConnectSuccess(mIndex);
  341. }
  342. void
  343. RilSocket::OnConnectError()
  344. {
  345. mConsumer->OnConnectError(mIndex);
  346. }
  347. void
  348. RilSocket::OnDisconnect()
  349. {
  350. mConsumer->OnDisconnect(mIndex);
  351. }
  352. } // namespace ipc
  353. } // namespace mozilla