mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-29 18:47:31 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
950
ipc/hal/DaemonRunnables.h
Normal file
950
ipc/hal/DaemonRunnables.h
Normal file
|
|
@ -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
|
||||
263
ipc/hal/DaemonSocket.cpp
Normal file
263
ipc/hal/DaemonSocket.cpp
Normal file
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
63
ipc/hal/DaemonSocket.h
Normal file
63
ipc/hal/DaemonSocket.h
Normal file
|
|
@ -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
|
||||
244
ipc/hal/DaemonSocketConnector.cpp
Normal file
244
ipc/hal/DaemonSocketConnector.cpp
Normal file
|
|
@ -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
|
||||
61
ipc/hal/DaemonSocketConnector.h
Normal file
61
ipc/hal/DaemonSocketConnector.h
Normal file
|
|
@ -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
|
||||
33
ipc/hal/DaemonSocketConsumer.cpp
Normal file
33
ipc/hal/DaemonSocketConsumer.cpp
Normal file
|
|
@ -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()
|
||||
{ }
|
||||
|
||||
}
|
||||
}
|
||||
68
ipc/hal/DaemonSocketConsumer.h
Normal file
68
ipc/hal/DaemonSocketConsumer.h
Normal file
|
|
@ -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
|
||||
|
||||
40
ipc/hal/DaemonSocketMessageHandlers.h
Normal file
40
ipc/hal/DaemonSocketMessageHandlers.h
Normal file
|
|
@ -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
|
||||
202
ipc/hal/DaemonSocketPDU.cpp
Normal file
202
ipc/hal/DaemonSocketPDU.cpp
Normal file
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
94
ipc/hal/DaemonSocketPDU.h
Normal file
94
ipc/hal/DaemonSocketPDU.h
Normal file
|
|
@ -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
|
||||
|
||||
335
ipc/hal/DaemonSocketPDUHelpers.cpp
Normal file
335
ipc/hal/DaemonSocketPDUHelpers.cpp
Normal file
|
|
@ -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
|
||||
1283
ipc/hal/DaemonSocketPDUHelpers.h
Normal file
1283
ipc/hal/DaemonSocketPDUHelpers.h
Normal file
File diff suppressed because it is too large
Load diff
27
ipc/hal/moz.build
Normal file
27
ipc/hal/moz.build
Normal file
|
|
@ -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'
|
||||
Loading…
Add table
Add a link
Reference in a new issue