123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446 |
- /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "RilSocket.h"
- #include <fcntl.h>
- #include "mozilla/dom/workers/Workers.h"
- #include "mozilla/ipc/UnixSocketConnector.h"
- #include "mozilla/RefPtr.h"
- #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, MOZ_COUNT_DTOR
- #include "nsXULAppAPI.h"
- #include "RilSocketConsumer.h"
- #include "mozilla/Unused.h"
- static const size_t MAX_READ_SIZE = 1 << 16;
- namespace mozilla {
- namespace ipc {
- USING_WORKERS_NAMESPACE
- //
- // RilSocketIO
- //
- class RilSocketIO final : public ConnectionOrientedSocketIO
- {
- public:
- class ConnectTask;
- class DelayedConnectTask;
- class ReceiveTask;
- RilSocketIO(WorkerCrossThreadDispatcher* aDispatcher,
- MessageLoop* aConsumerLoop,
- MessageLoop* aIOLoop,
- RilSocket* aRilSocket,
- UnixSocketConnector* aConnector);
- ~RilSocketIO();
- RilSocket* GetRilSocket();
- DataSocket* GetDataSocket();
- // Delayed-task handling
- //
- void SetDelayedConnectTask(CancelableRunnable* aTask);
- void ClearDelayedConnectTask();
- void CancelDelayedConnectTask();
- // Methods for |DataSocket|
- //
- nsresult QueryReceiveBuffer(UnixSocketIOBuffer** aBuffer) override;
- void ConsumeBuffer() override;
- void DiscardBuffer() override;
- // Methods for |SocketIOBase|
- //
- SocketBase* GetSocketBase() override;
- bool IsShutdownOnConsumerThread() const override;
- bool IsShutdownOnIOThread() const override;
- void ShutdownOnConsumerThread() override;
- void ShutdownOnIOThread() override;
- private:
- /**
- * Cross-thread dispatcher for the RIL worker
- */
- RefPtr<WorkerCrossThreadDispatcher> mDispatcher;
- /**
- * Consumer pointer. Non-thread safe RefPtr, so should only be manipulated
- * directly from consumer thread. All non-consumer-thread accesses should
- * happen with mIO as container.
- */
- RefPtr<RilSocket> mRilSocket;
- /**
- * If true, do not requeue whatever task we're running
- */
- bool mShuttingDownOnIOThread;
- /**
- * Task member for delayed connect task. Should only be access on consumer
- * thread.
- */
- CancelableRunnable* mDelayedConnectTask;
- /**
- * I/O buffer for received data
- */
- UniquePtr<UnixSocketRawData> mBuffer;
- };
- RilSocketIO::RilSocketIO(WorkerCrossThreadDispatcher* aDispatcher,
- MessageLoop* aConsumerLoop,
- MessageLoop* aIOLoop,
- RilSocket* aRilSocket,
- UnixSocketConnector* aConnector)
- : ConnectionOrientedSocketIO(aConsumerLoop, aIOLoop, aConnector)
- , mDispatcher(aDispatcher)
- , mRilSocket(aRilSocket)
- , mShuttingDownOnIOThread(false)
- , mDelayedConnectTask(nullptr)
- {
- MOZ_ASSERT(mDispatcher);
- MOZ_ASSERT(mRilSocket);
- MOZ_COUNT_CTOR_INHERITED(RilSocketIO, ConnectionOrientedSocketIO);
- }
- RilSocketIO::~RilSocketIO()
- {
- MOZ_ASSERT(IsConsumerThread());
- MOZ_ASSERT(IsShutdownOnConsumerThread());
- MOZ_COUNT_DTOR_INHERITED(RilSocketIO, ConnectionOrientedSocketIO);
- }
- RilSocket*
- RilSocketIO::GetRilSocket()
- {
- return mRilSocket.get();
- }
- DataSocket*
- RilSocketIO::GetDataSocket()
- {
- return mRilSocket.get();
- }
- void
- RilSocketIO::SetDelayedConnectTask(CancelableRunnable* aTask)
- {
- MOZ_ASSERT(IsConsumerThread());
- mDelayedConnectTask = aTask;
- }
- void
- RilSocketIO::ClearDelayedConnectTask()
- {
- MOZ_ASSERT(IsConsumerThread());
- mDelayedConnectTask = nullptr;
- }
- void
- RilSocketIO::CancelDelayedConnectTask()
- {
- MOZ_ASSERT(IsConsumerThread());
- if (!mDelayedConnectTask) {
- return;
- }
- mDelayedConnectTask->Cancel();
- ClearDelayedConnectTask();
- }
- // |DataSocketIO|
- nsresult
- RilSocketIO::QueryReceiveBuffer(UnixSocketIOBuffer** aBuffer)
- {
- MOZ_ASSERT(aBuffer);
- if (!mBuffer) {
- mBuffer = MakeUnique<UnixSocketRawData>(MAX_READ_SIZE);
- }
- *aBuffer = mBuffer.get();
- return NS_OK;
- }
- /**
- * |ReceiveTask| transfers data received on the I/O thread
- * to an instance of |RilSocket| on the consumer thread.
- */
- class RilSocketIO::ReceiveTask final : public WorkerTask
- {
- public:
- ReceiveTask(RilSocketIO* aIO, UnixSocketBuffer* aBuffer)
- : mIO(aIO)
- , mBuffer(aBuffer)
- {
- MOZ_ASSERT(mIO);
- }
- bool RunTask(JSContext* aCx) override
- {
- // Dispatched via WCTD, but still needs to run on the consumer thread
- MOZ_ASSERT(mIO->IsConsumerThread());
- if (NS_WARN_IF(mIO->IsShutdownOnConsumerThread())) {
- // Since we've already explicitly closed and the close
- // happened before this, this isn't really an error.
- return true;
- }
- RilSocket* rilSocket = mIO->GetRilSocket();
- MOZ_ASSERT(rilSocket);
- rilSocket->ReceiveSocketData(aCx, mBuffer);
- return true;
- }
- private:
- RilSocketIO* mIO;
- UniquePtr<UnixSocketBuffer> mBuffer;
- };
- void
- RilSocketIO::ConsumeBuffer()
- {
- RefPtr<ReceiveTask> task = new ReceiveTask(this, mBuffer.release());
- Unused << NS_WARN_IF(!mDispatcher->PostTask(task));
- }
- void
- RilSocketIO::DiscardBuffer()
- {
- // Nothing to do.
- }
- // |SocketIOBase|
- SocketBase*
- RilSocketIO::GetSocketBase()
- {
- return GetDataSocket();
- }
- bool
- RilSocketIO::IsShutdownOnConsumerThread() const
- {
- MOZ_ASSERT(IsConsumerThread());
- return mRilSocket == nullptr;
- }
- bool
- RilSocketIO::IsShutdownOnIOThread() const
- {
- return mShuttingDownOnIOThread;
- }
- void
- RilSocketIO::ShutdownOnConsumerThread()
- {
- MOZ_ASSERT(IsConsumerThread());
- MOZ_ASSERT(!IsShutdownOnConsumerThread());
- mRilSocket = nullptr;
- }
- void
- RilSocketIO::ShutdownOnIOThread()
- {
- MOZ_ASSERT(!IsConsumerThread());
- MOZ_ASSERT(!mShuttingDownOnIOThread);
- Close(); // will also remove fd from I/O loop
- mShuttingDownOnIOThread = true;
- }
- //
- // Socket tasks
- //
- class RilSocketIO::ConnectTask final
- : public SocketIOTask<RilSocketIO>
- {
- public:
- ConnectTask(RilSocketIO* aIO)
- : SocketIOTask<RilSocketIO>(aIO)
- { }
- NS_IMETHOD Run() override
- {
- MOZ_ASSERT(!GetIO()->IsConsumerThread());
- MOZ_ASSERT(!IsCanceled());
- GetIO()->Connect();
- return NS_OK;
- }
- };
- class RilSocketIO::DelayedConnectTask final
- : public SocketIOTask<RilSocketIO>
- {
- public:
- DelayedConnectTask(RilSocketIO* aIO)
- : SocketIOTask<RilSocketIO>(aIO)
- { }
- NS_IMETHOD Run() override
- {
- MOZ_ASSERT(GetIO()->IsConsumerThread());
- if (IsCanceled()) {
- return NS_OK;
- }
- RilSocketIO* io = GetIO();
- if (io->IsShutdownOnConsumerThread()) {
- return NS_OK;
- }
- io->ClearDelayedConnectTask();
- io->GetIOLoop()->PostTask(MakeAndAddRef<ConnectTask>(io));
- return NS_OK;
- }
- };
- //
- // RilSocket
- //
- RilSocket::RilSocket(WorkerCrossThreadDispatcher* aDispatcher,
- RilSocketConsumer* aConsumer, int aIndex)
- : mIO(nullptr)
- , mDispatcher(aDispatcher)
- , mConsumer(aConsumer)
- , mIndex(aIndex)
- {
- MOZ_ASSERT(mDispatcher);
- MOZ_ASSERT(mConsumer);
- MOZ_COUNT_CTOR_INHERITED(RilSocket, ConnectionOrientedSocket);
- }
- RilSocket::~RilSocket()
- {
- MOZ_ASSERT(!mIO);
- MOZ_COUNT_DTOR_INHERITED(RilSocket, ConnectionOrientedSocket);
- }
- void
- RilSocket::ReceiveSocketData(JSContext* aCx,
- UniquePtr<UnixSocketBuffer>& aBuffer)
- {
- mConsumer->ReceiveSocketData(aCx, mIndex, aBuffer);
- }
- nsresult
- RilSocket::Connect(UnixSocketConnector* aConnector, int aDelayMs,
- MessageLoop* aConsumerLoop, MessageLoop* aIOLoop)
- {
- MOZ_ASSERT(!mIO);
- mIO = new RilSocketIO(mDispatcher, aConsumerLoop, aIOLoop, this, aConnector);
- SetConnectionStatus(SOCKET_CONNECTING);
- if (aDelayMs > 0) {
- RefPtr<RilSocketIO::DelayedConnectTask> connectTask =
- MakeAndAddRef<RilSocketIO::DelayedConnectTask>(mIO);
- mIO->SetDelayedConnectTask(connectTask);
- MessageLoop::current()->PostDelayedTask(connectTask.forget(), aDelayMs);
- } else {
- aIOLoop->PostTask(MakeAndAddRef<RilSocketIO::ConnectTask>(mIO));
- }
- return NS_OK;
- }
- nsresult
- RilSocket::Connect(UnixSocketConnector* aConnector, int aDelayMs)
- {
- return Connect(aConnector, aDelayMs,
- MessageLoop::current(), XRE_GetIOMessageLoop());
- }
- // |ConnectionOrientedSocket|
- nsresult
- RilSocket::PrepareAccept(UnixSocketConnector* aConnector,
- MessageLoop* aConsumerLoop,
- MessageLoop* aIOLoop,
- ConnectionOrientedSocketIO*& aIO)
- {
- MOZ_CRASH("|RilSocket| does not support accepting connections.");
- }
- // |DataSocket|
- void
- RilSocket::SendSocketData(UnixSocketIOBuffer* aBuffer)
- {
- MOZ_ASSERT(mIO);
- MOZ_ASSERT(mIO->IsConsumerThread());
- MOZ_ASSERT(!mIO->IsShutdownOnConsumerThread());
- mIO->GetIOLoop()->PostTask(
- MakeAndAddRef<SocketIOSendTask<RilSocketIO, UnixSocketIOBuffer>>(mIO, aBuffer));
- }
- // |SocketBase|
- void
- RilSocket::Close()
- {
- MOZ_ASSERT(mIO);
- MOZ_ASSERT(mIO->IsConsumerThread());
- mIO->CancelDelayedConnectTask();
- // From this point on, we consider |mIO| as being deleted. We sever
- // the relationship here so any future calls to |Connect| will create
- // a new I/O object.
- mIO->ShutdownOnConsumerThread();
- mIO->GetIOLoop()->PostTask(MakeAndAddRef<SocketIOShutdownTask>(mIO));
- mIO = nullptr;
- NotifyDisconnect();
- }
- void
- RilSocket::OnConnectSuccess()
- {
- mConsumer->OnConnectSuccess(mIndex);
- }
- void
- RilSocket::OnConnectError()
- {
- mConsumer->OnConnectError(mIndex);
- }
- void
- RilSocket::OnDisconnect()
- {
- mConsumer->OnDisconnect(mIndex);
- }
- } // namespace ipc
- } // namespace mozilla
|