From 3126a07df493057078bebcbac0bf02ec611b5092 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 15 Jun 2015 14:44:03 +0200 Subject: [PATCH] Bug 1171017: Move classes from ipc/bluetooth to ipc/hal, r=shuang The class |DaemonSocket| and its helpers implement a service- neutral connection to a HAL daemon. This patch moves the code to an appropriate directory and breaks up the code into smaller pieces. --HG-- rename : ipc/bluetooth/BluetoothDaemonConnection.cpp => ipc/hal/DaemonSocket.cpp rename : ipc/bluetooth/BluetoothDaemonConnection.h => ipc/hal/DaemonSocket.h rename : ipc/bluetooth/BluetoothDaemonConnectionConsumer.cpp => ipc/hal/DaemonSocketConsumer.cpp rename : ipc/bluetooth/BluetoothDaemonConnectionConsumer.h => ipc/hal/DaemonSocketConsumer.h rename : ipc/bluetooth/moz.build => ipc/hal/moz.build --- .../bluedroid/BluetoothDaemonHelpers.h | 2 +- .../bluedroid/BluetoothDaemonInterface.cpp | 1 + .../bluedroid/BluetoothDaemonInterface.h | 2 +- ipc/bluetooth/BluetoothDaemonConnection.h | 156 -------------- .../DaemonSocket.cpp} | 191 +----------------- ipc/hal/DaemonSocket.h | 63 ++++++ .../DaemonSocketConsumer.cpp} | 12 +- .../DaemonSocketConsumer.h} | 30 ++- ipc/hal/DaemonSocketPDU.cpp | 188 +++++++++++++++++ ipc/hal/DaemonSocketPDU.h | 91 +++++++++ ipc/{bluetooth => hal}/moz.build | 12 +- ipc/moz.build | 5 +- 12 files changed, 390 insertions(+), 363 deletions(-) delete mode 100644 ipc/bluetooth/BluetoothDaemonConnection.h rename ipc/{bluetooth/BluetoothDaemonConnection.cpp => hal/DaemonSocket.cpp} (52%) create mode 100644 ipc/hal/DaemonSocket.h rename ipc/{bluetooth/BluetoothDaemonConnectionConsumer.cpp => hal/DaemonSocketConsumer.cpp} (73%) rename ipc/{bluetooth/BluetoothDaemonConnectionConsumer.h => hal/DaemonSocketConsumer.h} (68%) create mode 100644 ipc/hal/DaemonSocketPDU.cpp create mode 100644 ipc/hal/DaemonSocketPDU.h rename ipc/{bluetooth => hal}/moz.build (70%) diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h b/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h index 18e3786335816..3b31d7c3bb84a 100644 --- a/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h +++ b/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h @@ -10,7 +10,7 @@ #include "BluetoothCommon.h" #include "mozilla/ArrayUtils.h" #include "mozilla/dom/bluetooth/BluetoothTypes.h" -#include "mozilla/ipc/BluetoothDaemonConnection.h" +#include "mozilla/ipc/DaemonSocketPDU.h" #include "nsThreadUtils.h" using namespace mozilla::ipc; diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp b/dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp index 0052e0d840941..3f22be1422afa 100644 --- a/dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp +++ b/dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp @@ -17,6 +17,7 @@ #include "BluetoothDaemonSetupInterface.h" #include "BluetoothDaemonSocketInterface.h" #include "BluetoothInterfaceHelpers.h" +#include "mozilla/ipc/DaemonSocket.h" #include "mozilla/ipc/ListenSocket.h" #include "mozilla/unused.h" #include "prrng.h" diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonInterface.h b/dom/bluetooth/bluedroid/BluetoothDaemonInterface.h index 891e3ebda048e..1d2b33610032c 100644 --- a/dom/bluetooth/bluedroid/BluetoothDaemonInterface.h +++ b/dom/bluetooth/bluedroid/BluetoothDaemonInterface.h @@ -8,7 +8,7 @@ #define mozilla_dom_bluetooth_bluedroid_bluetoothdaemoninterface_h__ #include "BluetoothInterface.h" -#include "mozilla/ipc/BluetoothDaemonConnectionConsumer.h" +#include "mozilla/ipc/DaemonSocketConsumer.h" #include "mozilla/ipc/ListenSocketConsumer.h" namespace mozilla { diff --git a/ipc/bluetooth/BluetoothDaemonConnection.h b/ipc/bluetooth/BluetoothDaemonConnection.h deleted file mode 100644 index cc13de03eb3b8..0000000000000 --- a/ipc/bluetooth/BluetoothDaemonConnection.h +++ /dev/null @@ -1,156 +0,0 @@ -/* -*- 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_bluetooth_DaemonSocket_h -#define mozilla_ipc_bluetooth_DaemonSocket_h - -#include "mozilla/Attributes.h" -#include "mozilla/FileUtils.h" -#include "mozilla/ipc/ConnectionOrientedSocket.h" -#include "nsAutoPtr.h" - -class MessageLoop; - -namespace mozilla { -namespace ipc { - -class DaemonSocketConsumer; -class DaemonSocketIO; -class DaemonSocketIOConsumer; - -/* - * |DaemonSocketPDU| represents a single PDU that is transfered from or to - * the Bluetooth daemon. Each PDU contains exactly one command. - * - * A PDU as the following format - * - * | 1 | 1 | 2 | n | - * | service | opcode | payload length | payload | - * - * Service and Opcode each require 1 byte, the payload length requires 2 - * bytes, and the payload requires the number of bytes as stored in the - * payload-length field. - * - * Each service and opcode can have a different payload with individual - * length. For the exact details of the Bluetooth protocol, please refer - * to - * - * https://git.kernel.org/cgit/bluetooth/bluez.git/tree/android/hal-ipc-api.txt?id=5.24 - * - */ -class DaemonSocketPDU final : public UnixSocketIOBuffer -{ -public: - enum { - OFF_SERVICE = 0, - OFF_OPCODE = 1, - OFF_LENGTH = 2, - OFF_PAYLOAD = 4, - HEADER_SIZE = OFF_PAYLOAD, - MAX_PAYLOAD_LENGTH = 1 << 16 - }; - - DaemonSocketPDU(uint8_t aService, uint8_t aOpcode, - uint16_t aPayloadSize); - DaemonSocketPDU(size_t aPayloadSize); - ~DaemonSocketPDU(); - - void SetConsumer(DaemonSocketIOConsumer* aConsumer) - { - mConsumer = aConsumer; - } - - void SetUserData(void* aUserData) - { - mUserData = aUserData; - } - - void* GetUserData() const - { - return mUserData; - } - - void GetHeader(uint8_t& aService, uint8_t& aOpcode, - uint16_t& aPayloadSize); - - ssize_t Send(int aFd) override; - ssize_t Receive(int aFd) override; - - int AcquireFd(); - - nsresult UpdateHeader(); - -private: - size_t GetPayloadSize() const; - void OnError(const char* aFunction, int aErrno); - - DaemonSocketIOConsumer* mConsumer; - void* mUserData; - ScopedClose mReceivedFd; -}; - -/* - * |DaemonSocketIOConsumer| processes incoming PDUs from the Bluetooth - * daemon. Please note that its method |Handle| runs on a different than the - * consumer thread. - */ -class DaemonSocketIOConsumer -{ -public: - virtual ~DaemonSocketIOConsumer(); - - virtual void Handle(DaemonSocketPDU& aPDU) = 0; - virtual void StoreUserData(const DaemonSocketPDU& aPDU) = 0; - -protected: - DaemonSocketIOConsumer(); -}; - -/* - * |DaemonSocket| represents the socket to connect to the - * Bluetooth daemon. It offers connection establishment and sending - * PDUs. PDU receiving is performed by |DaemonSocketIOConsumer|. - */ -class DaemonSocket : public ConnectionOrientedSocket -{ -public: - DaemonSocket(DaemonSocketIOConsumer* aIOConsumer, - DaemonSocketConsumer* aConsumer, - int aIndex); - virtual ~DaemonSocket(); - - // Methods for |ConnectionOrientedSocket| - // - - nsresult PrepareAccept(UnixSocketConnector* aConnector, - MessageLoop* aConsumerLoop, - MessageLoop* aIOLoop, - ConnectionOrientedSocketIO*& aIO) override; - - // Methods for |DataSocket| - // - - void SendSocketData(UnixSocketIOBuffer* aBuffer) override; - - // Methods for |SocketBase| - // - - void Close() override; - void OnConnectSuccess() override; - void OnConnectError() override; - void OnDisconnect() override; - -private: - DaemonSocketIO* mIO; - DaemonSocketIOConsumer* mIOConsumer; - DaemonSocketConsumer* mConsumer; - int mIndex; -}; - -} -} - -#endif diff --git a/ipc/bluetooth/BluetoothDaemonConnection.cpp b/ipc/hal/DaemonSocket.cpp similarity index 52% rename from ipc/bluetooth/BluetoothDaemonConnection.cpp rename to ipc/hal/DaemonSocket.cpp index 9661e21d5de44..26f62a08a782b 100644 --- a/ipc/bluetooth/BluetoothDaemonConnection.cpp +++ b/ipc/hal/DaemonSocket.cpp @@ -4,16 +4,9 @@ * 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 "BluetoothDaemonConnection.h" -#include -#include -#include -#include -#include -#include "mozilla/ipc/BluetoothDaemonConnectionConsumer.h" -#include "mozilla/ipc/DataSocket.h" -#include "nsTArray.h" -#include "nsXULAppAPI.h" +#include "DaemonSocket.h" +#include "mozilla/ipc/DaemonSocketConsumer.h" +#include "mozilla/ipc/DaemonSocketPDU.h" #ifdef CHROMIUM_LOG #undef CHROMIUM_LOG @@ -31,182 +24,6 @@ namespace mozilla { namespace ipc { -// The connection to the Bluetooth daemon is established -// using an abstract socket name. The \0 prefix will be added -// by the |Connect| method. -static const char sBluetoothdSocketName[] = "bluez_hal_socket"; - -// -// DaemonSocketPDU -// - -DaemonSocketPDU::DaemonSocketPDU(uint8_t aService, uint8_t aOpcode, - uint16_t aPayloadSize) - : mConsumer(nullptr) - , mUserData(nullptr) -{ - // Allocate memory - size_t availableSpace = HEADER_SIZE + aPayloadSize; - ResetBuffer(new uint8_t[availableSpace], 0, 0, availableSpace); - - // Reserve PDU header - uint8_t* data = Append(HEADER_SIZE); - MOZ_ASSERT(data); - - // Setup PDU header - data[OFF_SERVICE] = aService; - data[OFF_OPCODE] = aOpcode; - memcpy(data + OFF_LENGTH, &aPayloadSize, sizeof(aPayloadSize)); -} - -DaemonSocketPDU::DaemonSocketPDU(size_t aPayloadSize) - : mConsumer(nullptr) - , mUserData(nullptr) -{ - size_t availableSpace = HEADER_SIZE + aPayloadSize; - ResetBuffer(new uint8_t[availableSpace], 0, 0, availableSpace); -} - -DaemonSocketPDU::~DaemonSocketPDU() -{ - nsAutoArrayPtr data(GetBuffer()); - ResetBuffer(nullptr, 0, 0, 0); -} - -void -DaemonSocketPDU::GetHeader(uint8_t& aService, uint8_t& aOpcode, - uint16_t& aPayloadSize) -{ - memcpy(&aService, GetData(OFF_SERVICE), sizeof(aService)); - memcpy(&aOpcode, GetData(OFF_OPCODE), sizeof(aOpcode)); - memcpy(&aPayloadSize, GetData(OFF_LENGTH), sizeof(aPayloadSize)); -} - -ssize_t -DaemonSocketPDU::Send(int aFd) -{ - struct iovec iv; - memset(&iv, 0, sizeof(iv)); - iv.iov_base = GetData(GetLeadingSpace()); - iv.iov_len = GetSize(); - - struct msghdr msg; - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = &iv; - msg.msg_iovlen = 1; - msg.msg_control = nullptr; - msg.msg_controllen = 0; - - ssize_t res = TEMP_FAILURE_RETRY(sendmsg(aFd, &msg, 0)); - if (res < 0) { - MOZ_ASSERT(errno != EBADF); /* internal error */ - OnError("sendmsg", errno); - return -1; - } - - Consume(res); - - if (mConsumer) { - // We successfully sent a PDU, now store the - // result runnable in the consumer. - mConsumer->StoreUserData(*this); - } - - return res; -} - -#define CMSGHDR_CONTAINS_FD(_cmsghdr) \ - ( ((_cmsghdr)->cmsg_level == SOL_SOCKET) && \ - ((_cmsghdr)->cmsg_type == SCM_RIGHTS) ) - -ssize_t -DaemonSocketPDU::Receive(int aFd) -{ - struct iovec iv; - memset(&iv, 0, sizeof(iv)); - iv.iov_base = GetData(0); - iv.iov_len = GetAvailableSpace(); - - uint8_t cmsgbuf[CMSG_SPACE(sizeof(int))]; - - struct msghdr msg; - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = &iv; - msg.msg_iovlen = 1; - msg.msg_control = cmsgbuf; - msg.msg_controllen = sizeof(cmsgbuf); - - ssize_t res = TEMP_FAILURE_RETRY(recvmsg(aFd, &msg, MSG_NOSIGNAL)); - if (res < 0) { - MOZ_ASSERT(errno != EBADF); /* internal error */ - OnError("recvmsg", errno); - return -1; - } - if (msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE)) { - return -1; - } - - SetRange(0, res); - - struct cmsghdr *chdr = CMSG_FIRSTHDR(&msg); - - for (; chdr; chdr = CMSG_NXTHDR(&msg, chdr)) { - if (NS_WARN_IF(!CMSGHDR_CONTAINS_FD(chdr))) { - continue; - } - // Retrieve sent file descriptor. If multiple file descriptors - // have been sent, we close all but the final one. - mReceivedFd = *(static_cast(CMSG_DATA(chdr))); - } - - return res; -} - -int -DaemonSocketPDU::AcquireFd() -{ - return mReceivedFd.forget(); -} - -nsresult -DaemonSocketPDU::UpdateHeader() -{ - size_t len = GetPayloadSize(); - if (len >= MAX_PAYLOAD_LENGTH) { - return NS_ERROR_ILLEGAL_VALUE; - } - uint16_t len16 = static_cast(len); - - memcpy(GetData(OFF_LENGTH), &len16, sizeof(len16)); - - return NS_OK; -} - -size_t -DaemonSocketPDU::GetPayloadSize() const -{ - MOZ_ASSERT(GetSize() >= HEADER_SIZE); - - return GetSize() - HEADER_SIZE; -} - -void -DaemonSocketPDU::OnError(const char* aFunction, int aErrno) -{ - CHROMIUM_LOG("%s failed with error %d (%s)", - aFunction, aErrno, strerror(aErrno)); -} - -// -// DaemonSocketIOConsumer -// - -DaemonSocketIOConsumer::DaemonSocketIOConsumer() -{ } - -DaemonSocketIOConsumer::~DaemonSocketIOConsumer() -{ } - // // DaemonSocketIO // @@ -396,7 +213,7 @@ void DaemonSocket::Close() { if (!mIO) { - CHROMIUM_LOG("Bluetooth daemon already disconnected!"); + CHROMIUM_LOG("HAL daemon already disconnected!"); return; } diff --git a/ipc/hal/DaemonSocket.h b/ipc/hal/DaemonSocket.h new file mode 100644 index 0000000000000..63d3a2e5cc081 --- /dev/null +++ b/ipc/hal/DaemonSocket.h @@ -0,0 +1,63 @@ +/* -*- 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_DaemonSocket_h +#define mozilla_ipc_DaemonSocket_h + +#include "mozilla/ipc/ConnectionOrientedSocket.h" + +namespace mozilla { +namespace ipc { + +class DaemonSocketConsumer; +class DaemonSocketIO; +class DaemonSocketIOConsumer; + +/** + * |DaemonSocket| represents the socket to connect to the HAL daemon. It + * offers connection establishment and sending PDUs. PDU receiving is + * performed by |DaemonSocketIOConsumer|. + */ +class DaemonSocket : public ConnectionOrientedSocket +{ +public: + DaemonSocket(DaemonSocketIOConsumer* aIOConsumer, + DaemonSocketConsumer* aConsumer, + int aIndex); + virtual ~DaemonSocket(); + + // Methods for |ConnectionOrientedSocket| + // + + nsresult PrepareAccept(UnixSocketConnector* aConnector, + MessageLoop* aConsumerLoop, + MessageLoop* aIOLoop, + ConnectionOrientedSocketIO*& aIO) override; + + // Methods for |DataSocket| + // + + void SendSocketData(UnixSocketIOBuffer* aBuffer) override; + + // Methods for |SocketBase| + // + + void Close() override; + void OnConnectSuccess() override; + void OnConnectError() override; + void OnDisconnect() override; + +private: + DaemonSocketIO* mIO; + DaemonSocketIOConsumer* mIOConsumer; + DaemonSocketConsumer* mConsumer; + int mIndex; +}; + +} +} + +#endif diff --git a/ipc/bluetooth/BluetoothDaemonConnectionConsumer.cpp b/ipc/hal/DaemonSocketConsumer.cpp similarity index 73% rename from ipc/bluetooth/BluetoothDaemonConnectionConsumer.cpp rename to ipc/hal/DaemonSocketConsumer.cpp index 7cf2626fe28d8..ad57d5f575d0e 100644 --- a/ipc/bluetooth/BluetoothDaemonConnectionConsumer.cpp +++ b/ipc/hal/DaemonSocketConsumer.cpp @@ -4,11 +4,21 @@ * 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 "BluetoothDaemonConnectionConsumer.h" +#include "DaemonSocketConsumer.h" namespace mozilla { namespace ipc { +// +// DaemonSocketIOConsumer +// + +DaemonSocketIOConsumer::DaemonSocketIOConsumer() +{ } + +DaemonSocketIOConsumer::~DaemonSocketIOConsumer() +{ } + // // DaemonSocketConsumer // diff --git a/ipc/bluetooth/BluetoothDaemonConnectionConsumer.h b/ipc/hal/DaemonSocketConsumer.h similarity index 68% rename from ipc/bluetooth/BluetoothDaemonConnectionConsumer.h rename to ipc/hal/DaemonSocketConsumer.h index 7791b60fb18bd..4dda45046fef8 100644 --- a/ipc/bluetooth/BluetoothDaemonConnectionConsumer.h +++ b/ipc/hal/DaemonSocketConsumer.h @@ -4,18 +4,32 @@ * 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_BluetoothDaemonConnectionConsumer_h -#define mozilla_ipc_BluetoothDaemonConnectionConsumer_h - -#include "mozilla/Attributes.h" -#include "mozilla/FileUtils.h" -#include "mozilla/ipc/ConnectionOrientedSocket.h" -#include "nsAutoPtr.h" +#ifndef mozilla_ipc_DaemonSocketConsumer_h +#define mozilla_ipc_DaemonSocketConsumer_h namespace mozilla { namespace ipc { -/* +class DaemonSocketPDU; + +/** + * |DaemonSocketIOConsumer| processes incoming PDUs from the + * HAL daemon. Please note that its method |Handle| runs on a + * different than the consumer thread. + */ +class DaemonSocketIOConsumer +{ +public: + virtual ~DaemonSocketIOConsumer(); + + virtual void Handle(DaemonSocketPDU& aPDU) = 0; + virtual void StoreUserData(const DaemonSocketPDU& aPDU) = 0; + +protected: + DaemonSocketIOConsumer(); +}; + +/** * |DaemonSocketConsumer| handles socket events. */ class DaemonSocketConsumer diff --git a/ipc/hal/DaemonSocketPDU.cpp b/ipc/hal/DaemonSocketPDU.cpp new file mode 100644 index 0000000000000..a410e55a8d1aa --- /dev/null +++ b/ipc/hal/DaemonSocketPDU.cpp @@ -0,0 +1,188 @@ +/* -*- 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/. */ + +#include "DaemonSocketPDU.h" +#include "mozilla/ipc/DaemonSocketConsumer.h" + +#ifdef CHROMIUM_LOG +#undef CHROMIUM_LOG +#endif + +#if defined(MOZ_WIDGET_GONK) +#include +#define CHROMIUM_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "I/O", args); +#else +#include +#define IODEBUG true +#define CHROMIUM_LOG(args...) if (IODEBUG) printf(args); +#endif + +namespace mozilla { +namespace ipc { + +// +// DaemonSocketPDU +// + +DaemonSocketPDU::DaemonSocketPDU(uint8_t aService, uint8_t aOpcode, + uint16_t aPayloadSize) + : mConsumer(nullptr) + , mUserData(nullptr) +{ + // Allocate memory + size_t availableSpace = HEADER_SIZE + aPayloadSize; + ResetBuffer(new uint8_t[availableSpace], 0, 0, availableSpace); + + // Reserve PDU header + uint8_t* data = Append(HEADER_SIZE); + MOZ_ASSERT(data); + + // Setup PDU header + data[OFF_SERVICE] = aService; + data[OFF_OPCODE] = aOpcode; + memcpy(data + OFF_LENGTH, &aPayloadSize, sizeof(aPayloadSize)); +} + +DaemonSocketPDU::DaemonSocketPDU(size_t aPayloadSize) + : mConsumer(nullptr) + , mUserData(nullptr) +{ + size_t availableSpace = HEADER_SIZE + aPayloadSize; + ResetBuffer(new uint8_t[availableSpace], 0, 0, availableSpace); +} + +DaemonSocketPDU::~DaemonSocketPDU() +{ + nsAutoArrayPtr data(GetBuffer()); + ResetBuffer(nullptr, 0, 0, 0); +} + +void +DaemonSocketPDU::GetHeader(uint8_t& aService, uint8_t& aOpcode, + uint16_t& aPayloadSize) +{ + memcpy(&aService, GetData(OFF_SERVICE), sizeof(aService)); + memcpy(&aOpcode, GetData(OFF_OPCODE), sizeof(aOpcode)); + memcpy(&aPayloadSize, GetData(OFF_LENGTH), sizeof(aPayloadSize)); +} + +ssize_t +DaemonSocketPDU::Send(int aFd) +{ + struct iovec iv; + memset(&iv, 0, sizeof(iv)); + iv.iov_base = GetData(GetLeadingSpace()); + iv.iov_len = GetSize(); + + struct msghdr msg; + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &iv; + msg.msg_iovlen = 1; + msg.msg_control = nullptr; + msg.msg_controllen = 0; + + ssize_t res = TEMP_FAILURE_RETRY(sendmsg(aFd, &msg, 0)); + if (res < 0) { + MOZ_ASSERT(errno != EBADF); /* internal error */ + OnError("sendmsg", errno); + return -1; + } + + Consume(res); + + if (mConsumer) { + // We successfully sent a PDU, now store the + // result runnable in the consumer. + mConsumer->StoreUserData(*this); + } + + return res; +} + +#define CMSGHDR_CONTAINS_FD(_cmsghdr) \ + ( ((_cmsghdr)->cmsg_level == SOL_SOCKET) && \ + ((_cmsghdr)->cmsg_type == SCM_RIGHTS) ) + +ssize_t +DaemonSocketPDU::Receive(int aFd) +{ + struct iovec iv; + memset(&iv, 0, sizeof(iv)); + iv.iov_base = GetData(0); + iv.iov_len = GetAvailableSpace(); + + uint8_t cmsgbuf[CMSG_SPACE(sizeof(int))]; + + struct msghdr msg; + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &iv; + msg.msg_iovlen = 1; + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + + ssize_t res = TEMP_FAILURE_RETRY(recvmsg(aFd, &msg, MSG_NOSIGNAL)); + if (res < 0) { + MOZ_ASSERT(errno != EBADF); /* internal error */ + OnError("recvmsg", errno); + return -1; + } + if (msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE)) { + return -1; + } + + SetRange(0, res); + + struct cmsghdr *chdr = CMSG_FIRSTHDR(&msg); + + for (; chdr; chdr = CMSG_NXTHDR(&msg, chdr)) { + if (NS_WARN_IF(!CMSGHDR_CONTAINS_FD(chdr))) { + continue; + } + // Retrieve sent file descriptor. If multiple file descriptors + // have been sent, we close all but the final one. + mReceivedFd = *(static_cast(CMSG_DATA(chdr))); + } + + return res; +} + +int +DaemonSocketPDU::AcquireFd() +{ + return mReceivedFd.forget(); +} + +nsresult +DaemonSocketPDU::UpdateHeader() +{ + size_t len = GetPayloadSize(); + if (len >= MAX_PAYLOAD_LENGTH) { + return NS_ERROR_ILLEGAL_VALUE; + } + uint16_t len16 = static_cast(len); + + memcpy(GetData(OFF_LENGTH), &len16, sizeof(len16)); + + return NS_OK; +} + +size_t +DaemonSocketPDU::GetPayloadSize() const +{ + MOZ_ASSERT(GetSize() >= HEADER_SIZE); + + return GetSize() - HEADER_SIZE; +} + +void +DaemonSocketPDU::OnError(const char* aFunction, int aErrno) +{ + CHROMIUM_LOG("%s failed with error %d (%s)", + aFunction, aErrno, strerror(aErrno)); +} + +} +} diff --git a/ipc/hal/DaemonSocketPDU.h b/ipc/hal/DaemonSocketPDU.h new file mode 100644 index 0000000000000..95275f03c5c07 --- /dev/null +++ b/ipc/hal/DaemonSocketPDU.h @@ -0,0 +1,91 @@ +/* -*- 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_DaemonSocketPDU_h +#define mozilla_ipc_DaemonSocketPDU_h + +#include "mozilla/FileUtils.h" +#include "mozilla/ipc/SocketBase.h" + +namespace mozilla { +namespace ipc { + +class DaemonSocketIOConsumer; + +/** + * |DaemonSocketPDU| represents a single PDU that is transfered from or to + * the HAL daemon. Each PDU contains exactly one command. + * + * A PDU as the following format + * + * | 1 | 1 | 2 | n | + * | service | opcode | payload length | payload | + * + * Service and Opcode each require 1 byte, the payload length requires 2 + * bytes, and the payload requires the number of bytes as stored in the + * payload-length field. + * + * Each service and opcode can have a different payload with individual + * length. For the exact details of the HAL protocol, please refer to + * + * https://git.kernel.org/cgit/bluetooth/bluez.git/tree/android/hal-ipc-api.txt?id=5.24 + * + */ +class DaemonSocketPDU final : public UnixSocketIOBuffer +{ +public: + enum { + OFF_SERVICE = 0, + OFF_OPCODE = 1, + OFF_LENGTH = 2, + OFF_PAYLOAD = 4, + HEADER_SIZE = OFF_PAYLOAD, + MAX_PAYLOAD_LENGTH = 1 << 16 + }; + + DaemonSocketPDU(uint8_t aService, uint8_t aOpcode, uint16_t aPayloadSize); + DaemonSocketPDU(size_t aPayloadSize); + ~DaemonSocketPDU(); + + void SetConsumer(DaemonSocketIOConsumer* aConsumer) + { + mConsumer = aConsumer; + } + + void SetUserData(void* aUserData) + { + mUserData = aUserData; + } + + void* GetUserData() const + { + return mUserData; + } + + void GetHeader(uint8_t& aService, uint8_t& aOpcode, + uint16_t& aPayloadSize); + + ssize_t Send(int aFd) override; + ssize_t Receive(int aFd) override; + + int AcquireFd(); + + nsresult UpdateHeader(); + +private: + size_t GetPayloadSize() const; + void OnError(const char* aFunction, int aErrno); + + DaemonSocketIOConsumer* mConsumer; + void* mUserData; + ScopedClose mReceivedFd; +}; + +} +} + +#endif + diff --git a/ipc/bluetooth/moz.build b/ipc/hal/moz.build similarity index 70% rename from ipc/bluetooth/moz.build rename to ipc/hal/moz.build index 7a71491aab9cc..382856dec0a10 100644 --- a/ipc/bluetooth/moz.build +++ b/ipc/hal/moz.build @@ -5,13 +5,15 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. EXPORTS.mozilla.ipc += [ - 'BluetoothDaemonConnection.h', - 'BluetoothDaemonConnectionConsumer.h' + 'DaemonSocket.h', + 'DaemonSocketConsumer.h', + 'DaemonSocketPDU.h' ] -SOURCES += [ - 'BluetoothDaemonConnection.cpp', - 'BluetoothDaemonConnectionConsumer.cpp' +UNIFIED_SOURCES += [ + 'DaemonSocket.cpp', + 'DaemonSocketConsumer.cpp', + 'DaemonSocketPDU.cpp' ] include('/ipc/chromium/chromium-config.mozbuild') diff --git a/ipc/moz.build b/ipc/moz.build index 568ca5d2b35a8..ab07dc69458b0 100644 --- a/ipc/moz.build +++ b/ipc/moz.build @@ -14,9 +14,6 @@ DIRS += [ if CONFIG['MOZ_B2G_RIL']: DIRS += ['ril'] -if CONFIG['MOZ_B2G_BT_BLUEDROID']: - DIRS += ['bluetooth'] - if CONFIG['MOZ_B2G_BT_BLUEZ']: DIRS += ['dbus'] @@ -27,7 +24,7 @@ if CONFIG['MOZ_B2G_RIL'] or CONFIG['MOZ_B2G_BT'] or CONFIG['MOZ_NFC'] or CONFIG[ DIRS += ['unixfd', 'unixsocket'] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': - DIRS += ['keystore', 'netd'] + DIRS += ['hal', 'keystore', 'netd'] if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android': DIRS += ['contentproc']