summaryrefslogtreecommitdiffstats
path: root/ipc/hal
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/hal')
-rw-r--r--ipc/hal/DaemonRunnables.h950
-rw-r--r--ipc/hal/DaemonSocket.cpp263
-rw-r--r--ipc/hal/DaemonSocket.h63
-rw-r--r--ipc/hal/DaemonSocketConnector.cpp244
-rw-r--r--ipc/hal/DaemonSocketConnector.h61
-rw-r--r--ipc/hal/DaemonSocketConsumer.cpp33
-rw-r--r--ipc/hal/DaemonSocketConsumer.h68
-rw-r--r--ipc/hal/DaemonSocketMessageHandlers.h40
-rw-r--r--ipc/hal/DaemonSocketPDU.cpp202
-rw-r--r--ipc/hal/DaemonSocketPDU.h94
-rw-r--r--ipc/hal/DaemonSocketPDUHelpers.cpp335
-rw-r--r--ipc/hal/DaemonSocketPDUHelpers.h1283
-rw-r--r--ipc/hal/moz.build27
13 files changed, 3663 insertions, 0 deletions
diff --git a/ipc/hal/DaemonRunnables.h b/ipc/hal/DaemonRunnables.h
new file mode 100644
index 000000000..e4a528a9b
--- /dev/null
+++ b/ipc/hal/DaemonRunnables.h
@@ -0,0 +1,950 @@
+/* -*- 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_DaemonRunnables_h
+#define mozilla_ipc_DaemonRunnables_h
+
+#include "mozilla/Unused.h"
+#include "mozilla/UniquePtr.h"
+#include "nsThreadUtils.h"
+
+namespace mozilla {
+namespace ipc {
+
+namespace details {
+
+class DaemonRunnable : public Runnable
+{
+protected:
+ DaemonRunnable() = default;
+ virtual ~DaemonRunnable() = default;
+
+ template<typename Out, typename In>
+ static Out& ConvertArg(In& aArg)
+ {
+ return aArg;
+ }
+
+ template<typename Out, typename In>
+ static Out ConvertArg(UniquePtr<In>& aArg)
+ {
+ return aArg.get();
+ }
+};
+
+} // namespace detail
+
+//
+// Result handling
+//
+// The classes of type |DaemonResultRunnable[0..3]| transfer a result
+// handler from the I/O thread to the main thread for execution. Call
+// the methods |Create| and |Dispatch| to create or create-and-dispatch
+// a result runnable.
+//
+// You need to specify the called method. The |Create| and |Dispatch|
+// methods of |DaemonResultRunnable[1..3]| receive an extra argument
+// for initializing the result's arguments. During creation, the result
+// runnable calls the supplied class's call operator with the result's
+// argument. This is where initialization and conversion from backend-
+// specific types is performed.
+//
+
+template <typename Obj, typename Res>
+class DaemonResultRunnable0 final : public details::DaemonRunnable
+{
+public:
+ typedef DaemonResultRunnable0<Obj, Res> SelfType;
+
+ template <typename InitOp>
+ static already_AddRefed<SelfType>
+ Create(Obj* aObj, Res (Obj::*aMethod)(), const InitOp& aInitOp)
+ {
+ RefPtr<SelfType> runnable(new SelfType(aObj, aMethod));
+ if (NS_FAILED(runnable->Init(aInitOp))) {
+ return nullptr;
+ }
+ return runnable.forget();
+ }
+
+ template <typename InitOp>
+ static void
+ Dispatch(Obj* aObj, Res (Obj::*aMethod)(), const InitOp& aInitOp)
+ {
+ if (!aObj) {
+ return; // silently return if no result runnable has been given
+ }
+ RefPtr<SelfType> runnable = Create(aObj, aMethod, aInitOp);
+ if (!runnable) {
+ return;
+ }
+ Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable)));
+ }
+
+ NS_IMETHOD Run() override
+ {
+ ((*mObj).*mMethod)();
+ return NS_OK;
+ }
+
+private:
+ DaemonResultRunnable0(Obj* aObj, Res (Obj::*aMethod)())
+ : mObj(aObj)
+ , mMethod(aMethod)
+ {
+ MOZ_ASSERT(mObj);
+ MOZ_ASSERT(mMethod);
+ }
+
+ template<typename InitOp>
+ nsresult Init(const InitOp& aInitOp)
+ {
+ return aInitOp();
+ }
+
+ RefPtr<Obj> mObj;
+ void (Obj::*mMethod)();
+};
+
+template <typename Obj, typename Res, typename Tin1, typename Arg1>
+class DaemonResultRunnable1 final : public details::DaemonRunnable
+{
+public:
+ typedef DaemonResultRunnable1<Obj, Res, Tin1, Arg1> SelfType;
+
+ template <typename InitOp>
+ static already_AddRefed<SelfType>
+ Create(Obj* aObj, Res (Obj::*aMethod)(Arg1), const InitOp& aInitOp)
+ {
+ RefPtr<SelfType> runnable(new SelfType(aObj, aMethod));
+ if (NS_FAILED(runnable->Init(aInitOp))) {
+ return nullptr;
+ }
+ return runnable.forget();
+ }
+
+ template <typename InitOp>
+ static void
+ Dispatch(Obj* aObj, Res (Obj::*aMethod)(Arg1), const InitOp& aInitOp)
+ {
+ if (!aObj) {
+ return; // silently return if no result runnable has been given
+ }
+ RefPtr<SelfType> runnable = Create(aObj, aMethod, aInitOp);
+ if (!runnable) {
+ return;
+ }
+ Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable)));
+ }
+
+ NS_IMETHOD Run() override
+ {
+ ((*mObj).*mMethod)(ConvertArg<Arg1>(mArg1));
+ return NS_OK;
+ }
+
+private:
+ DaemonResultRunnable1(Obj* aObj, Res (Obj::*aMethod)(Arg1))
+ : mObj(aObj)
+ , mMethod(aMethod)
+ {
+ MOZ_ASSERT(mObj);
+ MOZ_ASSERT(mMethod);
+ }
+
+ template<typename InitOp>
+ nsresult Init(const InitOp& aInitOp)
+ {
+ return aInitOp(mArg1);
+ }
+
+ RefPtr<Obj> mObj;
+ Res (Obj::*mMethod)(Arg1);
+ Tin1 mArg1;
+};
+
+template <typename Obj, typename Res,
+ typename Tin1, typename Tin2, typename Tin3,
+ typename Arg1, typename Arg2, typename Arg3>
+class DaemonResultRunnable3 final : public details::DaemonRunnable
+{
+public:
+ typedef DaemonResultRunnable3<Obj, Res,
+ Tin1, Tin2, Tin3,
+ Arg1, Arg2, Arg3> SelfType;
+
+ template<typename InitOp>
+ static already_AddRefed<SelfType>
+ Create(Obj* aObj, Res (Obj::*aMethod)(Arg1, Arg2, Arg3),
+ const InitOp& aInitOp)
+ {
+ RefPtr<SelfType> runnable(new SelfType(aObj, aMethod));
+ if (NS_FAILED(runnable->Init(aInitOp))) {
+ return nullptr;
+ }
+ return runnable.forget();
+ }
+
+ template<typename InitOp>
+ static void
+ Dispatch(Obj* aObj, Res (Obj::*aMethod)(Arg1, Arg2, Arg3),
+ const InitOp& aInitOp)
+ {
+ if (!aObj) {
+ return; // silently return if no result runnable has been given
+ }
+ RefPtr<SelfType> runnable = Create(aObj, aMethod, aInitOp);
+ if (!runnable) {
+ return;
+ }
+ Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable)));
+ }
+
+ NS_IMETHOD Run() override
+ {
+ ((*mObj).*mMethod)(ConvertArg<Arg1>(mArg1),
+ ConvertArg<Arg2>(mArg2),
+ ConvertArg<Arg3>(mArg3));
+ return NS_OK;
+ }
+
+private:
+ DaemonResultRunnable3(Obj* aObj, Res (Obj::*aMethod)(Arg1, Arg2, Arg3))
+ : mObj(aObj)
+ , mMethod(aMethod)
+ {
+ MOZ_ASSERT(mObj);
+ MOZ_ASSERT(mMethod);
+ }
+
+ template<typename InitOp>
+ nsresult
+ Init(const InitOp& aInitOp)
+ {
+ return aInitOp(mArg1, mArg2, mArg3);
+ }
+
+ RefPtr<Obj> mObj;
+ Res (Obj::*mMethod)(Arg1, Arg2, Arg3);
+ Tin1 mArg1;
+ Tin2 mArg2;
+ Tin3 mArg3;
+};
+
+//
+// Notification handling
+//
+// The classes of type |DaemonNotificationRunnable[0..9]| transfer a
+// notification from the I/O thread to a notification handler on the
+// main thread. Call the methods |Create| and |Dispatch| to create or
+// create-and-dispatch a notification runnable.
+//
+// Like with result runnables, you need to specify the called method.
+// And like with result runnables, the |Create| and |Dispatch| methods
+// of |DaemonNotificationRunnable[1..9]| receive an extra argument
+// for initializing the notification's arguments. During creation, the
+// notification runnable calls the class's call operator with the
+// notification's argument. This is where initialization and conversion
+// from backend-specific types is performed.
+//
+
+template <typename ObjectWrapper, typename Res>
+class DaemonNotificationRunnable0 final : public details::DaemonRunnable
+{
+public:
+ typedef typename ObjectWrapper::ObjectType ObjectType;
+ typedef DaemonNotificationRunnable0<ObjectWrapper, Res> SelfType;
+
+ template<typename InitOp>
+ static already_AddRefed<SelfType>
+ Create(Res (ObjectType::*aMethod)(), const InitOp& aInitOp)
+ {
+ RefPtr<SelfType> runnable(new SelfType(aMethod));
+ if (NS_FAILED(runnable->Init(aInitOp))) {
+ return nullptr;
+ }
+ return runnable.forget();
+ }
+
+ template<typename InitOp>
+ static void
+ Dispatch(Res (ObjectType::*aMethod)(), const InitOp& aInitOp)
+ {
+ RefPtr<SelfType> runnable = Create(aMethod, aInitOp);
+ if (!runnable) {
+ return;
+ }
+ Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable)));
+ }
+
+ NS_IMETHOD Run() override
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ ObjectType* obj = ObjectWrapper::GetInstance();
+ if (!obj) {
+ NS_WARNING("Notification handler not initialized");
+ } else {
+ ((*obj).*mMethod)();
+ }
+ return NS_OK;
+ }
+
+private:
+ DaemonNotificationRunnable0(Res (ObjectType::*aMethod)())
+ : mMethod(aMethod)
+ {
+ MOZ_ASSERT(mMethod);
+ }
+
+ template<typename InitOp>
+ nsresult Init(const InitOp& aInitOp)
+ {
+ return aInitOp();
+ }
+
+ Res (ObjectType::*mMethod)();
+};
+
+template <typename ObjectWrapper, typename Res,
+ typename Tin1, typename Arg1=Tin1>
+class DaemonNotificationRunnable1 final : public details::DaemonRunnable
+{
+public:
+ typedef typename ObjectWrapper::ObjectType ObjectType;
+ typedef DaemonNotificationRunnable1<ObjectWrapper, Res,
+ Tin1, Arg1> SelfType;
+
+ template <typename InitOp>
+ static already_AddRefed<SelfType>
+ Create(Res (ObjectType::*aMethod)(Arg1), const InitOp& aInitOp)
+ {
+ RefPtr<SelfType> runnable(new SelfType(aMethod));
+ if (NS_FAILED(runnable->Init(aInitOp))) {
+ return nullptr;
+ }
+ return runnable.forget();
+ }
+
+ template <typename InitOp>
+ static void
+ Dispatch(Res (ObjectType::*aMethod)(Arg1), const InitOp& aInitOp)
+ {
+ RefPtr<SelfType> runnable = Create(aMethod, aInitOp);
+ if (!runnable) {
+ return;
+ }
+ Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable)));
+ }
+
+ NS_IMETHOD Run() override
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ ObjectType* obj = ObjectWrapper::GetInstance();
+ if (!obj) {
+ NS_WARNING("Notification handler not initialized");
+ } else {
+ ((*obj).*mMethod)(ConvertArg<Arg1>(mArg1));
+ }
+ return NS_OK;
+ }
+
+private:
+ DaemonNotificationRunnable1(Res (ObjectType::*aMethod)(Arg1))
+ : mMethod(aMethod)
+ {
+ MOZ_ASSERT(mMethod);
+ }
+
+ template<typename InitOp>
+ nsresult Init(const InitOp& aInitOp)
+ {
+ nsresult rv = aInitOp(mArg1);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return NS_OK;
+ }
+
+ Res (ObjectType::*mMethod)(Arg1);
+ Tin1 mArg1;
+};
+
+template <typename ObjectWrapper, typename Res,
+ typename Tin1, typename Tin2,
+ typename Arg1=Tin1, typename Arg2=Tin2>
+class DaemonNotificationRunnable2 final : public details::DaemonRunnable
+{
+public:
+ typedef typename ObjectWrapper::ObjectType ObjectType;
+ typedef DaemonNotificationRunnable2<ObjectWrapper, Res,
+ Tin1, Tin2,
+ Arg1, Arg2> SelfType;
+
+ template <typename InitOp>
+ static already_AddRefed<SelfType>
+ Create(Res (ObjectType::*aMethod)(Arg1, Arg2), const InitOp& aInitOp)
+ {
+ RefPtr<SelfType> runnable(new SelfType(aMethod));
+ if (NS_FAILED(runnable->Init(aInitOp))) {
+ return nullptr;
+ }
+ return runnable.forget();
+ }
+
+ template <typename InitOp>
+ static void
+ Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2), const InitOp& aInitOp)
+ {
+ RefPtr<SelfType> runnable = Create(aMethod, aInitOp);
+ if (!runnable) {
+ return;
+ }
+ Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable)));
+ }
+
+ NS_IMETHOD Run() override
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ ObjectType* obj = ObjectWrapper::GetInstance();
+ if (!obj) {
+ NS_WARNING("Notification handler not initialized");
+ } else {
+ ((*obj).*mMethod)(ConvertArg<Arg1>(mArg1),
+ ConvertArg<Arg2>(mArg2));
+ }
+ return NS_OK;
+ }
+
+private:
+ DaemonNotificationRunnable2(
+ Res (ObjectType::*aMethod)(Arg1, Arg2))
+ : mMethod(aMethod)
+ {
+ MOZ_ASSERT(mMethod);
+ }
+
+ template<typename InitOp>
+ nsresult Init(const InitOp& aInitOp)
+ {
+ nsresult rv = aInitOp(mArg1, mArg2);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return NS_OK;
+ }
+
+ Res (ObjectType::*mMethod)(Arg1, Arg2);
+ Tin1 mArg1;
+ Tin2 mArg2;
+};
+
+template <typename ObjectWrapper, typename Res,
+ typename Tin1, typename Tin2, typename Tin3,
+ typename Arg1=Tin1, typename Arg2=Tin2, typename Arg3=Tin3>
+class DaemonNotificationRunnable3 final : public details::DaemonRunnable
+{
+public:
+ typedef typename ObjectWrapper::ObjectType ObjectType;
+ typedef DaemonNotificationRunnable3<ObjectWrapper, Res,
+ Tin1, Tin2, Tin3,
+ Arg1, Arg2, Arg3> SelfType;
+
+ template <typename InitOp>
+ static already_AddRefed<SelfType>
+ Create(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3), const InitOp& aInitOp)
+ {
+ RefPtr<SelfType> runnable(new SelfType(aMethod));
+ if (NS_FAILED(runnable->Init(aInitOp))) {
+ return nullptr;
+ }
+ return runnable.forget();
+ }
+
+ template <typename InitOp>
+ static void
+ Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3),
+ const InitOp& aInitOp)
+ {
+ RefPtr<SelfType> runnable = Create(aMethod, aInitOp);
+ if (!runnable) {
+ return;
+ }
+ Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable)));
+ }
+
+ NS_IMETHOD Run() override
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ ObjectType* obj = ObjectWrapper::GetInstance();
+ if (!obj) {
+ NS_WARNING("Notification handler not initialized");
+ } else {
+ ((*obj).*mMethod)(ConvertArg<Arg1>(mArg1),
+ ConvertArg<Arg2>(mArg2),
+ ConvertArg<Arg3>(mArg3));
+ }
+ return NS_OK;
+ }
+
+private:
+ DaemonNotificationRunnable3(
+ Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3))
+ : mMethod(aMethod)
+ {
+ MOZ_ASSERT(mMethod);
+ }
+
+ template<typename InitOp>
+ nsresult Init(const InitOp& aInitOp)
+ {
+ nsresult rv = aInitOp(mArg1, mArg2, mArg3);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return NS_OK;
+ }
+
+ Res (ObjectType::*mMethod)(Arg1, Arg2, Arg3);
+ Tin1 mArg1;
+ Tin2 mArg2;
+ Tin3 mArg3;
+};
+
+template <typename ObjectWrapper, typename Res,
+ typename Tin1, typename Tin2, typename Tin3, typename Tin4,
+ typename Arg1=Tin1, typename Arg2=Tin2,
+ typename Arg3=Tin3, typename Arg4=Tin4>
+class DaemonNotificationRunnable4 final : public details::DaemonRunnable
+{
+public:
+ typedef typename ObjectWrapper::ObjectType ObjectType;
+ typedef DaemonNotificationRunnable4<ObjectWrapper, Res,
+ Tin1, Tin2, Tin3, Tin4, Arg1, Arg2, Arg3, Arg4> SelfType;
+
+ template <typename InitOp>
+ static already_AddRefed<SelfType> Create(
+ Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4),
+ const InitOp& aInitOp)
+ {
+ RefPtr<SelfType> runnable(new SelfType(aMethod));
+ if (NS_FAILED(runnable->Init(aInitOp))) {
+ return nullptr;
+ }
+ return runnable.forget();
+ }
+
+ template <typename InitOp>
+ static void
+ Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4),
+ const InitOp& aInitOp)
+ {
+ RefPtr<SelfType> runnable = Create(aMethod, aInitOp);
+ if (!runnable) {
+ return;
+ }
+ Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable)));
+ }
+
+ NS_IMETHOD Run() override
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ ObjectType* obj = ObjectWrapper::GetInstance();
+ if (!obj) {
+ NS_WARNING("Notification handler not initialized");
+ } else {
+ ((*obj).*mMethod)(ConvertArg<Arg1>(mArg1),
+ ConvertArg<Arg2>(mArg2),
+ ConvertArg<Arg3>(mArg3),
+ ConvertArg<Arg4>(mArg4));
+ }
+ return NS_OK;
+ }
+
+private:
+ DaemonNotificationRunnable4(
+ Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4))
+ : mMethod(aMethod)
+ {
+ MOZ_ASSERT(mMethod);
+ }
+
+ template<typename InitOp>
+ nsresult Init(const InitOp& aInitOp)
+ {
+ nsresult rv = aInitOp(mArg1, mArg2, mArg3, mArg4);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return NS_OK;
+ }
+
+ Res (ObjectType::*mMethod)(Arg1, Arg2, Arg3, Arg4);
+ Tin1 mArg1;
+ Tin2 mArg2;
+ Tin3 mArg3;
+ Tin4 mArg4;
+};
+
+template <typename ObjectWrapper, typename Res,
+ typename Tin1, typename Tin2, typename Tin3,
+ typename Tin4, typename Tin5,
+ typename Arg1=Tin1, typename Arg2=Tin2, typename Arg3=Tin3,
+ typename Arg4=Tin4, typename Arg5=Tin5>
+class DaemonNotificationRunnable5 final : public details::DaemonRunnable
+{
+public:
+ typedef typename ObjectWrapper::ObjectType ObjectType;
+ typedef DaemonNotificationRunnable5<ObjectWrapper, Res,
+ Tin1, Tin2, Tin3, Tin4, Tin5, Arg1, Arg2, Arg3, Arg4, Arg5> SelfType;
+
+ template <typename InitOp>
+ static already_AddRefed<SelfType> Create(
+ Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4, Arg5),
+ const InitOp& aInitOp)
+ {
+ RefPtr<SelfType> runnable(new SelfType(aMethod));
+ if (NS_FAILED(runnable->Init(aInitOp))) {
+ return nullptr;
+ }
+ return runnable.forget();
+ }
+
+ template <typename InitOp>
+ static void
+ Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4, Arg5),
+ const InitOp& aInitOp)
+ {
+ RefPtr<SelfType> runnable = Create(aMethod, aInitOp);
+ if (!runnable) {
+ return;
+ }
+ Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable)));
+ }
+
+ NS_IMETHOD Run() override
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ ObjectType* obj = ObjectWrapper::GetInstance();
+ if (!obj) {
+ NS_WARNING("Notification handler not initialized");
+ } else {
+ ((*obj).*mMethod)(ConvertArg<Arg1>(mArg1),
+ ConvertArg<Arg2>(mArg2),
+ ConvertArg<Arg3>(mArg3),
+ ConvertArg<Arg4>(mArg4),
+ ConvertArg<Arg5>(mArg5));
+ }
+ return NS_OK;
+ }
+
+private:
+ DaemonNotificationRunnable5(
+ Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4, Arg5))
+ : mMethod(aMethod)
+ {
+ MOZ_ASSERT(mMethod);
+ }
+
+ template<typename InitOp>
+ nsresult Init(const InitOp& aInitOp)
+ {
+ nsresult rv = aInitOp(mArg1, mArg2, mArg3, mArg4, mArg5);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return NS_OK;
+ }
+
+ Res (ObjectType::*mMethod)(Arg1, Arg2, Arg3, Arg4, Arg5);
+ Tin1 mArg1;
+ Tin2 mArg2;
+ Tin3 mArg3;
+ Tin4 mArg4;
+ Tin5 mArg5;
+};
+
+template <typename ObjectWrapper, typename Res,
+ typename Tin1, typename Tin2, typename Tin3,
+ typename Tin4, typename Tin5, typename Tin6,
+ typename Arg1=Tin1, typename Arg2=Tin2, typename Arg3=Tin3,
+ typename Arg4=Tin4, typename Arg5=Tin5, typename Arg6=Tin6>
+class DaemonNotificationRunnable6 final : public details::DaemonRunnable
+{
+public:
+ typedef typename ObjectWrapper::ObjectType ObjectType;
+ typedef DaemonNotificationRunnable6<ObjectWrapper, Res,
+ Tin1, Tin2, Tin3, Tin4, Tin5, Tin6, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6>
+ SelfType;
+
+ template <typename InitOp>
+ static already_AddRefed<SelfType> Create(
+ Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6),
+ const InitOp& aInitOp)
+ {
+ RefPtr<SelfType> runnable(new SelfType(aMethod));
+ if (NS_FAILED(runnable->Init(aInitOp))) {
+ return nullptr;
+ }
+ return runnable.forget();
+ }
+
+ template <typename InitOp>
+ static void
+ Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6),
+ const InitOp& aInitOp)
+ {
+ RefPtr<SelfType> runnable = Create(aMethod, aInitOp);
+ if (!runnable) {
+ return;
+ }
+ Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable)));
+ }
+
+ NS_IMETHOD Run() override
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ ObjectType* obj = ObjectWrapper::GetInstance();
+ if (!obj) {
+ NS_WARNING("Notification handler not initialized");
+ } else {
+ ((*obj).*mMethod)(ConvertArg<Arg1>(mArg1),
+ ConvertArg<Arg2>(mArg2),
+ ConvertArg<Arg3>(mArg3),
+ ConvertArg<Arg4>(mArg4),
+ ConvertArg<Arg5>(mArg5),
+ ConvertArg<Arg6>(mArg6));
+ }
+ return NS_OK;
+ }
+
+private:
+ DaemonNotificationRunnable6(
+ Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6))
+ : mMethod(aMethod)
+ {
+ MOZ_ASSERT(mMethod);
+ }
+
+ template<typename InitOp>
+ nsresult Init(const InitOp& aInitOp)
+ {
+ nsresult rv = aInitOp(mArg1, mArg2, mArg3, mArg4, mArg5, mArg6);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return NS_OK;
+ }
+
+ Res (ObjectType::*mMethod)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6);
+ Tin1 mArg1;
+ Tin2 mArg2;
+ Tin3 mArg3;
+ Tin4 mArg4;
+ Tin5 mArg5;
+ Tin6 mArg6;
+};
+
+template <typename ObjectWrapper, typename Res,
+ typename Tin1, typename Tin2, typename Tin3,
+ typename Tin4, typename Tin5, typename Tin6,
+ typename Tin7, typename Tin8,
+ typename Arg1=Tin1, typename Arg2=Tin2, typename Arg3=Tin3,
+ typename Arg4=Tin4, typename Arg5=Tin5, typename Arg6=Tin6,
+ typename Arg7=Tin7, typename Arg8=Tin8>
+class DaemonNotificationRunnable8 final : public details::DaemonRunnable
+{
+public:
+ typedef typename ObjectWrapper::ObjectType ObjectType;
+ typedef DaemonNotificationRunnable8<ObjectWrapper, Res,
+ Tin1, Tin2, Tin3, Tin4, Tin5, Tin6, Tin7, Tin8,
+ Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8> SelfType;
+
+ template <typename InitOp>
+ static already_AddRefed<SelfType> Create(
+ Res (ObjectType::*aMethod)(
+ Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8),
+ const InitOp& aInitOp)
+ {
+ RefPtr<SelfType> runnable(new SelfType(aMethod));
+ if (NS_FAILED(runnable->Init(aInitOp))) {
+ return nullptr;
+ }
+ return runnable.forget();
+ }
+
+ template <typename InitOp>
+ static void
+ Dispatch(
+ Res (ObjectType::*aMethod)(
+ Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8),
+ const InitOp& aInitOp)
+ {
+ RefPtr<SelfType> runnable = Create(aMethod, aInitOp);
+ if (!runnable) {
+ return;
+ }
+ Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable)));
+ }
+
+ NS_IMETHOD Run() override
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ ObjectType* obj = ObjectWrapper::GetInstance();
+ if (!obj) {
+ NS_WARNING("Notification handler not initialized");
+ } else {
+ ((*obj).*mMethod)(ConvertArg<Arg1>(mArg1),
+ ConvertArg<Arg2>(mArg2),
+ ConvertArg<Arg3>(mArg3),
+ ConvertArg<Arg4>(mArg4),
+ ConvertArg<Arg5>(mArg5),
+ ConvertArg<Arg6>(mArg6),
+ ConvertArg<Arg7>(mArg7),
+ ConvertArg<Arg8>(mArg8));
+ }
+ return NS_OK;
+ }
+
+private:
+ DaemonNotificationRunnable8(
+ Res (ObjectType::*aMethod)(
+ Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8))
+ : mMethod(aMethod)
+ {
+ MOZ_ASSERT(mMethod);
+ }
+
+ template<typename InitOp>
+ nsresult Init(const InitOp& aInitOp)
+ {
+ nsresult rv = aInitOp(mArg1, mArg2, mArg3, mArg4,
+ mArg5, mArg6, mArg7, mArg8);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return NS_OK;
+ }
+
+ Res (ObjectType::*mMethod)(
+ Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8);
+ Tin1 mArg1;
+ Tin2 mArg2;
+ Tin3 mArg3;
+ Tin4 mArg4;
+ Tin5 mArg5;
+ Tin6 mArg6;
+ Tin7 mArg7;
+ Tin8 mArg8;
+};
+
+template <typename ObjectWrapper, typename Res,
+ typename Tin1, typename Tin2, typename Tin3,
+ typename Tin4, typename Tin5, typename Tin6,
+ typename Tin7, typename Tin8, typename Tin9,
+ typename Arg1=Tin1, typename Arg2=Tin2, typename Arg3=Tin3,
+ typename Arg4=Tin4, typename Arg5=Tin5, typename Arg6=Tin6,
+ typename Arg7=Tin7, typename Arg8=Tin8, typename Arg9=Tin9>
+class DaemonNotificationRunnable9 final : public details::DaemonRunnable
+{
+public:
+ typedef typename ObjectWrapper::ObjectType ObjectType;
+ typedef DaemonNotificationRunnable9<ObjectWrapper, Res,
+ Tin1, Tin2, Tin3, Tin4, Tin5, Tin6, Tin7, Tin8, Tin9,
+ Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9> SelfType;
+
+ template <typename InitOp>
+ static already_AddRefed<SelfType> Create(
+ Res (ObjectType::*aMethod)(
+ Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9),
+ const InitOp& aInitOp)
+ {
+ RefPtr<SelfType> runnable(new SelfType(aMethod));
+ if (NS_FAILED(runnable->Init(aInitOp))) {
+ return nullptr;
+ }
+ return runnable.forget();
+ }
+
+ template <typename InitOp>
+ static void
+ Dispatch(
+ Res (ObjectType::*aMethod)(
+ Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9),
+ const InitOp& aInitOp)
+ {
+ RefPtr<SelfType> runnable = Create(aMethod, aInitOp);
+ if (!runnable) {
+ return;
+ }
+ Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable)));
+ }
+
+ NS_IMETHOD Run() override
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ ObjectType* obj = ObjectWrapper::GetInstance();
+ if (!obj) {
+ NS_WARNING("Notification handler not initialized");
+ } else {
+ ((*obj).*mMethod)(ConvertArg<Arg1>(mArg1),
+ ConvertArg<Arg2>(mArg2),
+ ConvertArg<Arg3>(mArg3),
+ ConvertArg<Arg4>(mArg4),
+ ConvertArg<Arg5>(mArg5),
+ ConvertArg<Arg6>(mArg6),
+ ConvertArg<Arg7>(mArg7),
+ ConvertArg<Arg8>(mArg8),
+ ConvertArg<Arg9>(mArg9));
+ }
+ return NS_OK;
+ }
+
+private:
+ DaemonNotificationRunnable9(
+ Res (ObjectType::*aMethod)(
+ Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9))
+ : mMethod(aMethod)
+ {
+ MOZ_ASSERT(mMethod);
+ }
+
+ template<typename InitOp>
+ nsresult Init(const InitOp& aInitOp)
+ {
+ nsresult rv = aInitOp(mArg1, mArg2, mArg3, mArg4,
+ mArg5, mArg6, mArg7, mArg8, mArg9);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return NS_OK;
+ }
+
+ Res (ObjectType::*mMethod)(
+ Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9);
+ Tin1 mArg1;
+ Tin2 mArg2;
+ Tin3 mArg3;
+ Tin4 mArg4;
+ Tin5 mArg5;
+ Tin6 mArg6;
+ Tin7 mArg7;
+ Tin8 mArg8;
+ Tin9 mArg9;
+};
+
+}
+}
+
+#endif // mozilla_ipc_DaemonRunnables_h
diff --git a/ipc/hal/DaemonSocket.cpp b/ipc/hal/DaemonSocket.cpp
new file mode 100644
index 000000000..94c36b955
--- /dev/null
+++ b/ipc/hal/DaemonSocket.cpp
@@ -0,0 +1,263 @@
+/* -*- 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 "DaemonSocket.h"
+#include "mozilla/ipc/DaemonSocketConsumer.h"
+#include "mozilla/ipc/DaemonSocketPDU.h"
+#include "mozilla/UniquePtr.h"
+#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, MOZ_COUNT_DTOR
+
+#ifdef CHROMIUM_LOG
+#undef CHROMIUM_LOG
+#endif
+
+#if defined(MOZ_WIDGET_GONK)
+#include <android/log.h>
+#define CHROMIUM_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "I/O", args);
+#else
+#include <stdio.h>
+#define IODEBUG true
+#define CHROMIUM_LOG(args...) if (IODEBUG) printf(args);
+#endif
+
+namespace mozilla {
+namespace ipc {
+
+//
+// DaemonSocketIO
+//
+
+class DaemonSocketIO final : public ConnectionOrientedSocketIO
+{
+public:
+ DaemonSocketIO(MessageLoop* aConsumerLoop,
+ MessageLoop* aIOLoop,
+ int aFd, ConnectionStatus aConnectionStatus,
+ UnixSocketConnector* aConnector,
+ DaemonSocket* aConnection,
+ DaemonSocketIOConsumer* aConsumer);
+
+ ~DaemonSocketIO();
+
+ // Methods for |DataSocketIO|
+ //
+
+ 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:
+ DaemonSocket* mConnection;
+ DaemonSocketIOConsumer* mConsumer;
+ UniquePtr<DaemonSocketPDU> mPDU;
+ bool mShuttingDownOnIOThread;
+};
+
+DaemonSocketIO::DaemonSocketIO(
+ MessageLoop* aConsumerLoop,
+ MessageLoop* aIOLoop,
+ int aFd,
+ ConnectionStatus aConnectionStatus,
+ UnixSocketConnector* aConnector,
+ DaemonSocket* aConnection,
+ DaemonSocketIOConsumer* aConsumer)
+ : ConnectionOrientedSocketIO(aConsumerLoop,
+ aIOLoop,
+ aFd,
+ aConnectionStatus,
+ aConnector)
+ , mConnection(aConnection)
+ , mConsumer(aConsumer)
+ , mShuttingDownOnIOThread(false)
+{
+ MOZ_ASSERT(mConnection);
+ MOZ_ASSERT(mConsumer);
+
+ MOZ_COUNT_CTOR_INHERITED(DaemonSocketIO, ConnectionOrientedSocketIO);
+}
+
+DaemonSocketIO::~DaemonSocketIO()
+{
+ MOZ_COUNT_DTOR_INHERITED(DaemonSocketIO, ConnectionOrientedSocketIO);
+}
+
+// |DataSocketIO|
+
+nsresult
+DaemonSocketIO::QueryReceiveBuffer(UnixSocketIOBuffer** aBuffer)
+{
+ MOZ_ASSERT(aBuffer);
+
+ if (!mPDU) {
+ /* There's only one PDU for receiving. We reuse it every time. */
+ mPDU = MakeUnique<DaemonSocketPDU>(DaemonSocketPDU::PDU_MAX_PAYLOAD_LENGTH);
+ }
+ *aBuffer = mPDU.get();
+
+ return NS_OK;
+}
+
+void
+DaemonSocketIO::ConsumeBuffer()
+{
+ MOZ_ASSERT(mConsumer);
+
+ mConsumer->Handle(*mPDU);
+}
+
+void
+DaemonSocketIO::DiscardBuffer()
+{
+ // Nothing to do.
+}
+
+// |SocketIOBase|
+
+SocketBase*
+DaemonSocketIO::GetSocketBase()
+{
+ return mConnection;
+}
+
+bool
+DaemonSocketIO::IsShutdownOnConsumerThread() const
+{
+ MOZ_ASSERT(IsConsumerThread());
+
+ return mConnection == nullptr;
+}
+
+bool
+DaemonSocketIO::IsShutdownOnIOThread() const
+{
+ return mShuttingDownOnIOThread;
+}
+
+void
+DaemonSocketIO::ShutdownOnConsumerThread()
+{
+ MOZ_ASSERT(IsConsumerThread());
+ MOZ_ASSERT(!IsShutdownOnConsumerThread());
+
+ mConnection = nullptr;
+}
+
+void
+DaemonSocketIO::ShutdownOnIOThread()
+{
+ MOZ_ASSERT(!IsConsumerThread());
+ MOZ_ASSERT(!mShuttingDownOnIOThread);
+
+ Close(); // will also remove fd from I/O loop
+ mShuttingDownOnIOThread = true;
+}
+
+//
+// DaemonSocket
+//
+
+DaemonSocket::DaemonSocket(
+ DaemonSocketIOConsumer* aIOConsumer,
+ DaemonSocketConsumer* aConsumer,
+ int aIndex)
+ : mIO(nullptr)
+ , mIOConsumer(aIOConsumer)
+ , mConsumer(aConsumer)
+ , mIndex(aIndex)
+{
+ MOZ_ASSERT(mConsumer);
+
+ MOZ_COUNT_CTOR_INHERITED(DaemonSocket, ConnectionOrientedSocket);
+}
+
+DaemonSocket::~DaemonSocket()
+{
+ MOZ_COUNT_DTOR_INHERITED(DaemonSocket, ConnectionOrientedSocket);
+}
+
+// |ConnectionOrientedSocket|
+
+nsresult
+DaemonSocket::PrepareAccept(UnixSocketConnector* aConnector,
+ MessageLoop* aConsumerLoop,
+ MessageLoop* aIOLoop,
+ ConnectionOrientedSocketIO*& aIO)
+{
+ MOZ_ASSERT(!mIO);
+
+ SetConnectionStatus(SOCKET_CONNECTING);
+
+ mIO = new DaemonSocketIO(
+ aConsumerLoop, aIOLoop, -1, UnixSocketWatcher::SOCKET_IS_CONNECTING,
+ aConnector, this, mIOConsumer);
+ aIO = mIO;
+
+ return NS_OK;
+}
+
+// |DataSocket|
+
+void
+DaemonSocket::SendSocketData(UnixSocketIOBuffer* aBuffer)
+{
+ MOZ_ASSERT(mIO);
+ MOZ_ASSERT(mIO->IsConsumerThread());
+
+ mIO->GetIOLoop()->PostTask(
+ MakeAndAddRef<SocketIOSendTask<DaemonSocketIO, UnixSocketIOBuffer>>(
+ mIO, aBuffer));
+}
+
+// |SocketBase|
+
+void
+DaemonSocket::Close()
+{
+ if (!mIO) {
+ CHROMIUM_LOG("HAL daemon already disconnected!");
+ return;
+ }
+
+ MOZ_ASSERT(mIO->IsConsumerThread());
+
+ mIO->ShutdownOnConsumerThread();
+ mIO->GetIOLoop()->PostTask(MakeAndAddRef<SocketIOShutdownTask>(mIO));
+ mIO = nullptr;
+
+ NotifyDisconnect();
+}
+
+void
+DaemonSocket::OnConnectSuccess()
+{
+ mConsumer->OnConnectSuccess(mIndex);
+}
+
+void
+DaemonSocket::OnConnectError()
+{
+ mConsumer->OnConnectError(mIndex);
+}
+
+void
+DaemonSocket::OnDisconnect()
+{
+ mConsumer->OnDisconnect(mIndex);
+}
+
+}
+}
diff --git a/ipc/hal/DaemonSocket.h b/ipc/hal/DaemonSocket.h
new file mode 100644
index 000000000..63d3a2e5c
--- /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/hal/DaemonSocketConnector.cpp b/ipc/hal/DaemonSocketConnector.cpp
new file mode 100644
index 000000000..97106bdd0
--- /dev/null
+++ b/ipc/hal/DaemonSocketConnector.cpp
@@ -0,0 +1,244 @@
+/* -*- 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 "DaemonSocketConnector.h"
+#include <fcntl.h>
+#include <limits.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/un.h>
+#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, MOZ_COUNT_DTOR
+#include "prrng.h"
+
+#ifdef CHROMIUM_LOG
+#undef CHROMIUM_LOG
+#endif
+
+#if defined(MOZ_WIDGET_GONK)
+#include <android/log.h>
+#define CHROMIUM_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "I/O", args);
+#else
+#include <stdio.h>
+#define IODEBUG true
+#define CHROMIUM_LOG(args...) if (IODEBUG) printf(args);
+#endif
+
+namespace mozilla {
+namespace ipc {
+
+nsresult
+DaemonSocketConnector::CreateRandomAddressString(
+ const nsACString& aPrefix, unsigned long aPostfixLength,
+ nsACString& aAddress)
+{
+ static const char sHexChar[16] = {
+ [0x0] = '0', [0x1] = '1', [0x2] = '2', [0x3] = '3',
+ [0x4] = '4', [0x5] = '5', [0x6] = '6', [0x7] = '7',
+ [0x8] = '8', [0x9] = '9', [0xa] = 'a', [0xb] = 'b',
+ [0xc] = 'c', [0xd] = 'd', [0xe] = 'e', [0xf] = 'f'
+ };
+
+ unsigned short seed[3];
+
+ if (NS_WARN_IF(!PR_GetRandomNoise(seed, sizeof(seed)))) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+ }
+
+ aAddress = aPrefix;
+ aAddress.Append('-');
+
+ while (aPostfixLength) {
+ // Android doesn't provide rand_r, so we use nrand48 here,
+ // even though it's deprecated.
+ long value = nrand48(seed);
+
+ size_t bits = sizeof(value) * CHAR_BIT;
+
+ while ((bits > 4) && aPostfixLength) {
+ aAddress.Append(sHexChar[value&0xf]);
+ bits -= 4;
+ value >>= 4;
+ --aPostfixLength;
+ }
+ }
+
+ return NS_OK;
+}
+
+DaemonSocketConnector::DaemonSocketConnector(const nsACString& aSocketName)
+ : mSocketName(aSocketName)
+{
+ MOZ_COUNT_CTOR_INHERITED(DaemonSocketConnector, UnixSocketConnector);
+}
+
+DaemonSocketConnector::~DaemonSocketConnector()
+{
+ MOZ_COUNT_CTOR_INHERITED(DaemonSocketConnector, UnixSocketConnector);
+}
+
+nsresult
+DaemonSocketConnector::CreateSocket(int& aFd) const
+{
+ aFd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
+ if (aFd < 0) {
+ CHROMIUM_LOG("Could not open daemon socket!");
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+nsresult
+DaemonSocketConnector::SetSocketFlags(int aFd) const
+{
+ static const int sReuseAddress = 1;
+
+ // Set close-on-exec bit.
+ int flags = TEMP_FAILURE_RETRY(fcntl(aFd, F_GETFD));
+ if (flags < 0) {
+ return NS_ERROR_FAILURE;
+ }
+ flags |= FD_CLOEXEC;
+ int res = TEMP_FAILURE_RETRY(fcntl(aFd, F_SETFD, flags));
+ if (res < 0) {
+ return NS_ERROR_FAILURE;
+ }
+
+ // Set non-blocking status flag.
+ flags = TEMP_FAILURE_RETRY(fcntl(aFd, F_GETFL));
+ if (flags < 0) {
+ return NS_ERROR_FAILURE;
+ }
+ flags |= O_NONBLOCK;
+ res = TEMP_FAILURE_RETRY(fcntl(aFd, F_SETFL, flags));
+ if (res < 0) {
+ return NS_ERROR_FAILURE;
+ }
+
+ // Set socket addr to be reused even if kernel is still waiting to close.
+ res = setsockopt(aFd, SOL_SOCKET, SO_REUSEADDR, &sReuseAddress,
+ sizeof(sReuseAddress));
+ if (res < 0) {
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+nsresult
+DaemonSocketConnector::CreateAddress(struct sockaddr& aAddress,
+ socklen_t& aAddressLength) const
+{
+ static const size_t sNameOffset = 1;
+
+ struct sockaddr_un* address =
+ reinterpret_cast<struct sockaddr_un*>(&aAddress);
+
+ size_t namesiz = mSocketName.Length() + 1; // include trailing '\0'
+
+ if (NS_WARN_IF((sNameOffset + namesiz) > sizeof(address->sun_path))) {
+ return NS_ERROR_FAILURE;
+ }
+
+ address->sun_family = AF_UNIX;
+ memset(address->sun_path, '\0', sNameOffset); // abstract socket
+ memcpy(address->sun_path + sNameOffset, mSocketName.get(), namesiz);
+
+ aAddressLength =
+ offsetof(struct sockaddr_un, sun_path) + sNameOffset + namesiz;
+
+ return NS_OK;
+}
+
+// |UnixSocketConnector|
+
+nsresult
+DaemonSocketConnector::ConvertAddressToString(
+ const struct sockaddr& aAddress, socklen_t aAddressLength,
+ nsACString& aAddressString)
+{
+ MOZ_ASSERT(aAddress.sa_family == AF_UNIX);
+
+ const struct sockaddr_un* un =
+ reinterpret_cast<const struct sockaddr_un*>(&aAddress);
+
+ size_t len = aAddressLength - offsetof(struct sockaddr_un, sun_path);
+
+ aAddressString.Assign(un->sun_path, len);
+
+ return NS_OK;
+}
+
+nsresult
+DaemonSocketConnector::CreateListenSocket(struct sockaddr* aAddress,
+ socklen_t* aAddressLength,
+ int& aListenFd)
+{
+ ScopedClose fd;
+
+ nsresult rv = CreateSocket(fd.rwget());
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = SetSocketFlags(fd);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ if (aAddress && aAddressLength) {
+ rv = CreateAddress(*aAddress, *aAddressLength);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+
+ aListenFd = fd.forget();
+
+ return NS_OK;
+}
+
+nsresult
+DaemonSocketConnector::AcceptStreamSocket(int aListenFd,
+ struct sockaddr* aAddress,
+ socklen_t* aAddressLength,
+ int& aStreamFd)
+{
+ ScopedClose fd(
+ TEMP_FAILURE_RETRY(accept(aListenFd, aAddress, aAddressLength)));
+ if (fd < 0) {
+ CHROMIUM_LOG("Cannot accept file descriptor!");
+ return NS_ERROR_FAILURE;
+ }
+ nsresult rv = SetSocketFlags(fd);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ aStreamFd = fd.forget();
+
+ return NS_OK;
+}
+
+nsresult
+DaemonSocketConnector::CreateStreamSocket(struct sockaddr* aAddress,
+ socklen_t* aAddressLength,
+ int& aStreamFd)
+{
+ MOZ_CRASH("|DaemonSocketConnector| does not support "
+ "creating stream sockets.");
+ return NS_ERROR_ABORT;
+}
+
+nsresult
+DaemonSocketConnector::Duplicate(UnixSocketConnector*& aConnector)
+{
+ aConnector = new DaemonSocketConnector(*this);
+
+ return NS_OK;
+}
+
+} // namespace ipc
+} // namespace mozilla
diff --git a/ipc/hal/DaemonSocketConnector.h b/ipc/hal/DaemonSocketConnector.h
new file mode 100644
index 000000000..b7f2b8045
--- /dev/null
+++ b/ipc/hal/DaemonSocketConnector.h
@@ -0,0 +1,61 @@
+/* -*- 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_DaemonSocketConnector_h
+#define mozilla_ipc_DaemonSocketConnector_h
+
+#include "mozilla/ipc/UnixSocketConnector.h"
+#include "nsString.h"
+
+namespace mozilla {
+namespace ipc {
+
+class DaemonSocketConnector final : public UnixSocketConnector
+{
+public:
+ static nsresult CreateRandomAddressString(const nsACString& aPrefix,
+ unsigned long aPostfixLength,
+ nsACString& aAddress);
+
+ DaemonSocketConnector(const nsACString& aSocketName);
+ ~DaemonSocketConnector();
+
+ // Methods for |UnixSocketConnector|
+ //
+
+ nsresult ConvertAddressToString(const struct sockaddr& aAddress,
+ socklen_t aAddressLength,
+ nsACString& aAddressString) override;
+
+ nsresult CreateListenSocket(struct sockaddr* aAddress,
+ socklen_t* aAddressLength,
+ int& aListenFd) override;
+
+ nsresult AcceptStreamSocket(int aListenFd,
+ struct sockaddr* aAddress,
+ socklen_t* aAddressLen,
+ int& aStreamFd) override;
+
+ nsresult CreateStreamSocket(struct sockaddr* aAddress,
+ socklen_t* aAddressLength,
+ int& aStreamFd) override;
+
+ nsresult Duplicate(UnixSocketConnector*& aConnector) override;
+
+private:
+ nsresult CreateSocket(int& aFd) const;
+ nsresult SetSocketFlags(int aFd) const;
+ nsresult CreateAddress(struct sockaddr& aAddress,
+ socklen_t& aAddressLength) const;
+
+ nsCString mSocketName;
+};
+
+} // namespace ipc
+} // namespace mozilla
+
+#endif // mozilla_ipc_DaemonSocketConnector_h
diff --git a/ipc/hal/DaemonSocketConsumer.cpp b/ipc/hal/DaemonSocketConsumer.cpp
new file mode 100644
index 000000000..ad57d5f57
--- /dev/null
+++ b/ipc/hal/DaemonSocketConsumer.cpp
@@ -0,0 +1,33 @@
+/* -*- 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 "DaemonSocketConsumer.h"
+
+namespace mozilla {
+namespace ipc {
+
+//
+// DaemonSocketIOConsumer
+//
+
+DaemonSocketIOConsumer::DaemonSocketIOConsumer()
+{ }
+
+DaemonSocketIOConsumer::~DaemonSocketIOConsumer()
+{ }
+
+//
+// DaemonSocketConsumer
+//
+
+DaemonSocketConsumer::DaemonSocketConsumer()
+{ }
+
+DaemonSocketConsumer::~DaemonSocketConsumer()
+{ }
+
+}
+}
diff --git a/ipc/hal/DaemonSocketConsumer.h b/ipc/hal/DaemonSocketConsumer.h
new file mode 100644
index 000000000..ababab893
--- /dev/null
+++ b/ipc/hal/DaemonSocketConsumer.h
@@ -0,0 +1,68 @@
+/* -*- 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_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 StoreResultHandler(const DaemonSocketPDU& aPDU) = 0;
+
+protected:
+ DaemonSocketIOConsumer();
+};
+
+/**
+ * |DaemonSocketConsumer| handles socket events.
+ */
+class DaemonSocketConsumer
+{
+public:
+ /**
+ * Callback for socket success. Consumer-thread only.
+ *
+ * @param aIndex The index that has been given to the stream socket.
+ */
+ virtual void OnConnectSuccess(int aIndex) = 0;
+
+ /**
+ * Callback for socket errors. Consumer-thread only.
+ *
+ * @param aIndex The index that has been given to the stream socket.
+ */
+ virtual void OnConnectError(int aIndex) = 0;
+
+ /**
+ * Callback for socket disconnect. Consumer-thread only.
+ *
+ * @param aIndex The index that has been given to the stream socket.
+ */
+ virtual void OnDisconnect(int aIndex) = 0;
+
+protected:
+ DaemonSocketConsumer();
+ virtual ~DaemonSocketConsumer();
+};
+
+}
+}
+
+#endif
+
diff --git a/ipc/hal/DaemonSocketMessageHandlers.h b/ipc/hal/DaemonSocketMessageHandlers.h
new file mode 100644
index 000000000..184e687f1
--- /dev/null
+++ b/ipc/hal/DaemonSocketMessageHandlers.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=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/. */
+
+/*
+ * Message handlers
+ *
+ * This file contains base classes for message handling.
+ */
+
+#ifndef mozilla_ipc_DaemonSocketMessageHandlers_h
+#define mozilla_ipc_DaemonSocketMessageHandlers_h
+
+#include "nsISupportsImpl.h" // for ref-counting
+
+namespace mozilla {
+namespace ipc {
+
+/**
+ * |DaemonSocketResultHandler| is the base class for all protocol-specific
+ * result handlers. It currently only manages the reference counting.
+ */
+class DaemonSocketResultHandler
+{
+public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DaemonSocketResultHandler);
+
+protected:
+ DaemonSocketResultHandler()
+ { }
+ virtual ~DaemonSocketResultHandler()
+ { }
+};
+
+} // namespace ipc
+} // namespace mozilla
+
+#endif // mozilla_ipc_DaemonSocketMessageHandlers_h
diff --git a/ipc/hal/DaemonSocketPDU.cpp b/ipc/hal/DaemonSocketPDU.cpp
new file mode 100644
index 000000000..de6aa0da7
--- /dev/null
+++ b/ipc/hal/DaemonSocketPDU.cpp
@@ -0,0 +1,202 @@
+/* -*- 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"
+#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, MOZ_COUNT_DTOR
+
+#ifdef CHROMIUM_LOG
+#undef CHROMIUM_LOG
+#endif
+
+#if defined(MOZ_WIDGET_GONK)
+#include <android/log.h>
+#define CHROMIUM_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "I/O", args);
+#else
+#include <stdio.h>
+#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)
+{
+ MOZ_COUNT_CTOR_INHERITED(DaemonSocketPDU, UnixSocketIOBuffer);
+
+ // Allocate memory
+ size_t availableSpace = PDU_HEADER_SIZE + aPayloadSize;
+ ResetBuffer(new uint8_t[availableSpace], 0, 0, availableSpace);
+
+ // Reserve PDU header
+ uint8_t* data = Append(PDU_HEADER_SIZE);
+ MOZ_ASSERT(data);
+
+ // Setup PDU header
+ data[PDU_OFF_SERVICE] = aService;
+ data[PDU_OFF_OPCODE] = aOpcode;
+ memcpy(data + PDU_OFF_LENGTH, &aPayloadSize, sizeof(aPayloadSize));
+}
+
+DaemonSocketPDU::DaemonSocketPDU(size_t aPayloadSize)
+ : mConsumer(nullptr)
+{
+ MOZ_COUNT_CTOR_INHERITED(DaemonSocketPDU, UnixSocketIOBuffer);
+
+ size_t availableSpace = PDU_HEADER_SIZE + aPayloadSize;
+ ResetBuffer(new uint8_t[availableSpace], 0, 0, availableSpace);
+}
+
+DaemonSocketPDU::~DaemonSocketPDU()
+{
+ MOZ_COUNT_DTOR_INHERITED(DaemonSocketPDU, UnixSocketIOBuffer);
+
+ UniquePtr<uint8_t[]> data(GetBuffer());
+ ResetBuffer(nullptr, 0, 0, 0);
+}
+
+void
+DaemonSocketPDU::GetHeader(uint8_t& aService, uint8_t& aOpcode,
+ uint16_t& aPayloadSize)
+{
+ memcpy(&aService, GetData(PDU_OFF_SERVICE), sizeof(aService));
+ memcpy(&aOpcode, GetData(PDU_OFF_OPCODE), sizeof(aOpcode));
+ memcpy(&aPayloadSize, GetData(PDU_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 handler in the consumer.
+ mConsumer->StoreResultHandler(*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)* MAX_NFDS)];
+
+ 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 descriptors.
+ size_t fdCount = (chdr->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr))) / sizeof(int);
+ for (size_t i = 0; i < fdCount; i++) {
+ int* receivedFd = static_cast<int*>(CMSG_DATA(chdr)) + i;
+ mReceivedFds.AppendElement(*receivedFd);
+ }
+ }
+
+ return res;
+}
+
+nsTArray<int>
+DaemonSocketPDU::AcquireFds()
+{
+ // Forget all RAII object to avoid closing the fds.
+ nsTArray<int> fds;
+ for (auto& fd : mReceivedFds) {
+ fds.AppendElement(fd.forget());
+ }
+ mReceivedFds.Clear();
+ return fds;
+}
+
+nsresult
+DaemonSocketPDU::UpdateHeader()
+{
+ size_t len = GetPayloadSize();
+ if (len >= PDU_MAX_PAYLOAD_LENGTH) {
+ return NS_ERROR_ILLEGAL_VALUE;
+ }
+ uint16_t len16 = static_cast<uint16_t>(len);
+
+ memcpy(GetData(PDU_OFF_LENGTH), &len16, sizeof(len16));
+
+ return NS_OK;
+}
+
+size_t
+DaemonSocketPDU::GetPayloadSize() const
+{
+ MOZ_ASSERT(GetSize() >= PDU_HEADER_SIZE);
+
+ return GetSize() - PDU_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 000000000..ebc4e4419
--- /dev/null
+++ b/ipc/hal/DaemonSocketPDU.h
@@ -0,0 +1,94 @@
+/* -*- 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"
+#include "mozilla/ipc/DaemonSocketMessageHandlers.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace ipc {
+
+static const size_t MAX_NFDS = 16;
+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 {
+ PDU_OFF_SERVICE = 0,
+ PDU_OFF_OPCODE = 1,
+ PDU_OFF_LENGTH = 2,
+ PDU_OFF_PAYLOAD = 4,
+ PDU_HEADER_SIZE = PDU_OFF_PAYLOAD,
+ PDU_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 SetResultHandler(DaemonSocketResultHandler* aRes)
+ {
+ mRes = aRes;
+ }
+
+ DaemonSocketResultHandler* GetResultHandler() const
+ {
+ return mRes;
+ }
+
+ void GetHeader(uint8_t& aService, uint8_t& aOpcode,
+ uint16_t& aPayloadSize);
+
+ ssize_t Send(int aFd) override;
+ ssize_t Receive(int aFd) override;
+
+ nsTArray<int> AcquireFds();
+
+ nsresult UpdateHeader();
+
+private:
+ size_t GetPayloadSize() const;
+ void OnError(const char* aFunction, int aErrno);
+
+ DaemonSocketIOConsumer* mConsumer;
+ RefPtr<DaemonSocketResultHandler> mRes;
+ nsTArray<ScopedClose> mReceivedFds;
+};
+
+}
+}
+
+#endif
+
diff --git a/ipc/hal/DaemonSocketPDUHelpers.cpp b/ipc/hal/DaemonSocketPDUHelpers.cpp
new file mode 100644
index 000000000..6aaf21c33
--- /dev/null
+++ b/ipc/hal/DaemonSocketPDUHelpers.cpp
@@ -0,0 +1,335 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=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 "DaemonSocketPDUHelpers.h"
+#include <limits>
+
+// Enable this constant to abort Gecko on IPC errors. This is helpful
+// for debugging, but should *never* be enabled by default.
+#define MOZ_HAL_ABORT_ON_IPC_ERRORS (0)
+
+#ifdef CHROMIUM_LOG
+#undef CHROMIUM_LOG
+#endif
+
+#if defined(MOZ_WIDGET_GONK)
+
+#include <android/log.h>
+
+#define CHROMIUM_LOG(args...) \
+ __android_log_print(ANDROID_LOG_INFO, "HAL-IPC", args);
+
+#define CHROMIUM_LOG_VA(fmt, ap) \
+ __android_log_vprint(ANDROID_LOG_INFO, "HAL-IPC", fmt, ap);
+
+#else
+
+#include <stdio.h>
+
+#define IODEBUG true
+#define CHROMIUM_LOG(args...) if (IODEBUG) { printf(args); }
+#define CHROMIUM_LOG_VA(fmt, ap) if (IODEBUG) { vprintf(fmt, ap); }
+
+#endif
+
+namespace mozilla {
+namespace ipc {
+namespace DaemonSocketPDUHelpers {
+
+//
+// Logging
+//
+
+namespace detail {
+
+void
+LogProtocolError(const char* aFmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, aFmt);
+ CHROMIUM_LOG_VA(aFmt, ap);
+ va_end(ap);
+
+ if (MOZ_HAL_ABORT_ON_IPC_ERRORS) {
+ MOZ_CRASH("HAL IPC protocol error");
+ }
+}
+
+} // namespace detail
+
+//
+// Conversion
+//
+
+nsresult
+Convert(bool aIn, uint8_t& aOut)
+{
+ static const uint8_t sValue[] = {
+ [false] = 0x00,
+ [true] = 0x01
+ };
+ if (MOZ_HAL_IPC_CONVERT_WARN_IF(
+ aIn >= MOZ_ARRAY_LENGTH(sValue), bool, uint8_t)) {
+ aOut = 0;
+ return NS_ERROR_ILLEGAL_VALUE;
+ }
+ aOut = sValue[aIn];
+ return NS_OK;
+}
+
+nsresult
+Convert(bool aIn, int32_t& aOut)
+{
+ uint8_t out;
+ nsresult rv = Convert(aIn, out);
+ if (NS_FAILED(rv)) {
+ out = 0; // silence compiler warning
+ return rv;
+ }
+ aOut = static_cast<int32_t>(out);
+ return NS_OK;
+}
+
+nsresult
+Convert(int aIn, uint8_t& aOut)
+{
+ if (MOZ_HAL_IPC_CONVERT_WARN_IF(
+ aIn < std::numeric_limits<uint8_t>::min(), int, uint8_t) ||
+ MOZ_HAL_IPC_CONVERT_WARN_IF(
+ aIn > std::numeric_limits<uint8_t>::max(), int, uint8_t)) {
+ aOut = 0; // silences compiler warning
+ return NS_ERROR_ILLEGAL_VALUE;
+ }
+ aOut = static_cast<uint8_t>(aIn);
+ return NS_OK;
+}
+
+nsresult
+Convert(int aIn, int16_t& aOut)
+{
+ if (MOZ_HAL_IPC_CONVERT_WARN_IF(
+ aIn < std::numeric_limits<int16_t>::min(), int, int16_t) ||
+ MOZ_HAL_IPC_CONVERT_WARN_IF(
+ aIn > std::numeric_limits<int16_t>::max(), int, int16_t)) {
+ aOut = 0; // silences compiler warning
+ return NS_ERROR_ILLEGAL_VALUE;
+ }
+ aOut = static_cast<int16_t>(aIn);
+ return NS_OK;
+}
+
+nsresult
+Convert(int aIn, int32_t& aOut)
+{
+ if (MOZ_HAL_IPC_CONVERT_WARN_IF(
+ aIn < std::numeric_limits<int32_t>::min(), int, int32_t) ||
+ MOZ_HAL_IPC_CONVERT_WARN_IF(
+ aIn > std::numeric_limits<int32_t>::max(), int, int32_t)) {
+ aOut = 0; // silences compiler warning
+ return NS_ERROR_ILLEGAL_VALUE;
+ }
+ aOut = static_cast<int32_t>(aIn);
+ return NS_OK;
+}
+
+nsresult
+Convert(uint8_t aIn, bool& aOut)
+{
+ static const bool sBool[] = {
+ [0x00] = false,
+ [0x01] = true
+ };
+ if (MOZ_HAL_IPC_CONVERT_WARN_IF(
+ aIn >= MOZ_ARRAY_LENGTH(sBool), uint8_t, bool)) {
+ return NS_ERROR_ILLEGAL_VALUE;
+ }
+ aOut = sBool[aIn];
+ return NS_OK;
+}
+
+nsresult
+Convert(uint8_t aIn, char& aOut)
+{
+ aOut = static_cast<char>(aIn);
+ return NS_OK;
+}
+
+nsresult
+Convert(uint8_t aIn, int& aOut)
+{
+ aOut = static_cast<int>(aIn);
+ return NS_OK;
+}
+
+nsresult
+Convert(uint8_t aIn, unsigned long& aOut)
+{
+ aOut = static_cast<unsigned long>(aIn);
+ return NS_OK;
+}
+
+nsresult
+Convert(uint32_t aIn, int& aOut)
+{
+ aOut = static_cast<int>(aIn);
+ return NS_OK;
+}
+
+nsresult
+Convert(uint32_t aIn, uint8_t& aOut)
+{
+ if (MOZ_HAL_IPC_CONVERT_WARN_IF(
+ aIn < std::numeric_limits<uint8_t>::min(), uint32_t, uint8_t) ||
+ MOZ_HAL_IPC_CONVERT_WARN_IF(
+ aIn > std::numeric_limits<uint8_t>::max(), uint32_t, uint8_t)) {
+ aOut = 0; // silences compiler warning
+ return NS_ERROR_ILLEGAL_VALUE;
+ }
+ aOut = static_cast<uint8_t>(aIn);
+ return NS_OK;
+}
+
+nsresult
+Convert(size_t aIn, uint16_t& aOut)
+{
+ if (MOZ_HAL_IPC_CONVERT_WARN_IF(aIn >= (1ul << 16), size_t, uint16_t)) {
+ aOut = 0; // silences compiler warning
+ return NS_ERROR_ILLEGAL_VALUE;
+ }
+ aOut = static_cast<uint16_t>(aIn);
+ return NS_OK;
+}
+
+//
+// Packing
+//
+
+nsresult
+PackPDU(bool aIn, DaemonSocketPDU& aPDU)
+{
+ return PackPDU(PackConversion<bool, uint8_t>(aIn), aPDU);
+}
+
+nsresult
+PackPDU(const DaemonSocketPDUHeader& aIn, DaemonSocketPDU& aPDU)
+{
+ nsresult rv = PackPDU(aIn.mService, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn.mOpcode, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn.mLength, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return NS_OK;
+}
+
+//
+// Unpacking
+//
+
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, bool& aOut)
+{
+ return UnpackPDU(aPDU, UnpackConversion<uint8_t, bool>(aOut));
+}
+
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, char& aOut)
+{
+ return UnpackPDU(aPDU, UnpackConversion<uint8_t, char>(aOut));
+}
+
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, nsDependentCString& aOut)
+{
+ // We get a pointer to the first character in the PDU, a length
+ // of 1 ensures we consume the \0 byte. With 'str' pointing to
+ // the string in the PDU, we can copy the actual bytes.
+
+ const char* str = reinterpret_cast<const char*>(aPDU.Consume(1));
+ if (MOZ_HAL_IPC_UNPACK_WARN_IF(!str, nsDependentCString)) {
+ return NS_ERROR_ILLEGAL_VALUE; // end of PDU
+ }
+
+ const char* end = static_cast<char*>(memchr(str, '\0', aPDU.GetSize() + 1));
+ if (MOZ_HAL_IPC_UNPACK_WARN_IF(!end, nsDependentCString)) {
+ return NS_ERROR_ILLEGAL_VALUE; // no string terminator
+ }
+
+ ptrdiff_t len = end - str;
+
+ const uint8_t* rest = aPDU.Consume(len);
+ if (MOZ_HAL_IPC_UNPACK_WARN_IF(!rest, nsDependentCString)) {
+ // We couldn't consume bytes that should have been there.
+ return NS_ERROR_ILLEGAL_VALUE;
+ }
+
+ aOut.Rebind(str, len);
+
+ return NS_OK;
+}
+
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, const UnpackCString0& aOut)
+{
+ nsDependentCString cstring;
+
+ nsresult rv = UnpackPDU(aPDU, cstring);
+ if (NS_FAILED(rv)) {
+ return NS_ERROR_ILLEGAL_VALUE;
+ }
+
+ aOut.mString->AssignASCII(cstring.get(), cstring.Length());
+
+ return NS_OK;
+}
+
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, const UnpackString0& aOut)
+{
+ nsDependentCString cstring;
+
+ nsresult rv = UnpackPDU(aPDU, cstring);
+ if (NS_FAILED(rv)) {
+ return NS_ERROR_ILLEGAL_VALUE;
+ }
+
+ *aOut.mString = NS_ConvertUTF8toUTF16(cstring);
+
+ return NS_OK;
+}
+
+//
+// Init operators
+//
+
+void
+PDUInitOp::WarnAboutTrailingData() const
+{
+ size_t size = mPDU->GetSize();
+
+ if (MOZ_LIKELY(!size)) {
+ return;
+ }
+
+ uint8_t service, opcode;
+ uint16_t payloadSize;
+ mPDU->GetHeader(service, opcode, payloadSize);
+
+ detail::LogProtocolError(
+ "Unpacked PDU of type (%x,%x) still contains %zu Bytes of data.",
+ service, opcode, size);
+}
+
+} // namespace DaemonSocketPDUHelpers
+} // namespace ipc
+} // namespace mozilla
diff --git a/ipc/hal/DaemonSocketPDUHelpers.h b/ipc/hal/DaemonSocketPDUHelpers.h
new file mode 100644
index 000000000..38a848e46
--- /dev/null
+++ b/ipc/hal/DaemonSocketPDUHelpers.h
@@ -0,0 +1,1283 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=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_DaemonSocketPDUHelpers_h
+#define mozilla_ipc_DaemonSocketPDUHelpers_h
+
+#include <stdint.h>
+#include "mozilla/ipc/DaemonSocketPDU.h"
+#include "mozilla/UniquePtr.h"
+#include "nsString.h"
+
+namespace mozilla {
+namespace ipc {
+
+struct DaemonSocketPDUHeader {
+ DaemonSocketPDUHeader()
+ : mService(0x00)
+ , mOpcode(0x00)
+ , mLength(0x00)
+ { }
+
+ DaemonSocketPDUHeader(uint8_t aService, uint8_t aOpcode, uint16_t aLength)
+ : mService(aService)
+ , mOpcode(aOpcode)
+ , mLength(aLength)
+ { }
+
+ uint8_t mService;
+ uint8_t mOpcode;
+ uint16_t mLength;
+};
+
+namespace DaemonSocketPDUHelpers {
+
+//
+// Logging
+//
+// The HAL IPC logging macros below print clear error messages for
+// failed IPC operations. Use |MOZ_HAL_IPC_CONVERT_WARN_IF|,
+// |MOZ_HAL_IPC_PACK_WARN_IF| and |MOZ_HAL_IPC_UNPACK_WARN_IF| to
+// test for failures when processing PDUs.
+//
+// All macros accept the test condition as their first argument, and
+// additional type information: the convert macro takes the input and
+// output types, the pack macro takes the input type, and the unpack
+// macro takes output type. All macros return the result of the test
+// condition. If the test fails (i.e., the condition is true), they
+// output a warning to the log.
+//
+// Don't call the functions in the detail namespace. They are helpers
+// and not for general use.
+//
+
+namespace detail {
+
+void
+LogProtocolError(const char*, ...);
+
+inline bool
+ConvertWarnIfImpl(const char* aFile, unsigned long aLine,
+ bool aCondition, const char* aExpr, const char* aIn,
+ const char* aOut)
+{
+ if (MOZ_UNLIKELY(aCondition)) {
+ LogProtocolError("%s:%d: Convert('%s' to '%s') failed: %s",
+ aFile, aLine, aIn, aOut, aExpr);
+ }
+ return aCondition;
+}
+
+inline bool
+PackWarnIfImpl(const char* aFile, unsigned long aLine,
+ bool aCondition, const char* aExpr, const char* aIn)
+{
+ if (MOZ_UNLIKELY(aCondition)) {
+ LogProtocolError("%s:%d: Pack('%s') failed: %s",
+ aFile, aLine, aIn, aExpr);
+ }
+ return aCondition;
+}
+
+inline bool
+UnpackWarnIfImpl(const char* aFile, unsigned long aLine,
+ bool aCondition, const char* aExpr, const char* aOut)
+{
+ if (MOZ_UNLIKELY(aCondition)) {
+ LogProtocolError("%s:%d: Unpack('%s') failed: %s",
+ aFile, aLine, aOut, aExpr);
+ }
+ return aCondition;
+}
+
+} // namespace detail
+
+#define MOZ_HAL_IPC_CONVERT_WARN_IF(condition, in, out) \
+ ::mozilla::ipc::DaemonSocketPDUHelpers::detail:: \
+ ConvertWarnIfImpl(__FILE__, __LINE__, condition, #condition, #in, #out)
+
+#define MOZ_HAL_IPC_PACK_WARN_IF(condition, in) \
+ ::mozilla::ipc::DaemonSocketPDUHelpers::detail:: \
+ PackWarnIfImpl(__FILE__, __LINE__, condition, #condition, #in)
+
+#define MOZ_HAL_IPC_UNPACK_WARN_IF(condition, out) \
+ ::mozilla::ipc::DaemonSocketPDUHelpers::detail:: \
+ UnpackWarnIfImpl(__FILE__, __LINE__, condition, #condition, #out)
+
+//
+// Conversion
+//
+// PDUs can only store primitive data types, such as integers or
+// byte arrays. Gecko often uses more complex data types, such as
+// enumators or stuctures. Conversion functions convert between
+// primitive data and internal Gecko's data types during a PDU's
+// packing and unpacking.
+//
+
+nsresult
+Convert(bool aIn, uint8_t& aOut);
+
+nsresult
+Convert(bool aIn, int32_t& aOut);
+
+nsresult
+Convert(int aIn, uint8_t& aOut);
+
+nsresult
+Convert(int aIn, int16_t& aOut);
+
+nsresult
+Convert(int aIn, int32_t& aOut);
+
+nsresult
+Convert(uint8_t aIn, bool& aOut);
+
+nsresult
+Convert(uint8_t aIn, char& aOut);
+
+nsresult
+Convert(uint8_t aIn, int& aOut);
+
+nsresult
+Convert(uint8_t aIn, unsigned long& aOut);
+
+nsresult
+Convert(uint32_t aIn, int& aOut);
+
+nsresult
+Convert(uint32_t aIn, uint8_t& aOut);
+
+nsresult
+Convert(size_t aIn, uint16_t& aOut);
+
+//
+// Packing
+//
+
+// introduce link errors on non-handled data types
+template <typename T>
+nsresult
+PackPDU(T aIn, DaemonSocketPDU& aPDU);
+
+nsresult
+PackPDU(bool aIn, DaemonSocketPDU& aPDU);
+
+inline nsresult
+PackPDU(uint8_t aIn, DaemonSocketPDU& aPDU)
+{
+ return aPDU.Write(aIn);
+}
+
+inline nsresult
+PackPDU(uint16_t aIn, DaemonSocketPDU& aPDU)
+{
+ return aPDU.Write(aIn);
+}
+
+inline nsresult
+PackPDU(int32_t aIn, DaemonSocketPDU& aPDU)
+{
+ return aPDU.Write(aIn);
+}
+
+inline nsresult
+PackPDU(uint32_t aIn, DaemonSocketPDU& aPDU)
+{
+ return aPDU.Write(aIn);
+}
+
+inline nsresult
+PackPDU(int64_t aIn, DaemonSocketPDU& aPDU)
+{
+ return aPDU.Write(aIn);
+}
+
+inline nsresult
+PackPDU(uint64_t aIn, DaemonSocketPDU& aPDU)
+{
+ return aPDU.Write(aIn);
+}
+
+inline nsresult
+PackPDU(float aIn, DaemonSocketPDU& aPDU)
+{
+ return aPDU.Write(aIn);
+}
+
+inline nsresult
+PackPDU(double aIn, DaemonSocketPDU& aPDU)
+{
+ return aPDU.Write(aIn);
+}
+
+nsresult
+PackPDU(const DaemonSocketPDUHeader& aIn, DaemonSocketPDU& aPDU);
+
+/* |PackConversion| is a helper for packing converted values. Pass
+ * an instance of this structure to |PackPDU| to convert a value from
+ * the input type to the output type and and write it to the PDU.
+ */
+template<typename Tin, typename Tout>
+struct PackConversion {
+ PackConversion(const Tin& aIn)
+ : mIn(aIn)
+ { }
+
+ const Tin& mIn;
+};
+
+template<typename Tin, typename Tout>
+inline nsresult
+PackPDU(const PackConversion<Tin, Tout>& aIn, DaemonSocketPDU& aPDU)
+{
+ Tout out;
+
+ nsresult rv = Convert(aIn.mIn, out);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return PackPDU(out, aPDU);
+}
+
+/* |PackArray| is a helper for packing arrays. Pass an instance
+ * of this structure as the first argument to |PackPDU| to pack
+ * an array. The array's maximum default length is 255 elements.
+ */
+template <typename T>
+struct PackArray
+{
+ PackArray(const T* aData, size_t aLength)
+ : mData(aData)
+ , mLength(aLength)
+ { }
+
+ const T* mData;
+ size_t mLength;
+};
+
+/* This implementation of |PackPDU| packs the length of an array
+ * and the elements of the array one-by-one.
+ */
+template<typename T>
+inline nsresult
+PackPDU(const PackArray<T>& aIn, DaemonSocketPDU& aPDU)
+{
+ for (size_t i = 0; i < aIn.mLength; ++i) {
+ nsresult rv = PackPDU(aIn.mData[i], aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+ return NS_OK;
+}
+
+template<>
+inline nsresult
+PackPDU<uint8_t>(const PackArray<uint8_t>& aIn, DaemonSocketPDU& aPDU)
+{
+ /* Write raw bytes in one pass */
+ return aPDU.Write(aIn.mData, aIn.mLength);
+}
+
+template<>
+inline nsresult
+PackPDU<char>(const PackArray<char>& aIn, DaemonSocketPDU& aPDU)
+{
+ /* Write raw bytes in one pass */
+ return aPDU.Write(aIn.mData, aIn.mLength);
+}
+
+/* |PackCString0| is a helper for packing 0-terminated C string,
+ * including the \0 character. Pass an instance of this structure
+ * as the first argument to |PackPDU| to pack a string.
+ */
+struct PackCString0
+{
+ PackCString0(const nsCString& aString)
+ : mString(aString)
+ { }
+
+ const nsCString& mString;
+};
+
+/* This implementation of |PackPDU| packs a 0-terminated C string.
+ */
+inline nsresult
+PackPDU(const PackCString0& aIn, DaemonSocketPDU& aPDU)
+{
+ return PackPDU(
+ PackArray<uint8_t>(reinterpret_cast<const uint8_t*>(aIn.mString.get()),
+ aIn.mString.Length() + 1), aPDU);
+}
+
+/* |PackReversed| is a helper for packing data in reversed order. Pass an
+ * instance of this structure as the first argument to |PackPDU| to pack data
+ * in reversed order.
+ */
+template<typename T>
+struct PackReversed
+{
+ PackReversed(const T& aValue)
+ : mValue(aValue)
+ { }
+
+ const T& mValue;
+};
+
+/* No general rules to pack data in reversed order. Signal a link error if the
+ * type |T| of |PackReversed| is not defined explicitly.
+ */
+template<typename T>
+nsresult
+PackPDU(const PackReversed<T>& aIn, DaemonSocketPDU& aPDU);
+
+/* This implementation of |PackPDU| packs elements in |PackArray| in reversed
+ * order. (ex. reversed GATT UUID, see bug 1171866)
+ */
+template<typename U>
+inline nsresult
+PackPDU(const PackReversed<PackArray<U>>& aIn, DaemonSocketPDU& aPDU)
+{
+ for (size_t i = 0; i < aIn.mValue.mLength; ++i) {
+ nsresult rv = PackPDU(aIn.mValue.mData[aIn.mValue.mLength - i - 1], aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+ return NS_OK;
+}
+
+/* |PackArray<PackReversed<U>>| is a helper for packing data of each element in
+ * the reversed order. Pass an instance of this structure as the first argument
+ * to |PackPDU| to pack data of each array element in the reversed order.
+ *
+ * Unlike |PackReversed<PackArray<U>>| which packed array elements in the
+ * reversed order, here we use |PackReversed<U>| to pack data of each element
+ * of |PackArray| in the reversed order.
+ */
+template<typename U>
+struct PackArray<PackReversed<U>>
+{
+ PackArray(const U* aData, size_t aLength)
+ : mData(aData)
+ , mLength(aLength)
+ { }
+
+ const U* mData;
+ size_t mLength;
+};
+
+/* This implementation of |PackPDU| packs data of each element in |PackArray|
+ * in the reversed order. (ex. reversed GATT UUID, see bug 1171866)
+ */
+template<typename U>
+inline nsresult
+PackPDU(const PackArray<PackReversed<U>>& aIn, DaemonSocketPDU& aPDU)
+{
+ for (size_t i = 0; i < aIn.mLength; ++i) {
+ nsresult rv = PackPDU(PackReversed<U>(aIn.mData[i]), aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+ return NS_OK;
+}
+
+template <typename T1, typename T2>
+inline nsresult
+PackPDU(const T1& aIn1, const T2& aIn2, DaemonSocketPDU& aPDU)
+{
+ nsresult rv = PackPDU(aIn1, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return PackPDU(aIn2, aPDU);
+}
+
+template <typename T1, typename T2, typename T3>
+inline nsresult
+PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
+ DaemonSocketPDU& aPDU)
+{
+ nsresult rv = PackPDU(aIn1, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn2, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return PackPDU(aIn3, aPDU);
+}
+
+template <typename T1, typename T2, typename T3, typename T4>
+inline nsresult
+PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3, const T4& aIn4,
+ DaemonSocketPDU& aPDU)
+{
+ nsresult rv = PackPDU(aIn1, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn2, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn3, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return PackPDU(aIn4, aPDU);
+}
+
+template <typename T1, typename T2, typename T3,
+ typename T4, typename T5>
+inline nsresult
+PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
+ const T4& aIn4, const T5& aIn5,
+ DaemonSocketPDU& aPDU)
+{
+ nsresult rv = PackPDU(aIn1, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn2, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn3, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn4, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return PackPDU(aIn5, aPDU);
+}
+
+template <typename T1, typename T2, typename T3,
+ typename T4, typename T5, typename T6>
+inline nsresult
+PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
+ const T4& aIn4, const T5& aIn5, const T6& aIn6,
+ DaemonSocketPDU& aPDU)
+{
+ nsresult rv = PackPDU(aIn1, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn2, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn3, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn4, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn5, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return PackPDU(aIn6, aPDU);
+}
+
+template <typename T1, typename T2, typename T3,
+ typename T4, typename T5, typename T6,
+ typename T7>
+inline nsresult
+PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
+ const T4& aIn4, const T5& aIn5, const T6& aIn6,
+ const T7& aIn7, DaemonSocketPDU& aPDU)
+{
+ nsresult rv = PackPDU(aIn1, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn2, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn3, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn4, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn5, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn6, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return PackPDU(aIn7, aPDU);
+}
+
+template <typename T1, typename T2, typename T3,
+ typename T4, typename T5, typename T6,
+ typename T7, typename T8>
+inline nsresult
+PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
+ const T4& aIn4, const T5& aIn5, const T6& aIn6,
+ const T7& aIn7, const T8& aIn8, DaemonSocketPDU& aPDU)
+{
+ nsresult rv = PackPDU(aIn1, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn2, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn3, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn4, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn5, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn6, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn7, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return PackPDU(aIn8, aPDU);
+}
+
+template <typename T1, typename T2, typename T3,
+ typename T4, typename T5, typename T6,
+ typename T7, typename T8, typename T9,
+ typename T10, typename T11, typename T12,
+ typename T13>
+inline nsresult
+PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
+ const T4& aIn4, const T5& aIn5, const T6& aIn6,
+ const T7& aIn7, const T8& aIn8, const T9& aIn9,
+ const T10& aIn10, const T11& aIn11, const T12& aIn12,
+ const T13& aIn13, DaemonSocketPDU& aPDU)
+{
+ nsresult rv = PackPDU(aIn1, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn2, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn3, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn4, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn5, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn6, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn7, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn8, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn9, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn10, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn11, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn12, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return PackPDU(aIn13, aPDU);
+}
+
+//
+// Unpacking
+//
+
+// introduce link errors on non-handled data types
+template <typename T>
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, T& aOut);
+
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, bool& aOut);
+
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, char& aOut);
+
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, int8_t& aOut)
+{
+ return aPDU.Read(aOut);
+}
+
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, uint8_t& aOut)
+{
+ return aPDU.Read(aOut);
+}
+
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, uint16_t& aOut)
+{
+ return aPDU.Read(aOut);
+}
+
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, int32_t& aOut)
+{
+ return aPDU.Read(aOut);
+}
+
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, uint32_t& aOut)
+{
+ return aPDU.Read(aOut);
+}
+
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, int64_t& aOut)
+{
+ return aPDU.Read(aOut);
+}
+
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, uint64_t& aOut)
+{
+ return aPDU.Read(aOut);
+}
+
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, float& aOut)
+{
+ return aPDU.Read(aOut);
+}
+
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, double& aOut)
+{
+ return aPDU.Read(aOut);
+}
+
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, DaemonSocketPDUHeader& aOut)
+{
+ nsresult rv = UnpackPDU(aPDU, aOut.mService);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(aPDU, aOut.mOpcode);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return UnpackPDU(aPDU, aOut.mLength);
+}
+
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, nsDependentCString& aOut);
+
+/* |UnpackCString0| is a helper for unpacking 0-terminated C string,
+ * including the \0 character. Pass an instance of this structure
+ * as the first argument to |UnpackPDU| to unpack a string.
+ */
+struct UnpackCString0
+{
+ UnpackCString0(nsCString& aString)
+ : mString(&aString)
+ { }
+
+ nsCString* mString; // non-null by construction
+};
+
+/* This implementation of |UnpackPDU| unpacks a 0-terminated C string.
+ */
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, const UnpackCString0& aOut);
+
+/* |UnpackString0| is a helper for unpacking 0-terminated C string,
+ * including the \0 character. Pass an instance of this structure
+ * as the first argument to |UnpackPDU| to unpack a C string and convert
+ * it to wide-character encoding.
+ */
+struct UnpackString0
+{
+ UnpackString0(nsString& aString)
+ : mString(&aString)
+ { }
+
+ nsString* mString; // non-null by construction
+};
+
+/* This implementation of |UnpackPDU| unpacks a 0-terminated C string
+ * and converts it to wide-character encoding.
+ */
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, const UnpackString0& aOut);
+
+/* |UnpackConversion| is a helper for convering unpacked values. Pass
+ * an instance of this structure to |UnpackPDU| to read a value from
+ * the PDU in the input type and convert it to the output type.
+ */
+template<typename Tin, typename Tout>
+struct UnpackConversion {
+ UnpackConversion(Tout& aOut)
+ : mOut(aOut)
+ { }
+
+ Tout& mOut;
+};
+
+template<typename Tin, typename Tout>
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, const UnpackConversion<Tin, Tout>& aOut)
+{
+ Tin in;
+ nsresult rv = UnpackPDU(aPDU, in);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return Convert(in, aOut.mOut);
+}
+
+/* |UnpackArray| is a helper for unpacking arrays. Pass an instance
+ * of this structure as the second argument to |UnpackPDU| to unpack
+ * an array.
+ */
+template <typename T>
+struct UnpackArray
+{
+ UnpackArray(T* aData, size_t aLength)
+ : mData(aData)
+ , mLength(aLength)
+ { }
+
+ UnpackArray(UniquePtr<T[]>& aData, size_t aLength)
+ : mData(nullptr)
+ , mLength(aLength)
+ {
+ aData.reset(new T[mLength]);
+ mData = aData.get();
+ }
+
+ UnpackArray(UniquePtr<T>& aData, size_t aSize, size_t aElemSize)
+ : mData(nullptr)
+ , mLength(aSize / aElemSize)
+ {
+ aData.reset(new T[mLength]);
+ mData = aData.get();
+ }
+
+ T* mData;
+ size_t mLength;
+};
+
+template<typename T>
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, const UnpackArray<T>& aOut)
+{
+ for (size_t i = 0; i < aOut.mLength; ++i) {
+ nsresult rv = UnpackPDU(aPDU, aOut.mData[i]);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+ return NS_OK;
+}
+
+template<typename T>
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, UnpackArray<T>& aOut)
+{
+ for (size_t i = 0; i < aOut.mLength; ++i) {
+ nsresult rv = UnpackPDU(aPDU, aOut.mData[i]);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+ return NS_OK;
+}
+
+template<>
+inline nsresult
+UnpackPDU<uint8_t>(DaemonSocketPDU& aPDU, const UnpackArray<uint8_t>& aOut)
+{
+ /* Read raw bytes in one pass */
+ return aPDU.Read(aOut.mData, aOut.mLength);
+}
+
+template<typename T>
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, nsTArray<T>& aOut)
+{
+ for (typename nsTArray<T>::size_type i = 0; i < aOut.Length(); ++i) {
+ nsresult rv = UnpackPDU(aPDU, aOut[i]);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+ return NS_OK;
+}
+
+/* |UnpackReversed| is a helper for unpacking data in reversed order. Pass an
+ * instance of this structure as the second argument to |UnpackPDU| to unpack
+ * data in reversed order.
+ */
+template<typename T>
+struct UnpackReversed
+{
+ UnpackReversed(T& aValue)
+ : mValue(&aValue)
+ { }
+
+ UnpackReversed(T&& aValue)
+ : mValue(&aValue)
+ { }
+
+ T* mValue;
+};
+
+/* No general rules to unpack data in reversed order. Signal a link error if
+ * the type |T| of |UnpackReversed| is not defined explicitly.
+ */
+template<typename T>
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, const UnpackReversed<T>& aOut);
+
+template<typename U>
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, const UnpackReversed<UnpackArray<U>>& aOut)
+{
+ for (size_t i = 0; i < aOut.mValue->mLength; ++i) {
+ nsresult rv = UnpackPDU(aPDU,
+ aOut.mValue->mData[aOut.mValue->mLength - i - 1]);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+ return NS_OK;
+}
+
+//
+// Init operators
+//
+
+//
+// Below are general-purpose init operators for Bluetooth. The classes
+// of type |ConstantInitOp[1..3]| initialize results or notifications
+// with constant values.
+//
+
+template <typename T1>
+class ConstantInitOp1 final
+{
+public:
+ ConstantInitOp1(const T1& aArg1)
+ : mArg1(aArg1)
+ { }
+
+ nsresult operator () (T1& aArg1) const
+ {
+ aArg1 = mArg1;
+
+ return NS_OK;
+ }
+
+private:
+ const T1& mArg1;
+};
+
+template <typename T1, typename T2>
+class ConstantInitOp2 final
+{
+public:
+ ConstantInitOp2(const T1& aArg1, const T2& aArg2)
+ : mArg1(aArg1)
+ , mArg2(aArg2)
+ { }
+
+ nsresult operator () (T1& aArg1, T2& aArg2) const
+ {
+ aArg1 = mArg1;
+ aArg2 = mArg2;
+
+ return NS_OK;
+ }
+
+private:
+ const T1& mArg1;
+ const T2& mArg2;
+};
+
+template <typename T1, typename T2, typename T3>
+class ConstantInitOp3 final
+{
+public:
+ ConstantInitOp3(const T1& aArg1, const T2& aArg2, const T3& aArg3)
+ : mArg1(aArg1)
+ , mArg2(aArg2)
+ , mArg3(aArg3)
+ { }
+
+ nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3) const
+ {
+ aArg1 = mArg1;
+ aArg2 = mArg2;
+ aArg3 = mArg3;
+
+ return NS_OK;
+ }
+
+private:
+ const T1& mArg1;
+ const T2& mArg2;
+ const T3& mArg3;
+};
+
+// |PDUInitOP| provides functionality for init operators that unpack PDUs.
+class PDUInitOp
+{
+protected:
+ PDUInitOp(DaemonSocketPDU& aPDU)
+ : mPDU(&aPDU)
+ { }
+
+ DaemonSocketPDU& GetPDU() const
+ {
+ return *mPDU; // cannot be nullptr
+ }
+
+ void WarnAboutTrailingData() const;
+
+private:
+ DaemonSocketPDU* mPDU; // Hold pointer to allow for constant instances
+};
+
+// |UnpackPDUInitOp| is a general-purpose init operator for all variants
+// of |DaemonResultRunnable| and |DaemonNotificationRunnable|. The call
+// operators of |UnpackPDUInitOp| unpack a PDU into the supplied
+// arguments.
+class UnpackPDUInitOp final : private PDUInitOp
+{
+public:
+ UnpackPDUInitOp(DaemonSocketPDU& aPDU)
+ : PDUInitOp(aPDU)
+ { }
+
+ nsresult operator () () const
+ {
+ WarnAboutTrailingData();
+ return NS_OK;
+ }
+
+ template<typename T1>
+ nsresult operator () (T1& aArg1) const
+ {
+ nsresult rv = UnpackPDU(GetPDU(), aArg1);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ WarnAboutTrailingData();
+ return NS_OK;
+ }
+
+ template<typename T1, typename T2>
+ nsresult operator () (T1& aArg1, T2& aArg2) const
+ {
+ DaemonSocketPDU& pdu = GetPDU();
+
+ nsresult rv = UnpackPDU(pdu, aArg1);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg2);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ WarnAboutTrailingData();
+ return NS_OK;
+ }
+
+ template<typename T1, typename T2, typename T3>
+ nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3) const
+ {
+ DaemonSocketPDU& pdu = GetPDU();
+
+ nsresult rv = UnpackPDU(pdu, aArg1);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg2);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg3);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ WarnAboutTrailingData();
+ return NS_OK;
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4>
+ nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4) const
+ {
+ DaemonSocketPDU& pdu = GetPDU();
+
+ nsresult rv = UnpackPDU(pdu, aArg1);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg2);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg3);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg4);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ WarnAboutTrailingData();
+ return NS_OK;
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4, typename T5>
+ nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4,
+ T5& aArg5) const
+ {
+ DaemonSocketPDU& pdu = GetPDU();
+
+ nsresult rv = UnpackPDU(pdu, aArg1);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg2);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg3);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg4);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg5);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ WarnAboutTrailingData();
+ return NS_OK;
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6>
+ nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4,
+ T5& aArg5, T6& aArg6) const
+ {
+ DaemonSocketPDU& pdu = GetPDU();
+
+ nsresult rv = UnpackPDU(pdu, aArg1);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg2);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg3);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg4);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg5);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg6);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ WarnAboutTrailingData();
+ return NS_OK;
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+ nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4,
+ T5& aArg5, T6& aArg6, T7& aArg7) const
+ {
+ DaemonSocketPDU& pdu = GetPDU();
+
+ nsresult rv = UnpackPDU(pdu, aArg1);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg2);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg3);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg4);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg5);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg6);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg7);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ WarnAboutTrailingData();
+ return NS_OK;
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+ nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4,
+ T5& aArg5, T6& aArg6, T7& aArg7, T8& aArg8) const
+ {
+ DaemonSocketPDU& pdu = GetPDU();
+
+ nsresult rv = UnpackPDU(pdu, aArg1);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg2);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg3);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg4);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg5);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg6);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg7);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg8);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ WarnAboutTrailingData();
+ return NS_OK;
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+ nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4,
+ T5& aArg5, T6& aArg6, T7& aArg7, T8& aArg8,
+ T9& aArg9) const
+ {
+ DaemonSocketPDU& pdu = GetPDU();
+
+ nsresult rv = UnpackPDU(pdu, aArg1);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg2);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg3);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg4);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg5);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg6);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg7);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg8);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg9);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ WarnAboutTrailingData();
+ return NS_OK;
+ }
+};
+
+} // namespace DaemonSocketPDUHelpers
+
+} // namespace ipc
+} // namespace mozilla
+
+#endif // mozilla_ipc_DaemonSocketPDUHelpers_h
diff --git a/ipc/hal/moz.build b/ipc/hal/moz.build
new file mode 100644
index 000000000..e97963b1e
--- /dev/null
+++ b/ipc/hal/moz.build
@@ -0,0 +1,27 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+EXPORTS.mozilla.ipc += [
+ 'DaemonRunnables.h',
+ 'DaemonSocket.h',
+ 'DaemonSocketConnector.h',
+ 'DaemonSocketConsumer.h',
+ 'DaemonSocketMessageHandlers.h',
+ 'DaemonSocketPDU.h',
+ 'DaemonSocketPDUHelpers.h'
+]
+
+UNIFIED_SOURCES += [
+ 'DaemonSocket.cpp',
+ 'DaemonSocketConnector.cpp',
+ 'DaemonSocketConsumer.cpp',
+ 'DaemonSocketPDU.cpp',
+ 'DaemonSocketPDUHelpers.cpp'
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'