From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- ipc/hal/DaemonRunnables.h | 950 ++++++++++++++++++++++++ ipc/hal/DaemonSocket.cpp | 263 +++++++ ipc/hal/DaemonSocket.h | 63 ++ ipc/hal/DaemonSocketConnector.cpp | 244 +++++++ ipc/hal/DaemonSocketConnector.h | 61 ++ ipc/hal/DaemonSocketConsumer.cpp | 33 + ipc/hal/DaemonSocketConsumer.h | 68 ++ ipc/hal/DaemonSocketMessageHandlers.h | 40 + ipc/hal/DaemonSocketPDU.cpp | 202 ++++++ ipc/hal/DaemonSocketPDU.h | 94 +++ ipc/hal/DaemonSocketPDUHelpers.cpp | 335 +++++++++ ipc/hal/DaemonSocketPDUHelpers.h | 1283 +++++++++++++++++++++++++++++++++ ipc/hal/moz.build | 27 + 13 files changed, 3663 insertions(+) create mode 100644 ipc/hal/DaemonRunnables.h create mode 100644 ipc/hal/DaemonSocket.cpp create mode 100644 ipc/hal/DaemonSocket.h create mode 100644 ipc/hal/DaemonSocketConnector.cpp create mode 100644 ipc/hal/DaemonSocketConnector.h create mode 100644 ipc/hal/DaemonSocketConsumer.cpp create mode 100644 ipc/hal/DaemonSocketConsumer.h create mode 100644 ipc/hal/DaemonSocketMessageHandlers.h create mode 100644 ipc/hal/DaemonSocketPDU.cpp create mode 100644 ipc/hal/DaemonSocketPDU.h create mode 100644 ipc/hal/DaemonSocketPDUHelpers.cpp create mode 100644 ipc/hal/DaemonSocketPDUHelpers.h create mode 100644 ipc/hal/moz.build (limited to 'ipc/hal') 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 + static Out& ConvertArg(In& aArg) + { + return aArg; + } + + template + static Out ConvertArg(UniquePtr& 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 +class DaemonResultRunnable0 final : public details::DaemonRunnable +{ +public: + typedef DaemonResultRunnable0 SelfType; + + template + static already_AddRefed + Create(Obj* aObj, Res (Obj::*aMethod)(), const InitOp& aInitOp) + { + RefPtr runnable(new SelfType(aObj, aMethod)); + if (NS_FAILED(runnable->Init(aInitOp))) { + return nullptr; + } + return runnable.forget(); + } + + template + static void + Dispatch(Obj* aObj, Res (Obj::*aMethod)(), const InitOp& aInitOp) + { + if (!aObj) { + return; // silently return if no result runnable has been given + } + RefPtr 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 + nsresult Init(const InitOp& aInitOp) + { + return aInitOp(); + } + + RefPtr mObj; + void (Obj::*mMethod)(); +}; + +template +class DaemonResultRunnable1 final : public details::DaemonRunnable +{ +public: + typedef DaemonResultRunnable1 SelfType; + + template + static already_AddRefed + Create(Obj* aObj, Res (Obj::*aMethod)(Arg1), const InitOp& aInitOp) + { + RefPtr runnable(new SelfType(aObj, aMethod)); + if (NS_FAILED(runnable->Init(aInitOp))) { + return nullptr; + } + return runnable.forget(); + } + + template + 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 runnable = Create(aObj, aMethod, aInitOp); + if (!runnable) { + return; + } + Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable))); + } + + NS_IMETHOD Run() override + { + ((*mObj).*mMethod)(ConvertArg(mArg1)); + return NS_OK; + } + +private: + DaemonResultRunnable1(Obj* aObj, Res (Obj::*aMethod)(Arg1)) + : mObj(aObj) + , mMethod(aMethod) + { + MOZ_ASSERT(mObj); + MOZ_ASSERT(mMethod); + } + + template + nsresult Init(const InitOp& aInitOp) + { + return aInitOp(mArg1); + } + + RefPtr mObj; + Res (Obj::*mMethod)(Arg1); + Tin1 mArg1; +}; + +template +class DaemonResultRunnable3 final : public details::DaemonRunnable +{ +public: + typedef DaemonResultRunnable3 SelfType; + + template + static already_AddRefed + Create(Obj* aObj, Res (Obj::*aMethod)(Arg1, Arg2, Arg3), + const InitOp& aInitOp) + { + RefPtr runnable(new SelfType(aObj, aMethod)); + if (NS_FAILED(runnable->Init(aInitOp))) { + return nullptr; + } + return runnable.forget(); + } + + template + 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 runnable = Create(aObj, aMethod, aInitOp); + if (!runnable) { + return; + } + Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable))); + } + + NS_IMETHOD Run() override + { + ((*mObj).*mMethod)(ConvertArg(mArg1), + ConvertArg(mArg2), + ConvertArg(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 + nsresult + Init(const InitOp& aInitOp) + { + return aInitOp(mArg1, mArg2, mArg3); + } + + RefPtr 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 +class DaemonNotificationRunnable0 final : public details::DaemonRunnable +{ +public: + typedef typename ObjectWrapper::ObjectType ObjectType; + typedef DaemonNotificationRunnable0 SelfType; + + template + static already_AddRefed + Create(Res (ObjectType::*aMethod)(), const InitOp& aInitOp) + { + RefPtr runnable(new SelfType(aMethod)); + if (NS_FAILED(runnable->Init(aInitOp))) { + return nullptr; + } + return runnable.forget(); + } + + template + static void + Dispatch(Res (ObjectType::*aMethod)(), const InitOp& aInitOp) + { + RefPtr 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 + nsresult Init(const InitOp& aInitOp) + { + return aInitOp(); + } + + Res (ObjectType::*mMethod)(); +}; + +template +class DaemonNotificationRunnable1 final : public details::DaemonRunnable +{ +public: + typedef typename ObjectWrapper::ObjectType ObjectType; + typedef DaemonNotificationRunnable1 SelfType; + + template + static already_AddRefed + Create(Res (ObjectType::*aMethod)(Arg1), const InitOp& aInitOp) + { + RefPtr runnable(new SelfType(aMethod)); + if (NS_FAILED(runnable->Init(aInitOp))) { + return nullptr; + } + return runnable.forget(); + } + + template + static void + Dispatch(Res (ObjectType::*aMethod)(Arg1), const InitOp& aInitOp) + { + RefPtr 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(mArg1)); + } + return NS_OK; + } + +private: + DaemonNotificationRunnable1(Res (ObjectType::*aMethod)(Arg1)) + : mMethod(aMethod) + { + MOZ_ASSERT(mMethod); + } + + template + 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 +class DaemonNotificationRunnable2 final : public details::DaemonRunnable +{ +public: + typedef typename ObjectWrapper::ObjectType ObjectType; + typedef DaemonNotificationRunnable2 SelfType; + + template + static already_AddRefed + Create(Res (ObjectType::*aMethod)(Arg1, Arg2), const InitOp& aInitOp) + { + RefPtr runnable(new SelfType(aMethod)); + if (NS_FAILED(runnable->Init(aInitOp))) { + return nullptr; + } + return runnable.forget(); + } + + template + static void + Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2), const InitOp& aInitOp) + { + RefPtr 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(mArg1), + ConvertArg(mArg2)); + } + return NS_OK; + } + +private: + DaemonNotificationRunnable2( + Res (ObjectType::*aMethod)(Arg1, Arg2)) + : mMethod(aMethod) + { + MOZ_ASSERT(mMethod); + } + + template + 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 +class DaemonNotificationRunnable3 final : public details::DaemonRunnable +{ +public: + typedef typename ObjectWrapper::ObjectType ObjectType; + typedef DaemonNotificationRunnable3 SelfType; + + template + static already_AddRefed + Create(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3), const InitOp& aInitOp) + { + RefPtr runnable(new SelfType(aMethod)); + if (NS_FAILED(runnable->Init(aInitOp))) { + return nullptr; + } + return runnable.forget(); + } + + template + static void + Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3), + const InitOp& aInitOp) + { + RefPtr 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(mArg1), + ConvertArg(mArg2), + ConvertArg(mArg3)); + } + return NS_OK; + } + +private: + DaemonNotificationRunnable3( + Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3)) + : mMethod(aMethod) + { + MOZ_ASSERT(mMethod); + } + + template + 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 +class DaemonNotificationRunnable4 final : public details::DaemonRunnable +{ +public: + typedef typename ObjectWrapper::ObjectType ObjectType; + typedef DaemonNotificationRunnable4 SelfType; + + template + static already_AddRefed Create( + Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4), + const InitOp& aInitOp) + { + RefPtr runnable(new SelfType(aMethod)); + if (NS_FAILED(runnable->Init(aInitOp))) { + return nullptr; + } + return runnable.forget(); + } + + template + static void + Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4), + const InitOp& aInitOp) + { + RefPtr 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(mArg1), + ConvertArg(mArg2), + ConvertArg(mArg3), + ConvertArg(mArg4)); + } + return NS_OK; + } + +private: + DaemonNotificationRunnable4( + Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4)) + : mMethod(aMethod) + { + MOZ_ASSERT(mMethod); + } + + template + 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 +class DaemonNotificationRunnable5 final : public details::DaemonRunnable +{ +public: + typedef typename ObjectWrapper::ObjectType ObjectType; + typedef DaemonNotificationRunnable5 SelfType; + + template + static already_AddRefed Create( + Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4, Arg5), + const InitOp& aInitOp) + { + RefPtr runnable(new SelfType(aMethod)); + if (NS_FAILED(runnable->Init(aInitOp))) { + return nullptr; + } + return runnable.forget(); + } + + template + static void + Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4, Arg5), + const InitOp& aInitOp) + { + RefPtr 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(mArg1), + ConvertArg(mArg2), + ConvertArg(mArg3), + ConvertArg(mArg4), + ConvertArg(mArg5)); + } + return NS_OK; + } + +private: + DaemonNotificationRunnable5( + Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4, Arg5)) + : mMethod(aMethod) + { + MOZ_ASSERT(mMethod); + } + + template + 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 +class DaemonNotificationRunnable6 final : public details::DaemonRunnable +{ +public: + typedef typename ObjectWrapper::ObjectType ObjectType; + typedef DaemonNotificationRunnable6 + SelfType; + + template + static already_AddRefed Create( + Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6), + const InitOp& aInitOp) + { + RefPtr runnable(new SelfType(aMethod)); + if (NS_FAILED(runnable->Init(aInitOp))) { + return nullptr; + } + return runnable.forget(); + } + + template + static void + Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6), + const InitOp& aInitOp) + { + RefPtr 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(mArg1), + ConvertArg(mArg2), + ConvertArg(mArg3), + ConvertArg(mArg4), + ConvertArg(mArg5), + ConvertArg(mArg6)); + } + return NS_OK; + } + +private: + DaemonNotificationRunnable6( + Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6)) + : mMethod(aMethod) + { + MOZ_ASSERT(mMethod); + } + + template + 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 +class DaemonNotificationRunnable8 final : public details::DaemonRunnable +{ +public: + typedef typename ObjectWrapper::ObjectType ObjectType; + typedef DaemonNotificationRunnable8 SelfType; + + template + static already_AddRefed Create( + Res (ObjectType::*aMethod)( + Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8), + const InitOp& aInitOp) + { + RefPtr runnable(new SelfType(aMethod)); + if (NS_FAILED(runnable->Init(aInitOp))) { + return nullptr; + } + return runnable.forget(); + } + + template + static void + Dispatch( + Res (ObjectType::*aMethod)( + Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8), + const InitOp& aInitOp) + { + RefPtr 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(mArg1), + ConvertArg(mArg2), + ConvertArg(mArg3), + ConvertArg(mArg4), + ConvertArg(mArg5), + ConvertArg(mArg6), + ConvertArg(mArg7), + ConvertArg(mArg8)); + } + return NS_OK; + } + +private: + DaemonNotificationRunnable8( + Res (ObjectType::*aMethod)( + Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8)) + : mMethod(aMethod) + { + MOZ_ASSERT(mMethod); + } + + template + 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 +class DaemonNotificationRunnable9 final : public details::DaemonRunnable +{ +public: + typedef typename ObjectWrapper::ObjectType ObjectType; + typedef DaemonNotificationRunnable9 SelfType; + + template + static already_AddRefed Create( + Res (ObjectType::*aMethod)( + Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9), + const InitOp& aInitOp) + { + RefPtr runnable(new SelfType(aMethod)); + if (NS_FAILED(runnable->Init(aInitOp))) { + return nullptr; + } + return runnable.forget(); + } + + template + static void + Dispatch( + Res (ObjectType::*aMethod)( + Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9), + const InitOp& aInitOp) + { + RefPtr 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(mArg1), + ConvertArg(mArg2), + ConvertArg(mArg3), + ConvertArg(mArg4), + ConvertArg(mArg5), + ConvertArg(mArg6), + ConvertArg(mArg7), + ConvertArg(mArg8), + ConvertArg(mArg9)); + } + return NS_OK; + } + +private: + DaemonNotificationRunnable9( + Res (ObjectType::*aMethod)( + Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9)) + : mMethod(aMethod) + { + MOZ_ASSERT(mMethod); + } + + template + 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 +#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 { + +// +// 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 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::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>( + 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(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 +#include +#include +#include +#include +#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 +#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 { + +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(&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(&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 +#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) +{ + 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 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(CMSG_DATA(chdr)) + i; + mReceivedFds.AppendElement(*receivedFd); + } + } + + return res; +} + +nsTArray +DaemonSocketPDU::AcquireFds() +{ + // Forget all RAII object to avoid closing the fds. + nsTArray 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(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 AcquireFds(); + + nsresult UpdateHeader(); + +private: + size_t GetPayloadSize() const; + void OnError(const char* aFunction, int aErrno); + + DaemonSocketIOConsumer* mConsumer; + RefPtr mRes; + nsTArray 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 + +// 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 + +#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 + +#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(out); + return NS_OK; +} + +nsresult +Convert(int aIn, uint8_t& aOut) +{ + if (MOZ_HAL_IPC_CONVERT_WARN_IF( + aIn < std::numeric_limits::min(), int, uint8_t) || + MOZ_HAL_IPC_CONVERT_WARN_IF( + aIn > std::numeric_limits::max(), int, uint8_t)) { + aOut = 0; // silences compiler warning + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = static_cast(aIn); + return NS_OK; +} + +nsresult +Convert(int aIn, int16_t& aOut) +{ + if (MOZ_HAL_IPC_CONVERT_WARN_IF( + aIn < std::numeric_limits::min(), int, int16_t) || + MOZ_HAL_IPC_CONVERT_WARN_IF( + aIn > std::numeric_limits::max(), int, int16_t)) { + aOut = 0; // silences compiler warning + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = static_cast(aIn); + return NS_OK; +} + +nsresult +Convert(int aIn, int32_t& aOut) +{ + if (MOZ_HAL_IPC_CONVERT_WARN_IF( + aIn < std::numeric_limits::min(), int, int32_t) || + MOZ_HAL_IPC_CONVERT_WARN_IF( + aIn > std::numeric_limits::max(), int, int32_t)) { + aOut = 0; // silences compiler warning + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = static_cast(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(aIn); + return NS_OK; +} + +nsresult +Convert(uint8_t aIn, int& aOut) +{ + aOut = static_cast(aIn); + return NS_OK; +} + +nsresult +Convert(uint8_t aIn, unsigned long& aOut) +{ + aOut = static_cast(aIn); + return NS_OK; +} + +nsresult +Convert(uint32_t aIn, int& aOut) +{ + aOut = static_cast(aIn); + return NS_OK; +} + +nsresult +Convert(uint32_t aIn, uint8_t& aOut) +{ + if (MOZ_HAL_IPC_CONVERT_WARN_IF( + aIn < std::numeric_limits::min(), uint32_t, uint8_t) || + MOZ_HAL_IPC_CONVERT_WARN_IF( + aIn > std::numeric_limits::max(), uint32_t, uint8_t)) { + aOut = 0; // silences compiler warning + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = static_cast(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(aIn); + return NS_OK; +} + +// +// Packing +// + +nsresult +PackPDU(bool aIn, DaemonSocketPDU& aPDU) +{ + return PackPDU(PackConversion(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(aOut)); +} + +nsresult +UnpackPDU(DaemonSocketPDU& aPDU, char& aOut) +{ + return UnpackPDU(aPDU, UnpackConversion(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(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(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 +#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 +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 +struct PackConversion { + PackConversion(const Tin& aIn) + : mIn(aIn) + { } + + const Tin& mIn; +}; + +template +inline nsresult +PackPDU(const PackConversion& 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 +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 +inline nsresult +PackPDU(const PackArray& 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(const PackArray& aIn, DaemonSocketPDU& aPDU) +{ + /* Write raw bytes in one pass */ + return aPDU.Write(aIn.mData, aIn.mLength); +} + +template<> +inline nsresult +PackPDU(const PackArray& 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(reinterpret_cast(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 +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 +nsresult +PackPDU(const PackReversed& aIn, DaemonSocketPDU& aPDU); + +/* This implementation of |PackPDU| packs elements in |PackArray| in reversed + * order. (ex. reversed GATT UUID, see bug 1171866) + */ +template +inline nsresult +PackPDU(const PackReversed>& 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>| 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>| which packed array elements in the + * reversed order, here we use |PackReversed| to pack data of each element + * of |PackArray| in the reversed order. + */ +template +struct PackArray> +{ + 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 +inline nsresult +PackPDU(const PackArray>& aIn, DaemonSocketPDU& aPDU) +{ + for (size_t i = 0; i < aIn.mLength; ++i) { + nsresult rv = PackPDU(PackReversed(aIn.mData[i]), aPDU); + if (NS_FAILED(rv)) { + return rv; + } + } + return NS_OK; +} + +template +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 +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 +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 +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 +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 +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 +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 +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 +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 +struct UnpackConversion { + UnpackConversion(Tout& aOut) + : mOut(aOut) + { } + + Tout& mOut; +}; + +template +inline nsresult +UnpackPDU(DaemonSocketPDU& aPDU, const UnpackConversion& 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 +struct UnpackArray +{ + UnpackArray(T* aData, size_t aLength) + : mData(aData) + , mLength(aLength) + { } + + UnpackArray(UniquePtr& aData, size_t aLength) + : mData(nullptr) + , mLength(aLength) + { + aData.reset(new T[mLength]); + mData = aData.get(); + } + + UnpackArray(UniquePtr& 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 +inline nsresult +UnpackPDU(DaemonSocketPDU& aPDU, const UnpackArray& 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(DaemonSocketPDU& aPDU, UnpackArray& 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(DaemonSocketPDU& aPDU, const UnpackArray& aOut) +{ + /* Read raw bytes in one pass */ + return aPDU.Read(aOut.mData, aOut.mLength); +} + +template +inline nsresult +UnpackPDU(DaemonSocketPDU& aPDU, nsTArray& aOut) +{ + for (typename nsTArray::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 +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 +nsresult +UnpackPDU(DaemonSocketPDU& aPDU, const UnpackReversed& aOut); + +template +inline nsresult +UnpackPDU(DaemonSocketPDU& aPDU, const UnpackReversed>& 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 +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 +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 +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 + nsresult operator () (T1& aArg1) const + { + nsresult rv = UnpackPDU(GetPDU(), aArg1); + if (NS_FAILED(rv)) { + return rv; + } + WarnAboutTrailingData(); + return NS_OK; + } + + template + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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' -- cgit v1.2.3