diff options
Diffstat (limited to 'ipc/unixsocket/SocketBase.h')
-rw-r--r-- | ipc/unixsocket/SocketBase.h | 585 |
1 files changed, 585 insertions, 0 deletions
diff --git a/ipc/unixsocket/SocketBase.h b/ipc/unixsocket/SocketBase.h new file mode 100644 index 0000000000..191567fdb9 --- /dev/null +++ b/ipc/unixsocket/SocketBase.h @@ -0,0 +1,585 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ + +/* 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/. + */ + +#ifndef mozilla_ipc_SocketBase_h +#define mozilla_ipc_SocketBase_h + +#include "base/message_loop.h" +#include "mozilla/UniquePtr.h" + +namespace mozilla { +namespace ipc { + +// +// UnixSocketBuffer +// + +/** + * |UnixSocketBuffer| implements a FIFO buffer that stores raw socket + * data, either for sending on a socket or received from a socket. + */ +class UnixSocketBuffer +{ +public: + virtual ~UnixSocketBuffer(); + + const uint8_t* GetData() const + { + return mData + mOffset; + } + + size_t GetSize() const + { + return mSize - mOffset; + } + + const uint8_t* Consume(size_t aLen); + + nsresult Read(void* aValue, size_t aLen); + + nsresult Read(int8_t& aValue) + { + return Read(&aValue, sizeof(aValue)); + } + + nsresult Read(uint8_t& aValue) + { + return Read(&aValue, sizeof(aValue)); + } + + nsresult Read(int16_t& aValue) + { + return Read(&aValue, sizeof(aValue)); + } + + nsresult Read(uint16_t& aValue) + { + return Read(&aValue, sizeof(aValue)); + } + + nsresult Read(int32_t& aValue) + { + return Read(&aValue, sizeof(aValue)); + } + + nsresult Read(uint32_t& aValue) + { + return Read(&aValue, sizeof(aValue)); + } + + nsresult Read(int64_t& aValue) + { + return Read(&aValue, sizeof(aValue)); + } + + nsresult Read(uint64_t& aValue) + { + return Read(&aValue, sizeof(aValue)); + } + + nsresult Read(float& aValue) + { + return Read(&aValue, sizeof(aValue)); + } + + nsresult Read(double& aValue) + { + return Read(&aValue, sizeof(aValue)); + } + + uint8_t* Append(size_t aLen); + + nsresult Write(const void* aValue, size_t aLen); + + nsresult Write(int8_t aValue) + { + return Write(&aValue, sizeof(aValue)); + } + + nsresult Write(uint8_t aValue) + { + return Write(&aValue, sizeof(aValue)); + } + + nsresult Write(int16_t aValue) + { + return Write(&aValue, sizeof(aValue)); + } + + nsresult Write(uint16_t aValue) + { + return Write(&aValue, sizeof(aValue)); + } + + nsresult Write(int32_t aValue) + { + return Write(&aValue, sizeof(aValue)); + } + + nsresult Write(uint32_t aValue) + { + return Write(&aValue, sizeof(aValue)); + } + + nsresult Write(int64_t aValue) + { + return Write(&aValue, sizeof(aValue)); + } + + nsresult Write(uint64_t aValue) + { + return Write(&aValue, sizeof(aValue)); + } + + nsresult Write(float aValue) + { + return Write(&aValue, sizeof(aValue)); + } + + nsresult Write(double aValue) + { + return Write(&aValue, sizeof(aValue)); + } + +protected: + UnixSocketBuffer(); + + /** + * Sets the raw memory. The caller is responsible for freeing + * this memory. + * + * @param aData A pointer to the buffer's raw memory. + * @param aOffset The start of valid bytes in |aData|. + * @param aSize The number of valid bytes in |aData|. + * @param aAvailableSpace The number of bytes in |aData|. + */ + void ResetBuffer(uint8_t* aData, + size_t aOffset, size_t aSize, size_t aAvailableSpace) + { + MOZ_ASSERT(aData || !aAvailableSpace); + MOZ_ASSERT((aOffset + aSize) <= aAvailableSpace); + + mOffset = aOffset; + mSize = aSize; + mAvailableSpace = aAvailableSpace; + mData = aData; + } + + /** + * Retrieves the memory buffer. + * + * @return A pointer to the buffer's raw memory. + */ + uint8_t* GetBuffer() + { + return mData; + } + + size_t GetLeadingSpace() const + { + return mOffset; + } + + size_t GetTrailingSpace() const + { + return mAvailableSpace - mSize; + } + + size_t GetAvailableSpace() const + { + return mAvailableSpace; + } + + void* GetTrailingBytes() + { + return mData + mSize; + } + + uint8_t* GetData(size_t aOffset) + { + MOZ_ASSERT(aOffset <= mSize); + + return mData + aOffset; + } + + void SetRange(size_t aOffset, size_t aSize) + { + MOZ_ASSERT((aOffset + aSize) <= mAvailableSpace); + + mOffset = aOffset; + mSize = mOffset + aSize; + } + + void CleanupLeadingSpace(); + +private: + size_t mSize; + size_t mOffset; + size_t mAvailableSpace; + uint8_t* mData; +}; + +// +// UnixSocketIOBuffer +// + +/** + * |UnixSocketIOBuffer| is a |UnixSocketBuffer| that supports being + * received on a socket or being send on a socket. Network protocols + * might differ in their exact usage of Unix socket functions and + * |UnixSocketIOBuffer| provides a protocol-neutral interface. + */ +class UnixSocketIOBuffer : public UnixSocketBuffer +{ +public: + UnixSocketIOBuffer(); + virtual ~UnixSocketIOBuffer(); + + /** + * Receives data from aFd at the end of the buffer. The returned value + * is the number of newly received bytes, or 0 if the peer shut down + * its connection, or a negative value on errors. + */ + virtual ssize_t Receive(int aFd) = 0; + + /** + * Sends data to aFd from the beginning of the buffer. The returned value + * is the number of bytes written, or a negative value on error. + */ + virtual ssize_t Send(int aFd) = 0; +}; + +// +// UnixSocketRawData +// + +class UnixSocketRawData final : public UnixSocketIOBuffer +{ +public: + /** + * This constructor copies aData of aSize bytes length into the + * new instance of |UnixSocketRawData|. + * + * @param aData The buffer to copy. + * @param aSize The number of bytes in |aData|. + */ + UnixSocketRawData(const void* aData, size_t aSize); + + /** + * This constructor takes ownership of the data in aData. The + * data is assumed to be aSize bytes in length. + * + * @param aData The buffer to take ownership of. + * @param aSize The number of bytes in |aData|. + */ + UnixSocketRawData(UniquePtr<uint8_t[]> aData, size_t aSize); + + /** + * This constructor reserves aSize bytes of space. Currently + * it's only possible to fill this buffer by calling |Receive|. + * + * @param aSize The number of bytes to allocate. + */ + UnixSocketRawData(size_t aSize); + + /** + * The destructor releases the buffer's raw memory. + */ + ~UnixSocketRawData(); + + /** + * Receives data from aFd at the end of the buffer. The returned value + * is the number of newly received bytes, or 0 if the peer shut down + * its connection, or a negative value on errors. + */ + ssize_t Receive(int aFd) override; + + /** + * Sends data to aFd from the beginning of the buffer. The returned value + * is the number of bytes written, or a negative value on error. + */ + ssize_t Send(int aFd) override; +}; + +enum SocketConnectionStatus { + SOCKET_DISCONNECTED = 0, + SOCKET_LISTENING = 1, + SOCKET_CONNECTING = 2, + SOCKET_CONNECTED = 3 +}; + +// +// SocketBase +// + +class SocketBase +{ +public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SocketBase) + + SocketConnectionStatus GetConnectionStatus() const; + + int GetSuggestedConnectDelayMs() const; + + /** + * Queues the internal representation of socket for deletion. Can be called + * from consumer thread. + */ + virtual void Close() = 0; + + /** + * Callback for socket connect/accept success. Called after connect/accept has + * finished. Will be run on consumer thread before any reads take place. + */ + virtual void OnConnectSuccess() = 0; + + /** + * Callback for socket connect/accept error. Will be run on consumer thread. + */ + virtual void OnConnectError() = 0; + + /** + * Callback for socket disconnect. Will be run on consumer thread. + */ + virtual void OnDisconnect() = 0; + + /** + * Called by implementation to notify consumer of success. + */ + void NotifySuccess(); + + /** + * Called by implementation to notify consumer of error. + */ + void NotifyError(); + + /** + * Called by implementation to notify consumer of disconnect. + */ + void NotifyDisconnect(); + +protected: + SocketBase(); + virtual ~SocketBase(); + + void SetConnectionStatus(SocketConnectionStatus aConnectionStatus); + +private: + uint32_t CalculateConnectDelayMs() const; + + SocketConnectionStatus mConnectionStatus; + PRIntervalTime mConnectTimestamp; + uint32_t mConnectDelayMs; +}; + +// +// SocketIOBase +// + +/** + * |SocketIOBase| is a base class for Socket I/O classes that + * perform operations on the I/O thread. + */ +class SocketIOBase +{ +public: + virtual ~SocketIOBase(); + + /** + * Implemented by socket I/O classes to return the current instance of + * |SocketBase|. + * + * @return The current instance of |SocketBase| + */ + virtual SocketBase* GetSocketBase() = 0; + + /** + * Implemented by socket I/O classes to signal that the socket I/O class has + * been shut down. + * + * @return True if the socket I/O class has been shut down, false otherwise. + */ + virtual bool IsShutdownOnIOThread() const = 0; + + /** + * Implemented by socket I/O classes to signal that socket class has + * been shut down. + * + * @return True if the socket class has been shut down, false otherwise. + */ + virtual bool IsShutdownOnConsumerThread() const = 0; + + /** + * Signals to the socket I/O classes that it has been shut down. + */ + virtual void ShutdownOnIOThread() = 0; + + /** + * Signals to the socket I/O classes that the socket class has been + * shut down. + */ + virtual void ShutdownOnConsumerThread() = 0; + + /** + * Returns the consumer thread. + * + * @return A pointer to the consumer thread. + */ + MessageLoop* GetConsumerThread() const; + + /** + * @return True if the current thread is the consumer thread, or false + * otherwise. + */ + bool IsConsumerThread() const; + +protected: + SocketIOBase(MessageLoop* aConsumerLoop); + +private: + MessageLoop* mConsumerLoop; +}; + +// +// Socket tasks +// + +/* |SocketTask| is a task for sending a message from + * the I/O thread to the consumer thread. + */ +template <typename T> +class SocketTask : public CancelableRunnable +{ +public: + virtual ~SocketTask() + { } + + T* GetIO() const + { + return mIO; + } + +protected: + SocketTask(T* aIO) + : mIO(aIO) + { + MOZ_ASSERT(aIO); + } + +private: + T* mIO; +}; + +/** + * |SocketEventTask| reports the connection state on the + * I/O thread back to the consumer thread. + */ +class SocketEventTask final : public SocketTask<SocketIOBase> +{ +public: + enum SocketEvent { + CONNECT_SUCCESS, + CONNECT_ERROR, + DISCONNECT + }; + + SocketEventTask(SocketIOBase* aIO, SocketEvent aEvent); + ~SocketEventTask(); + + NS_IMETHOD Run() override; + +private: + SocketEvent mEvent; +}; + +/** + * |SocketRequestClosingTask| closes an instance of |SocketBase| + * on the consumer thread. + */ +class SocketRequestClosingTask final : public SocketTask<SocketIOBase> +{ +public: + SocketRequestClosingTask(SocketIOBase* aIO); + ~SocketRequestClosingTask(); + + NS_IMETHOD Run() override; +}; + +/** + * |SocketDeleteInstanceTask| deletes an object on the consumer thread. + */ +class SocketDeleteInstanceTask final : public Runnable +{ +public: + SocketDeleteInstanceTask(SocketIOBase* aIO); + ~SocketDeleteInstanceTask(); + + NS_IMETHOD Run() override; + +private: + UniquePtr<SocketIOBase> mIO; +}; + +// +// Socket I/O tasks +// + +/* |SocketIOTask| holds a reference to a Socket I/O object. It's + * supposed to run on the I/O thread. + */ +template<typename Tio> +class SocketIOTask : public CancelableRunnable +{ +public: + virtual ~SocketIOTask() + { } + + Tio* GetIO() const + { + return mIO; + } + + nsresult Cancel() override + { + mIO = nullptr; + return NS_OK; + } + + bool IsCanceled() const + { + return !mIO; + } + +protected: + SocketIOTask(Tio* aIO) + : mIO(aIO) + { + MOZ_ASSERT(mIO); + } + +private: + Tio* mIO; +}; + +/** + * |SocketIOShutdownTask| signals shutdown to the socket I/O class on + * the I/O thread and sends it to the consumer thread for destruction. + */ +class SocketIOShutdownTask final : public SocketIOTask<SocketIOBase> +{ +public: + SocketIOShutdownTask(SocketIOBase* aIO); + ~SocketIOShutdownTask(); + + NS_IMETHOD Run() override; +}; + +} +} + +#endif |