Remove other gonk widget conditionals and unused files.

Tag #288.
This commit is contained in:
wolfbeast 2018-05-13 22:46:04 +02:00 • committed by Roy Tam
commit 74df182488
232 changed files with 256 additions and 36730 deletions

View file

@ -65,12 +65,6 @@ LDFLAGS += CONFIG['MOZ_ALLOW_HEAP_EXECUTE_FLAGS']
if CONFIG['OS_ARCH'] == 'WINNT' and not CONFIG['GNU_CC']:
LDFLAGS += ['/HEAP:0x40000']
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
OS_LIBS += [
'binder',
'utils',
]
if CONFIG['GNU_CXX']:
CXXFLAGS += ['-Wshadow']

View file

@ -131,8 +131,6 @@ if os_linux:
]
DEFINES['ANDROID'] = True
DEFINES['_POSIX_MONOTONIC_CLOCK'] = 0
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
DEFINES['HAVE_ANDROID_OS'] = True
if os_bsd or os_linux:
if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:

View file

@ -1,950 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_ipc_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

View file

@ -1,258 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#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
#include <stdio.h>
#define IODEBUG true
#define CHROMIUM_LOG(args...) if (IODEBUG) printf(args);
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);
}
}
}

View file

@ -1,63 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_ipc_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

View file

@ -1,239 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#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
#include <stdio.h>
#define IODEBUG true
#define CHROMIUM_LOG(args...) if (IODEBUG) printf(args);
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

View file

@ -1,61 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_ipc_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

View file

@ -1,33 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DaemonSocketConsumer.h"
namespace mozilla {
namespace ipc {
//
// DaemonSocketIOConsumer
//
DaemonSocketIOConsumer::DaemonSocketIOConsumer()
{ }
DaemonSocketIOConsumer::~DaemonSocketIOConsumer()
{ }
//
// DaemonSocketConsumer
//
DaemonSocketConsumer::DaemonSocketConsumer()
{ }
DaemonSocketConsumer::~DaemonSocketConsumer()
{ }
}
}

View file

@ -1,68 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_ipc_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

View file

@ -1,40 +0,0 @@
/* -*- 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

View file

@ -1,197 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#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
#include <stdio.h>
#define IODEBUG true
#define CHROMIUM_LOG(args...) if (IODEBUG) printf(args);
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));
}
}
}

View file

@ -1,94 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_ipc_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

View file

@ -1,321 +0,0 @@
/* -*- 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
#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); }
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

File diff suppressed because it is too large Load diff

View file

@ -1,27 +0,0 @@
# -*- 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'

View file

@ -1,981 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=2 et ft=cpp: 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 <fcntl.h>
#include <limits.h>
#include <pwd.h>
#include <sys/stat.h>
#include <sys/types.h>
#define KEYSTORE_LOG(args...) printf(args);
#include "KeyStore.h"
#include "jsfriendapi.h"
#include "KeyStoreConnector.h"
#include "MainThreadUtils.h" // For NS_IsMainThread.
#include "nsICryptoHash.h"
#include "plbase64.h"
#include "certdb.h"
#include "ScopedNSSTypes.h"
using namespace mozilla::ipc;
#if ANDROID_VERSION >= 18
// After Android 4.3, it uses binder to access keystore instead of unix socket.
#include <android/log.h>
#include <binder/BinderService.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <security/keystore/include/keystore/IKeystoreService.h>
#include <security/keystore/include/keystore/keystore.h>
using namespace android;
namespace android {
// This class is used to make compiler happy.
class BpKeystoreService : public BpInterface<IKeystoreService>
{
public:
BpKeystoreService(const sp<IBinder>& impl)
: BpInterface<IKeystoreService>(impl)
{
}
virtual int32_t get(const String16& name, uint8_t** item, size_t* itemLength) {return 0;}
virtual int32_t test() {return 0;}
virtual int32_t insert(const String16& name, const uint8_t* item, size_t itemLength, int uid, int32_t flags) {return 0;}
virtual int32_t del(const String16& name, int uid) {return 0;}
virtual int32_t exist(const String16& name, int uid) {return 0;}
virtual int32_t saw(const String16& name, int uid, Vector<String16>* matches) {return 0;}
virtual int32_t reset() {return 0;}
virtual int32_t password(const String16& password) {return 0;}
virtual int32_t lock() {return 0;}
virtual int32_t unlock(const String16& password) {return 0;}
virtual int32_t zero() {return 0;}
virtual int32_t import(const String16& name, const uint8_t* data, size_t length, int uid, int32_t flags) {return 0;}
virtual int32_t sign(const String16& name, const uint8_t* data, size_t length, uint8_t** out, size_t* outLength) {return 0;}
virtual int32_t verify(const String16& name, const uint8_t* data, size_t dataLength, const uint8_t* signature, size_t signatureLength) {return 0;}
virtual int32_t get_pubkey(const String16& name, uint8_t** pubkey, size_t* pubkeyLength) {return 0;}
virtual int32_t del_key(const String16& name, int uid) {return 0;}
virtual int32_t grant(const String16& name, int32_t granteeUid) {return 0;}
virtual int32_t ungrant(const String16& name, int32_t granteeUid) {return 0;}
virtual int64_t getmtime(const String16& name) {return 0;}
virtual int32_t duplicate(const String16& srcKey, int32_t srcUid, const String16& destKey, int32_t destUid) {return 0;}
virtual int32_t clear_uid(int64_t uid) {return 0;}
#if ANDROID_VERSION >= 21
virtual int32_t generate(const String16& name, int32_t uid, int32_t keyType, int32_t keySize, int32_t flags, Vector<sp<KeystoreArg> >* args) {return 0;}
virtual int32_t is_hardware_backed(const String16& keyType) {return 0;}
virtual int32_t reset_uid(int32_t uid) {return 0;}
virtual int32_t sync_uid(int32_t sourceUid, int32_t targetUid) {return 0;}
virtual int32_t password_uid(const String16& password, int32_t uid) {return 0;}
#elif ANDROID_VERSION == 18
virtual int32_t generate(const String16& name, int uid, int32_t flags) {return 0;}
virtual int32_t is_hardware_backed() {return 0;}
#else
virtual int32_t generate(const String16& name, int32_t uid, int32_t keyType, int32_t keySize, int32_t flags, Vector<sp<KeystoreArg> >* args) {return 0;}
virtual int32_t is_hardware_backed(const String16& keyType) {return 0;}
#endif
};
IMPLEMENT_META_INTERFACE(KeystoreService, "android.security.keystore");
// Here comes binder requests.
status_t BnKeystoreService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case TEST: {
CHECK_INTERFACE(IKeystoreService, data, reply);
reply->writeNoException();
reply->writeInt32(test());
return NO_ERROR;
} break;
case GET: {
CHECK_INTERFACE(IKeystoreService, data, reply);
String16 name = data.readString16();
String8 tmp(name);
uint8_t* data = NULL;
size_t dataLength = 0;
int32_t ret = get(name, &data, &dataLength);
reply->writeNoException();
if (ret == 1) {
reply->writeInt32(dataLength);
void* buf = reply->writeInplace(dataLength);
memcpy(buf, data, dataLength);
free(data);
} else {
reply->writeInt32(-1);
}
return NO_ERROR;
} break;
case GET_PUBKEY: {
CHECK_INTERFACE(IKeystoreService, data, reply);
String16 name = data.readString16();
uint8_t* data = nullptr;
size_t dataLength = 0;
int32_t ret = get_pubkey(name, &data, &dataLength);
reply->writeNoException();
if (dataLength > 0 && data != nullptr) {
reply->writeInt32(dataLength);
void* buf = reply->writeInplace(dataLength);
memcpy(buf, data, dataLength);
free(data);
} else {
reply->writeInt32(-1);
}
reply->writeInt32(ret);
return NO_ERROR;
} break;
case SIGN: {
CHECK_INTERFACE(IKeystoreService, data, reply);
String16 name = data.readString16();
ssize_t signDataSize = data.readInt32();
const uint8_t *signData = nullptr;
if (signDataSize >= 0 && (size_t)signDataSize <= data.dataAvail()) {
signData = (const uint8_t *)data.readInplace(signDataSize);
}
uint8_t *signResult = nullptr;
size_t signResultSize;
int32_t ret = sign(name, signData, (size_t)signDataSize, &signResult,
&signResultSize);
reply->writeNoException();
if (signResultSize > 0 && signResult != nullptr) {
reply->writeInt32(signResultSize);
void* buf = reply->writeInplace(signResultSize);
memcpy(buf, signResult, signResultSize);
free(signResult);
} else {
reply->writeInt32(-1);
}
reply->writeInt32(ret);
return NO_ERROR;
} break;
default:
return NO_ERROR;
}
}
// Provide service for binder.
class KeyStoreService : public BnKeystoreService
, public nsNSSShutDownObject
{
public:
int32_t test() {
uid_t callingUid = IPCThreadState::self()->getCallingUid();
if (!mozilla::ipc::checkPermission(callingUid)) {
return ::PERMISSION_DENIED;
}
return ::NO_ERROR;
}
int32_t get(const String16& name, uint8_t** item, size_t* itemLength) {
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown()) {
return ::SYSTEM_ERROR;
}
uid_t callingUid = IPCThreadState::self()->getCallingUid();
if (!mozilla::ipc::checkPermission(callingUid)) {
return ::PERMISSION_DENIED;
}
String8 certName(name);
if (!strncmp(certName.string(), "WIFI_USERKEY_", 13)) {
return getPrivateKey(certName.string(), (const uint8_t**)item, itemLength);
}
return getCertificate(certName.string(), (const uint8_t**)item, itemLength);
}
int32_t insert(const String16& name, const uint8_t* item, size_t itemLength, int uid, int32_t flags) {return ::UNDEFINED_ACTION;}
int32_t del(const String16& name, int uid) {return ::UNDEFINED_ACTION;}
int32_t exist(const String16& name, int uid) {return ::UNDEFINED_ACTION;}
int32_t saw(const String16& name, int uid, Vector<String16>* matches) {return ::UNDEFINED_ACTION;}
int32_t reset() {return ::UNDEFINED_ACTION;}
int32_t password(const String16& password) {return ::UNDEFINED_ACTION;}
int32_t lock() {return ::UNDEFINED_ACTION;}
int32_t unlock(const String16& password) {return ::UNDEFINED_ACTION;}
int32_t zero() {return ::UNDEFINED_ACTION;}
int32_t import(const String16& name, const uint8_t* data, size_t length, int uid, int32_t flags) {return ::UNDEFINED_ACTION;}
int32_t sign(const String16& name, const uint8_t* data, size_t length, uint8_t** out, size_t* outLength)
{
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown()) {
return ::SYSTEM_ERROR;
}
uid_t callingUid = IPCThreadState::self()->getCallingUid();
if (!mozilla::ipc::checkPermission(callingUid)) {
return ::PERMISSION_DENIED;
}
if (data == nullptr) {
return ::SYSTEM_ERROR;
}
String8 keyName(name);
if (!strncmp(keyName.string(), "WIFI_USERKEY_", 13)) {
return signData(keyName.string(), data, length, out, outLength);
}
return ::UNDEFINED_ACTION;
}
int32_t verify(const String16& name, const uint8_t* data, size_t dataLength, const uint8_t* signature, size_t signatureLength) {return ::UNDEFINED_ACTION;}
int32_t get_pubkey(const String16& name, uint8_t** pubkey, size_t* pubkeyLength) {
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown()) {
return ::SYSTEM_ERROR;
}
uid_t callingUid = IPCThreadState::self()->getCallingUid();
if (!mozilla::ipc::checkPermission(callingUid)) {
return ::PERMISSION_DENIED;
}
String8 keyName(name);
if (!strncmp(keyName.string(), "WIFI_USERKEY_", 13)) {
return getPublicKey(keyName.string(), (const uint8_t**)pubkey, pubkeyLength);
}
return ::UNDEFINED_ACTION;
}
int32_t del_key(const String16& name, int uid) {return ::UNDEFINED_ACTION;}
int32_t grant(const String16& name, int32_t granteeUid) {return ::UNDEFINED_ACTION;}
int32_t ungrant(const String16& name, int32_t granteeUid) {return ::UNDEFINED_ACTION;}
int64_t getmtime(const String16& name) {return ::UNDEFINED_ACTION;}
int32_t duplicate(const String16& srcKey, int32_t srcUid, const String16& destKey, int32_t destUid) {return ::UNDEFINED_ACTION;}
int32_t clear_uid(int64_t uid) {return ::UNDEFINED_ACTION;}
#if ANDROID_VERSION >= 21
virtual int32_t generate(const String16& name, int32_t uid, int32_t keyType, int32_t keySize, int32_t flags, Vector<sp<KeystoreArg> >* args) {return ::UNDEFINED_ACTION;}
virtual int32_t is_hardware_backed(const String16& keyType) {return ::UNDEFINED_ACTION;}
virtual int32_t reset_uid(int32_t uid) {return ::UNDEFINED_ACTION;;}
virtual int32_t sync_uid(int32_t sourceUid, int32_t targetUid) {return ::UNDEFINED_ACTION;}
virtual int32_t password_uid(const String16& password, int32_t uid) {return ::UNDEFINED_ACTION;}
#elif ANDROID_VERSION == 18
virtual int32_t generate(const String16& name, int uid, int32_t flags) {return ::UNDEFINED_ACTION;}
virtual int32_t is_hardware_backed() {return ::UNDEFINED_ACTION;}
#else
virtual int32_t generate(const String16& name, int32_t uid, int32_t keyType, int32_t keySize, int32_t flags, Vector<sp<KeystoreArg> >* args) {return ::UNDEFINED_ACTION;}
virtual int32_t is_hardware_backed(const String16& keyType) {return ::UNDEFINED_ACTION;}
#endif
protected:
virtual void virtualDestroyNSSReference() {}
private:
~KeyStoreService() {
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown()) {
return;
}
shutdown(ShutdownCalledFrom::Object);
}
};
} // namespace android
void startKeyStoreService()
{
android::sp<android::IServiceManager> sm = android::defaultServiceManager();
android::sp<android::KeyStoreService> keyStoreService = new android::KeyStoreService();
sm->addService(String16("android.security.keystore"), keyStoreService);
}
#else
void startKeyStoreService() { return; }
#endif
static const char *CA_BEGIN = "-----BEGIN ",
*CA_END = "-----END ",
*CA_TAILER = "-----\n";
namespace mozilla {
namespace ipc {
static const char* KEYSTORE_ALLOWED_USERS[] = {
"root",
"wifi",
NULL
};
static const char* KEYSTORE_ALLOWED_PREFIXES[] = {
"WIFI_SERVERCERT_",
"WIFI_USERCERT_",
"WIFI_USERKEY_",
NULL
};
// Transform base64 certification data into DER format
void
FormatCaData(const char *aCaData, int aCaDataLength,
const char *aName, const uint8_t **aFormatData,
size_t *aFormatDataLength)
{
size_t bufSize = strlen(CA_BEGIN) + strlen(CA_END) + strlen(CA_TAILER) * 2 +
strlen(aName) * 2 + aCaDataLength + aCaDataLength/CA_LINE_SIZE
+ 2;
char *buf = (char *)malloc(bufSize);
if (!buf) {
*aFormatData = nullptr;
return;
}
*aFormatDataLength = bufSize;
*aFormatData = (const uint8_t *)buf;
char *ptr = buf;
size_t len;
// Create DER header.
len = snprintf(ptr, bufSize, "%s%s%s", CA_BEGIN, aName, CA_TAILER);
ptr += len;
bufSize -= len;
// Split base64 data in lines.
int copySize;
while (aCaDataLength > 0) {
copySize = (aCaDataLength > CA_LINE_SIZE) ? CA_LINE_SIZE : aCaDataLength;
memcpy(ptr, aCaData, copySize);
ptr += copySize;
aCaData += copySize;
aCaDataLength -= copySize;
bufSize -= copySize;
*ptr = '\n';
ptr++;
bufSize--;
}
// Create DEA tailer.
snprintf(ptr, bufSize, "%s%s%s", CA_END, aName, CA_TAILER);
}
ResponseCode
getCertificate(const char *aCertName, const uint8_t **aCertData,
size_t *aCertDataLength)
{
// certificate name prefix check.
if (!aCertName) {
return KEY_NOT_FOUND;
}
const char **prefix = KEYSTORE_ALLOWED_PREFIXES;
for (; *prefix; prefix++ ) {
if (!strncmp(*prefix, aCertName, strlen(*prefix))) {
break;
}
}
if (!(*prefix)) {
return KEY_NOT_FOUND;
}
// Get cert from NSS by name
ScopedCERTCertificate cert(CERT_FindCertByNickname(CERT_GetDefaultCertDB(),
aCertName));
if (!cert) {
return KEY_NOT_FOUND;
}
char *certDER = PL_Base64Encode((const char *)cert->derCert.data,
cert->derCert.len, nullptr);
if (!certDER) {
return SYSTEM_ERROR;
}
FormatCaData(certDER, strlen(certDER), "CERTIFICATE", aCertData,
aCertDataLength);
PL_strfree(certDER);
if (!(*aCertData)) {
return SYSTEM_ERROR;
}
return SUCCESS;
}
ResponseCode getPrivateKey(const char *aKeyName, const uint8_t **aKeyData,
size_t *aKeyDataLength)
{
*aKeyData = nullptr;
// Get corresponding user certificate nickname
char userCertName[128] = {0};
snprintf(userCertName, sizeof(userCertName) - 1, "WIFI_USERCERT_%s", aKeyName + 13);
// Get private key from user certificate.
ScopedCERTCertificate userCert(
CERT_FindCertByNickname(CERT_GetDefaultCertDB(), userCertName));
if (!userCert) {
return KEY_NOT_FOUND;
}
ScopedSECKEYPrivateKey privateKey(
PK11_FindKeyByAnyCert(userCert.get(), nullptr));
if (!privateKey) {
return KEY_NOT_FOUND;
}
// Export private key in PKCS#12 encrypted format, no password.
unsigned char pwstr[] = {0, 0};
SECItem password = {siBuffer, pwstr, sizeof(pwstr)};
ScopedSECKEYEncryptedPrivateKeyInfo encryptedPrivateKey(
PK11_ExportEncryptedPrivKeyInfo(privateKey->pkcs11Slot,
SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4, &password, privateKey, 1,
privateKey->wincx));
if (!encryptedPrivateKey) {
return KEY_NOT_FOUND;
}
// Decrypt into RSA private key.
//
// Generate key for PKCS#12 encryption, we use SHA1 with 1 iteration, as the
// parameters used in PK11_ExportEncryptedPrivKeyInfo() above.
// see: PKCS#12 v1.0, B.2.
//
uint8_t DSP[192] = {0};
memset(DSP, 0x01, 64); // Diversifier part, ID = 1 for decryption.
memset(DSP + 128, 0x00, 64); // Password part, no password.
uint8_t *S = &DSP[64]; // Salt part.
uint8_t *salt = encryptedPrivateKey->algorithm.parameters.data + 4;
int saltLength = (int)encryptedPrivateKey->algorithm.parameters.data[3];
if (saltLength <= 0) {
return SYSTEM_ERROR;
}
for (int i = 0; i < 64; i++) {
S[i] = salt[i % saltLength];
}
// Generate key by SHA-1
nsresult rv;
nsCOMPtr<nsICryptoHash> hash =
do_CreateInstance("@mozilla.org/security/hash;1", &rv);
if (NS_FAILED(rv)) {
return SYSTEM_ERROR;
}
rv = hash->Init(nsICryptoHash::SHA1);
if (NS_FAILED(rv)) {
return SYSTEM_ERROR;
}
rv = hash->Update(DSP, sizeof(DSP));
if (NS_FAILED(rv)) {
return SYSTEM_ERROR;
}
nsCString hashResult;
rv = hash->Finish(false, hashResult);
if (NS_FAILED(rv)) {
return SYSTEM_ERROR;
}
// First 40-bit as key for RC4.
uint8_t key[5];
memcpy(key, hashResult.get(), sizeof(key));
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
if (!slot) {
return SYSTEM_ERROR;
}
SECItem keyItem = {siBuffer, key, sizeof(key)};
ScopedPK11SymKey symKey(PK11_ImportSymKey(slot, CKM_RC4, PK11_OriginUnwrap,
CKA_DECRYPT, &keyItem, nullptr));
if (!symKey) {
return SYSTEM_ERROR;
}
// Get expected decrypted data size then allocate memory.
uint8_t *encryptedData = (uint8_t *)encryptedPrivateKey->encryptedData.data;
unsigned int encryptedDataLen = encryptedPrivateKey->encryptedData.len;
unsigned int decryptedDataLen = encryptedDataLen;
SECStatus srv = PK11_Decrypt(symKey, CKM_RC4, &keyItem, nullptr,
&decryptedDataLen, encryptedDataLen,
encryptedData, encryptedDataLen);
if (srv != SECSuccess) {
return SYSTEM_ERROR;
}
ScopedSECItem decryptedData(::SECITEM_AllocItem(nullptr, nullptr,
decryptedDataLen));
if (!decryptedData) {
return SYSTEM_ERROR;
}
// Decrypt by RC4.
srv = PK11_Decrypt(symKey, CKM_RC4, &keyItem, decryptedData->data,
&decryptedDataLen, decryptedData->len, encryptedData,
encryptedDataLen);
if (srv != SECSuccess) {
return SYSTEM_ERROR;
}
// Export key in PEM format.
char *keyPEM = PL_Base64Encode((const char *)decryptedData->data,
decryptedDataLen, nullptr);
if (!keyPEM) {
return SYSTEM_ERROR;
}
FormatCaData(keyPEM, strlen(keyPEM), "PRIVATE KEY", aKeyData, aKeyDataLength);
PL_strfree(keyPEM);
if (!(*aKeyData)) {
return SYSTEM_ERROR;
}
return SUCCESS;
}
ResponseCode getPublicKey(const char *aKeyName, const uint8_t **aKeyData,
size_t *aKeyDataLength)
{
*aKeyData = nullptr;
// Get corresponding user certificate nickname
char userCertName[128] = {0};
snprintf(userCertName, sizeof(userCertName) - 1, "WIFI_USERCERT_%s", aKeyName + 13);
// Get public key from user certificate.
ScopedCERTCertificate userCert(
CERT_FindCertByNickname(CERT_GetDefaultCertDB(), userCertName));
if (!userCert) {
return KEY_NOT_FOUND;
}
// Get public key.
ScopedSECKEYPublicKey publicKey(CERT_ExtractPublicKey(userCert));
if (!publicKey) {
return KEY_NOT_FOUND;
}
ScopedSECItem keyItem(PK11_DEREncodePublicKey(publicKey));
if (!keyItem) {
return KEY_NOT_FOUND;
}
size_t bufSize = keyItem->len;
char *buf = (char *)malloc(bufSize);
if (!buf) {
return SYSTEM_ERROR;
}
memcpy(buf, keyItem->data, bufSize);
*aKeyData = (const uint8_t *)buf;
*aKeyDataLength = bufSize;
return SUCCESS;
}
ResponseCode signData(const char *aKeyName, const uint8_t *data, size_t length,
uint8_t **out, size_t *outLength)
{
*out = nullptr;
// Get corresponding user certificate nickname
char userCertName[128] = {0};
snprintf(userCertName, sizeof(userCertName) - 1, "WIFI_USERCERT_%s", aKeyName + 13);
// Get private key from user certificate.
ScopedCERTCertificate userCert(
CERT_FindCertByNickname(CERT_GetDefaultCertDB(), userCertName));
if (!userCert) {
return KEY_NOT_FOUND;
}
ScopedSECKEYPrivateKey privateKey(
PK11_FindKeyByAnyCert(userCert.get(), nullptr));
if (!privateKey) {
return KEY_NOT_FOUND;
}
//
// Find hash data from incoming data.
//
// Incoming data might be padded by PKCS-1 format:
// 00 01 FF FF ... FF 00 || Hash of length 36
// If the padding part exists, we have to ignore them.
//
uint8_t *hash = (uint8_t *)data;
const size_t HASH_LENGTH = 36;
if (length < HASH_LENGTH) {
return VALUE_CORRUPTED;
}
if (hash[0] == 0x00 && hash[1] == 0x01 && hash[2] == 0xFF && hash[3] == 0xFF) {
hash += 4;
while (*hash == 0xFF) {
if (hash + HASH_LENGTH > data + length) {
return VALUE_CORRUPTED;
}
hash++;
}
if (*hash != 0x00) {
return VALUE_CORRUPTED;
}
hash++;
}
if (hash + HASH_LENGTH != data + length) {
return VALUE_CORRUPTED;
}
SECItem hashItem = {siBuffer, hash, HASH_LENGTH};
// Sign hash.
ScopedSECItem signItem(::SECITEM_AllocItem(nullptr, nullptr,
PK11_SignatureLen(privateKey)));
if (!signItem) {
return SYSTEM_ERROR;
}
SECStatus srv;
srv = PK11_Sign(privateKey, signItem.get(), &hashItem);
if (srv != SECSuccess) {
return SYSTEM_ERROR;
}
uint8_t *buf = (uint8_t *)malloc(signItem->len);
if (!buf) {
return SYSTEM_ERROR;
}
memcpy(buf, signItem->data, signItem->len);
*out = buf;
*outLength = signItem->len;
return SUCCESS;
}
bool
checkPermission(uid_t uid)
{
struct passwd *userInfo = getpwuid(uid);
for (const char **user = KEYSTORE_ALLOWED_USERS; *user; user++ ) {
if (!strcmp(*user, userInfo->pw_name)) {
return true;
}
}
return false;
}
//
// KeyStore
//
KeyStore::KeyStore()
: mShutdown(false)
{
MOZ_COUNT_CTOR(KeyStore);
::startKeyStoreService();
Listen();
}
KeyStore::~KeyStore()
{
nsNSSShutDownPreventionLock locker;
MOZ_COUNT_DTOR(KeyStore);
if (isAlreadyShutDown()) {
return;
}
shutdown(ShutdownCalledFrom::Object);
MOZ_ASSERT(!mListenSocket);
MOZ_ASSERT(!mStreamSocket);
}
void
KeyStore::Shutdown()
{
// We set mShutdown first, so that |OnDisconnect| won't try to reconnect.
mShutdown = true;
if (mStreamSocket) {
mStreamSocket->Close();
mStreamSocket = nullptr;
}
if (mListenSocket) {
mListenSocket->Close();
mListenSocket = nullptr;
}
}
void
KeyStore::Listen()
{
// We only allocate one |StreamSocket|, but re-use it for every connection.
if (mStreamSocket) {
mStreamSocket->Close();
} else {
mStreamSocket = new StreamSocket(this, STREAM_SOCKET);
}
if (!mListenSocket) {
// We only ever allocate one |ListenSocket|...
mListenSocket = new ListenSocket(this, LISTEN_SOCKET);
mListenSocket->Listen(new KeyStoreConnector(KEYSTORE_ALLOWED_USERS),
mStreamSocket);
} else {
// ... but keep it open.
mListenSocket->Listen(mStreamSocket);
}
ResetHandlerInfo();
}
void
KeyStore::ResetHandlerInfo()
{
mHandlerInfo.state = STATE_IDLE;
mHandlerInfo.command = 0;
mHandlerInfo.paramCount = 0;
mHandlerInfo.commandPattern = nullptr;
for (int i = 0; i < MAX_PARAM; i++) {
mHandlerInfo.param[i].length = 0;
memset(mHandlerInfo.param[i].data, 0, VALUE_SIZE);
}
}
bool
KeyStore::CheckSize(UnixSocketBuffer *aMessage, size_t aExpectSize)
{
return (aMessage->GetSize() >= aExpectSize);
}
ResponseCode
KeyStore::ReadCommand(UnixSocketBuffer *aMessage)
{
if (mHandlerInfo.state != STATE_IDLE) {
NS_WARNING("Wrong state in ReadCommand()!");
return SYSTEM_ERROR;
}
if (!CheckSize(aMessage, 1)) {
NS_WARNING("Data size error in ReadCommand()!");
return PROTOCOL_ERROR;
}
mHandlerInfo.command = *aMessage->GetData();
aMessage->Consume(1);
// Find corrsponding command pattern
const struct ProtocolCommand *command = commands;
while (command->command && command->command != mHandlerInfo.command) {
command++;
}
if (!command->command) {
NS_WARNING("Unsupported command!");
return PROTOCOL_ERROR;
}
// Get command pattern.
mHandlerInfo.commandPattern = command;
if (command->paramNum) {
// Read command parameter if needed.
mHandlerInfo.state = STATE_READ_PARAM_LEN;
} else {
mHandlerInfo.state = STATE_PROCESSING;
}
return SUCCESS;
}
ResponseCode
KeyStore::ReadLength(UnixSocketBuffer *aMessage)
{
if (mHandlerInfo.state != STATE_READ_PARAM_LEN) {
NS_WARNING("Wrong state in ReadLength()!");
return SYSTEM_ERROR;
}
if (!CheckSize(aMessage, 2)) {
NS_WARNING("Data size error in ReadLength()!");
return PROTOCOL_ERROR;
}
// Read length of command parameter.
// FIXME: Depends on endianess and (sizeof(unsigned short) == 2)
unsigned short dataLength;
memcpy(&dataLength, aMessage->GetData(), 2);
aMessage->Consume(2);
mHandlerInfo.param[mHandlerInfo.paramCount].length = ntohs(dataLength);
mHandlerInfo.state = STATE_READ_PARAM_DATA;
return SUCCESS;
}
ResponseCode
KeyStore::ReadData(UnixSocketBuffer *aMessage)
{
if (mHandlerInfo.state != STATE_READ_PARAM_DATA) {
NS_WARNING("Wrong state in ReadData()!");
return SYSTEM_ERROR;
}
if (!CheckSize(aMessage, mHandlerInfo.param[mHandlerInfo.paramCount].length)) {
NS_WARNING("Data size error in ReadData()!");
return PROTOCOL_ERROR;
}
// Read command parameter.
memcpy(mHandlerInfo.param[mHandlerInfo.paramCount].data,
aMessage->GetData(),
mHandlerInfo.param[mHandlerInfo.paramCount].length);
aMessage->Consume(mHandlerInfo.param[mHandlerInfo.paramCount].length);
mHandlerInfo.paramCount++;
if (mHandlerInfo.paramCount == mHandlerInfo.commandPattern->paramNum) {
mHandlerInfo.state = STATE_PROCESSING;
} else {
mHandlerInfo.state = STATE_READ_PARAM_LEN;
}
return SUCCESS;
}
// Status response
void
KeyStore::SendResponse(ResponseCode aResponse)
{
MOZ_ASSERT(mStreamSocket);
if (aResponse == NO_RESPONSE)
return;
uint8_t response = (uint8_t)aResponse;
UnixSocketRawData* data = new UnixSocketRawData((const void *)&response, 1);
mStreamSocket->SendSocketData(data);
}
// Data response
void
KeyStore::SendData(const uint8_t *aData, int aLength)
{
MOZ_ASSERT(mStreamSocket);
unsigned short dataLength = htons(aLength);
UnixSocketRawData* length = new UnixSocketRawData((const void *)&dataLength, 2);
mStreamSocket->SendSocketData(length);
UnixSocketRawData* data = new UnixSocketRawData((const void *)aData, aLength);
mStreamSocket->SendSocketData(data);
}
// |StreamSocketConsumer|, |ListenSocketConsumer|
void
KeyStore::ReceiveSocketData(int aIndex, UniquePtr<UnixSocketBuffer>& aMessage)
{
MOZ_ASSERT(NS_IsMainThread());
// Handle request.
ResponseCode result = SUCCESS;
while (aMessage->GetSize() ||
mHandlerInfo.state == STATE_PROCESSING) {
switch (mHandlerInfo.state) {
case STATE_IDLE:
result = ReadCommand(aMessage.get());
break;
case STATE_READ_PARAM_LEN:
result = ReadLength(aMessage.get());
break;
case STATE_READ_PARAM_DATA:
result = ReadData(aMessage.get());
break;
case STATE_PROCESSING:
if (mHandlerInfo.command == 'g') {
result = SYSTEM_ERROR;
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown()) {
break;
}
// Get CA
const uint8_t *data;
size_t dataLength;
const char *name = (const char *)mHandlerInfo.param[0].data;
if (!strncmp(name, "WIFI_USERKEY_", 13)) {
result = getPrivateKey(name, &data, &dataLength);
} else {
result = getCertificate(name, &data, &dataLength);
}
if (result != SUCCESS) {
break;
}
SendResponse(SUCCESS);
SendData(data, (int)dataLength);
free((void *)data);
}
ResetHandlerInfo();
break;
}
if (result != SUCCESS) {
SendResponse(result);
ResetHandlerInfo();
return;
}
}
}
void
KeyStore::OnConnectSuccess(int aIndex)
{
if (aIndex == STREAM_SOCKET) {
mShutdown = false;
}
}
void
KeyStore::OnConnectError(int aIndex)
{
if (mShutdown) {
return;
}
if (aIndex == STREAM_SOCKET) {
// Stream socket error; start listening again
Listen();
}
}
void
KeyStore::OnDisconnect(int aIndex)
{
if (mShutdown) {
return;
}
switch (aIndex) {
case LISTEN_SOCKET:
// Listen socket disconnected; start anew.
mListenSocket = nullptr;
Listen();
break;
case STREAM_SOCKET:
// Stream socket disconnected; start listening again.
Listen();
break;
}
}
} // namespace ipc
} // namespace mozilla

View file

@ -1,141 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=2 et ft=cpp: 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_KeyStore_h
#define mozilla_ipc_KeyStore_h 1
#include <sys/socket.h>
#include <sys/un.h>
#include "cert.h"
#include "mozilla/ipc/ListenSocket.h"
#include "mozilla/ipc/ListenSocketConsumer.h"
#include "mozilla/ipc/StreamSocket.h"
#include "mozilla/ipc/StreamSocketConsumer.h"
#include "nsNSSShutDown.h"
namespace mozilla {
namespace ipc {
enum ResponseCode {
SUCCESS = 1,
LOCKED = 2,
UNINITIALIZED = 3,
SYSTEM_ERROR = 4,
PROTOCOL_ERROR = 5,
PERMISSION_DENIED = 6,
KEY_NOT_FOUND = 7,
VALUE_CORRUPTED = 8,
UNDEFINED_ACTION = 9,
WRONG_PASSWORD_0 = 10,
WRONG_PASSWORD_1 = 11,
WRONG_PASSWORD_2 = 12,
WRONG_PASSWORD_3 = 13, // MAX_RETRY = 4
NO_RESPONSE
};
void FormatCaData(const uint8_t *aCaData, int aCaDataLength,
const char *aName, const uint8_t **aFormatData,
size_t *aFormatDataLength);
ResponseCode getCertificate(const char *aCertName, const uint8_t **aCertData,
size_t *aCertDataLength);
ResponseCode getPrivateKey(const char *aKeyName, const uint8_t **aKeyData,
size_t *aKeyDataLength);
ResponseCode getPublicKey(const char *aKeyName, const uint8_t **aKeyData,
size_t *aKeyDataLength);
ResponseCode signData(const char *aKeyName, const uint8_t *data, size_t length,
uint8_t **out, size_t *outLength);
bool checkPermission(uid_t uid);
static const int MAX_PARAM = 2;
static const int KEY_SIZE = ((NAME_MAX - 15) / 2);
static const int VALUE_SIZE = 32768;
static const int PASSWORD_SIZE = VALUE_SIZE;
static const int CA_LINE_SIZE = 64;
struct ProtocolCommand {
int8_t command;
int paramNum;
};
static const struct ProtocolCommand commands[] = {
{'g', 1}, // Get CA, command "g CERT_NAME"
{ 0, 0}
};
struct ProtocolParam{
uint length;
int8_t data[VALUE_SIZE];
};
typedef enum {
STATE_IDLE,
STATE_READ_PARAM_LEN,
STATE_READ_PARAM_DATA,
STATE_PROCESSING
} ProtocolHandlerState;
class KeyStore final
: public StreamSocketConsumer
, public ListenSocketConsumer
, public nsNSSShutDownObject
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(KeyStore)
KeyStore();
void Shutdown();
protected:
virtual void virtualDestroyNSSReference() {}
private:
enum SocketType {
LISTEN_SOCKET,
STREAM_SOCKET
};
~KeyStore();
struct {
ProtocolHandlerState state;
uint8_t command;
struct ProtocolParam param[MAX_PARAM];
int paramCount;
const struct ProtocolCommand *commandPattern;
} mHandlerInfo;
void ResetHandlerInfo();
void Listen();
bool CheckSize(UnixSocketBuffer *aMessage, size_t aExpectSize);
ResponseCode ReadCommand(UnixSocketBuffer *aMessage);
ResponseCode ReadLength(UnixSocketBuffer *aMessage);
ResponseCode ReadData(UnixSocketBuffer *aMessage);
void SendResponse(ResponseCode response);
void SendData(const uint8_t *data, int length);
// Methods for |StreamSocketConsumer|
//
void ReceiveSocketData(int aIndex,
UniquePtr<UnixSocketBuffer>& aMessage) override;
void OnConnectSuccess(int aIndex) override;
void OnConnectError(int aIndex) override;
void OnDisconnect(int aIndex) override;
bool mShutdown;
RefPtr<ListenSocket> mListenSocket;
RefPtr<StreamSocket> mStreamSocket;
};
} // namespace ipc
} // namespace mozilla
#endif // mozilla_ipc_KeyStore_h

View file

@ -1,234 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=2 et ft=cpp: 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 "KeyStoreConnector.h"
#include <fcntl.h>
#include <pwd.h>
#include <sys/stat.h>
#include <sys/un.h>
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, MOZ_COUNT_DTOR
#include "nsThreadUtils.h" // For NS_IsMainThread.
#define KEYSTORE_LOG(args...) printf(args);
namespace mozilla {
namespace ipc {
static const char KEYSTORE_SOCKET_PATH[] = "/dev/socket/keystore";
KeyStoreConnector::KeyStoreConnector(const char** const aAllowedUsers)
: mAllowedUsers(aAllowedUsers)
{
MOZ_COUNT_CTOR_INHERITED(KeyStoreConnector, UnixSocketConnector);
}
KeyStoreConnector::~KeyStoreConnector()
{
MOZ_COUNT_DTOR_INHERITED(KeyStoreConnector, UnixSocketConnector);
}
nsresult
KeyStoreConnector::CreateSocket(int& aFd) const
{
unlink(KEYSTORE_SOCKET_PATH);
aFd = socket(AF_LOCAL, SOCK_STREAM, 0);
if (aFd < 0) {
KEYSTORE_LOG("Could not open KeyStore socket!");
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
KeyStoreConnector::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
KeyStoreConnector::CheckPermission(int aFd) const
{
struct ucred userCred;
socklen_t len = sizeof(userCred);
if (getsockopt(aFd, SOL_SOCKET, SO_PEERCRED, &userCred, &len)) {
return NS_ERROR_FAILURE;
}
const struct passwd* userInfo = getpwuid(userCred.uid);
if (!userInfo) {
return NS_ERROR_FAILURE;
}
if (!mAllowedUsers) {
return NS_ERROR_FAILURE;
}
for (const char** user = mAllowedUsers; *user; ++user) {
if (!strcmp(*user, userInfo->pw_name)) {
return NS_OK;
}
}
return NS_ERROR_FAILURE;
}
nsresult
KeyStoreConnector::CreateAddress(struct sockaddr& aAddress,
socklen_t& aAddressLength) const
{
struct sockaddr_un* address =
reinterpret_cast<struct sockaddr_un*>(&aAddress);
size_t namesiz = strlen(KEYSTORE_SOCKET_PATH) + 1; // include trailing '\0'
if (namesiz > sizeof(address->sun_path)) {
KEYSTORE_LOG("Address too long for socket struct!");
return NS_ERROR_FAILURE;
}
address->sun_family = AF_UNIX;
memcpy(address->sun_path, KEYSTORE_SOCKET_PATH, namesiz);
aAddressLength = offsetof(struct sockaddr_un, sun_path) + namesiz;
return NS_OK;
}
// |UnixSocketConnector|
nsresult
KeyStoreConnector::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
KeyStoreConnector::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;
}
}
// Allow access for wpa_supplicant (different user, different group)
//
// TODO: Improve this by setting specific user/group for
// wpa_supplicant by calling |fchmod| and |fchown|.
//
chmod(KEYSTORE_SOCKET_PATH, S_IRUSR|S_IWUSR|
S_IRGRP|S_IWGRP|
S_IROTH|S_IWOTH);
aListenFd = fd.forget();
return NS_OK;
}
nsresult
KeyStoreConnector::AcceptStreamSocket(int aListenFd,
struct sockaddr* aAddress,
socklen_t* aAddressLength,
int& aStreamFd)
{
ScopedClose fd(
TEMP_FAILURE_RETRY(accept(aListenFd, aAddress, aAddressLength)));
if (fd < 0) {
NS_WARNING("Cannot accept file descriptor!");
return NS_ERROR_FAILURE;
}
nsresult rv = SetSocketFlags(fd);
if (NS_FAILED(rv)) {
return rv;
}
rv = CheckPermission(fd);
if (NS_FAILED(rv)) {
return rv;
}
aStreamFd = fd.forget();
return NS_OK;
}
nsresult
KeyStoreConnector::CreateStreamSocket(struct sockaddr* aAddress,
socklen_t* aAddressLength,
int& aStreamFd)
{
MOZ_CRASH("|KeyStoreConnector| does not support creating stream sockets.");
return NS_ERROR_FAILURE;
}
nsresult
KeyStoreConnector::Duplicate(UnixSocketConnector*& aConnector)
{
aConnector = new KeyStoreConnector(*this);
return NS_OK;
}
}
}

View file

@ -1,57 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=2 et ft=cpp: 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_KeyStoreConnector_h
#define mozilla_ipc_KeyStoreConnector_h
#include "mozilla/ipc/UnixSocketConnector.h"
namespace mozilla {
namespace ipc {
class KeyStoreConnector final : public UnixSocketConnector
{
public:
KeyStoreConnector(const char** const aAllowedUsers);
~KeyStoreConnector();
// 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* aAddressLength,
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 CheckPermission(int aFd) const;
nsresult CreateAddress(struct sockaddr& aAddress,
socklen_t& aAddressLength) const;
const char** const mAllowedUsers;
};
}
}
#endif

View file

@ -1,18 +0,0 @@
# -*- 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 += [
'KeyStore.h'
]
SOURCES += [
'KeyStore.cpp',
'KeyStoreConnector.cpp'
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'

View file

@ -14,12 +14,6 @@ DIRS += [
if CONFIG['MOZ_ENABLE_DBUS']:
DIRS += ['dbus']
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
DIRS += ['unixfd', 'unixsocket']
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
DIRS += ['hal', 'keystore', 'netd']
if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android':
DIRS += ['contentproc']

View file

@ -1,374 +0,0 @@
/* 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 "Netd.h"
#include <android/log.h>
#include <cutils/sockets.h>
#include <fcntl.h>
#include <sys/socket.h>
#include "android/log.h"
#include "base/task.h"
#include "nsWhitespaceTokenizer.h"
#include "nsXULAppAPI.h"
#include "nsString.h"
#include "nsThreadUtils.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Sprintf.h"
#include "SystemProperty.h"
#define NETD_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk", args)
#define ICS_SYS_USB_RNDIS_MAC "/sys/class/android_usb/android0/f_rndis/ethaddr"
#define INVALID_SOCKET -1
#define MAX_RECONNECT_TIMES 10
using mozilla::system::Property;
namespace {
RefPtr<mozilla::ipc::NetdClient> gNetdClient;
RefPtr<mozilla::ipc::NetdConsumer> gNetdConsumer;
class StopNetdConsumer : public mozilla::Runnable {
public:
NS_IMETHOD Run() override
{
MOZ_ASSERT(NS_IsMainThread());
gNetdConsumer = nullptr;
return NS_OK;
}
};
bool
InitRndisAddress()
{
char mac[20];
char serialno[] = "1234567890ABCDEF";
static const int kEthernetAddressLength = 6;
char address[kEthernetAddressLength];
int i = 0;
int ret = 0;
int length = 0;
mozilla::ScopedClose fd;
fd.rwget() = open(ICS_SYS_USB_RNDIS_MAC, O_WRONLY);
if (fd.rwget() == -1) {
NETD_LOG("Unable to open file %s.", ICS_SYS_USB_RNDIS_MAC);
return false;
}
Property::Get("ro.serialno", serialno, "1234567890ABCDEF");
memset(address, 0, sizeof(address));
// First byte is 0x02 to signify a locally administered address.
address[0] = 0x02;
length = strlen(serialno);
for (i = 0; i < length; i++) {
address[i % (kEthernetAddressLength - 1) + 1] ^= serialno[i];
}
SprintfLiteral(mac, "%02x:%02x:%02x:%02x:%02x:%02x",
address[0], address[1], address[2],
address[3], address[4], address[5]);
length = strlen(mac);
ret = write(fd.get(), mac, length);
if (ret != length) {
NETD_LOG("Fail to write file %s.", ICS_SYS_USB_RNDIS_MAC);
return false;
}
return true;
}
} // namespace
namespace mozilla {
namespace ipc {
NetdClient::NetdClient()
: LineWatcher('\0', MAX_COMMAND_SIZE)
, mIOLoop(MessageLoopForIO::current())
, mSocket(INVALID_SOCKET)
, mCurrentWriteOffset(0)
, mReConnectTimes(0)
{
MOZ_COUNT_CTOR(NetdClient);
}
NetdClient::~NetdClient()
{
MOZ_COUNT_DTOR(NetdClient);
}
bool
NetdClient::OpenSocket()
{
mSocket.rwget() = socket_local_client("netd",
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_STREAM);
if (mSocket.rwget() < 0) {
NETD_LOG("Error connecting to : netd (%s) - will retry", strerror(errno));
return false;
}
// Add FD_CLOEXEC flag.
int flags = fcntl(mSocket.get(), F_GETFD);
if (flags == -1) {
NETD_LOG("Error doing fcntl with F_GETFD command(%s)", strerror(errno));
return false;
}
flags |= FD_CLOEXEC;
if (fcntl(mSocket.get(), F_SETFD, flags) == -1) {
NETD_LOG("Error doing fcntl with F_SETFD command(%s)", strerror(errno));
return false;
}
// Set non-blocking.
if (fcntl(mSocket.get(), F_SETFL, O_NONBLOCK) == -1) {
NETD_LOG("Error set non-blocking socket(%s)", strerror(errno));
return false;
}
if (!MessageLoopForIO::current()->
WatchFileDescriptor(mSocket.get(),
true,
MessageLoopForIO::WATCH_READ,
&mReadWatcher,
this)) {
NETD_LOG("Error set socket read watcher(%s)", strerror(errno));
return false;
}
if (!mOutgoingQ.empty()) {
MessageLoopForIO::current()->
WatchFileDescriptor(mSocket.get(),
false,
MessageLoopForIO::WATCH_WRITE,
&mWriteWatcher,
this);
}
NETD_LOG("Connected to netd");
return true;
}
void NetdClient::OnLineRead(int aFd, nsDependentCSubstring& aMessage)
{
// Set errno to 0 first. For preventing to use the stale version of errno.
errno = 0;
// We found a line terminator. Each line is formatted as an
// integer response code followed by the rest of the line.
// Fish out the response code.
int responseCode = strtol(aMessage.Data(), nullptr, 10);
if (!errno) {
NetdCommand* response = new NetdCommand();
// Passing all the response message, including the line terminator.
response->mSize = aMessage.Length();
memcpy(response->mData, aMessage.Data(), aMessage.Length());
gNetdConsumer->MessageReceived(response);
}
if (!responseCode) {
NETD_LOG("Can't parse netd's response");
}
}
void
NetdClient::OnFileCanWriteWithoutBlocking(int aFd)
{
MOZ_ASSERT(aFd == mSocket.get());
WriteNetdCommand();
}
void
NetdClient::OnError()
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
mReadWatcher.StopWatchingFileDescriptor();
mWriteWatcher.StopWatchingFileDescriptor();
mSocket.dispose();
mCurrentWriteOffset = 0;
mCurrentNetdCommand = nullptr;
while (!mOutgoingQ.empty()) {
delete mOutgoingQ.front();
mOutgoingQ.pop();
}
Start();
}
// static
void
NetdClient::Start()
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
if (!gNetdClient) {
NETD_LOG("Netd Client is not initialized");
return;
}
if (!gNetdClient->OpenSocket()) {
// Socket open failed, try again in a second.
NETD_LOG("Fail to connect to Netd");
if (++gNetdClient->mReConnectTimes > MAX_RECONNECT_TIMES) {
NETD_LOG("Fail to connect to Netd after retry %d times", MAX_RECONNECT_TIMES);
return;
}
MessageLoopForIO::current()->
PostDelayedTask(NewRunnableFunction(NetdClient::Start),
1000);
return;
}
gNetdClient->mReConnectTimes = 0;
}
// static
void
NetdClient::SendNetdCommandIOThread(NetdCommand* aMessage)
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
MOZ_ASSERT(aMessage);
if (!gNetdClient) {
NETD_LOG("Netd Client is not initialized");
return;
}
gNetdClient->mOutgoingQ.push(aMessage);
if (gNetdClient->mSocket.get() == INVALID_SOCKET) {
NETD_LOG("Netd connection is not established, push the message to queue");
return;
}
gNetdClient->WriteNetdCommand();
}
void
NetdClient::WriteNetdCommand()
{
if (!mCurrentNetdCommand) {
mCurrentWriteOffset = 0;
mCurrentNetdCommand = mOutgoingQ.front();
mOutgoingQ.pop();
}
while (mCurrentWriteOffset < mCurrentNetdCommand->mSize) {
ssize_t write_amount = mCurrentNetdCommand->mSize - mCurrentWriteOffset;
ssize_t written = write(mSocket.get(),
mCurrentNetdCommand->mData + mCurrentWriteOffset,
write_amount);
if (written < 0) {
NETD_LOG("Cannot write to network, error %d\n", (int) written);
OnError();
return;
}
if (written > 0) {
mCurrentWriteOffset += written;
}
if (written != write_amount) {
NETD_LOG("WriteNetdCommand fail !!! Write is not completed");
break;
}
}
if (mCurrentWriteOffset != mCurrentNetdCommand->mSize) {
MessageLoopForIO::current()->
WatchFileDescriptor(mSocket.get(),
false,
MessageLoopForIO::WATCH_WRITE,
&mWriteWatcher,
this);
return;
}
mCurrentNetdCommand = nullptr;
}
static void
InitNetdIOThread()
{
bool result;
char propValue[Property::VALUE_MAX_LENGTH];
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
MOZ_ASSERT(!gNetdClient);
Property::Get("ro.build.version.sdk", propValue, "0");
// Assign rndis address for usb tethering in ICS.
if (atoi(propValue) >= 15) {
result = InitRndisAddress();
// We don't return here because InitRnsisAddress() function is related to
// usb tethering only. Others service such as wifi tethering still need
// to use ipc to communicate with netd.
if (!result) {
NETD_LOG("fail to give rndis interface an address");
}
}
gNetdClient = new NetdClient();
gNetdClient->Start();
}
static void
ShutdownNetdIOThread()
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
nsCOMPtr<nsIRunnable> shutdownEvent = new StopNetdConsumer();
gNetdClient = nullptr;
NS_DispatchToMainThread(shutdownEvent);
}
void
StartNetd(NetdConsumer* aNetdConsumer)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aNetdConsumer);
MOZ_ASSERT(gNetdConsumer == nullptr);
gNetdConsumer = aNetdConsumer;
XRE_GetIOMessageLoop()->PostTask(
NewRunnableFunction(InitNetdIOThread));
}
void
StopNetd()
{
MOZ_ASSERT(NS_IsMainThread());
nsIThread* currentThread = NS_GetCurrentThread();
NS_ASSERTION(currentThread, "This should never be null!");
XRE_GetIOMessageLoop()->PostTask(
NewRunnableFunction(ShutdownNetdIOThread));
while (gNetdConsumer) {
if (!NS_ProcessNextEvent(currentThread)) {
NS_WARNING("Something bad happened!");
break;
}
}
}
/**************************************************************************
*
* This function runs in net worker Thread context. The net worker thread
* is created in dom/system/gonk/NetworkManager.js
*
**************************************************************************/
void
SendNetdCommand(NetdCommand* aMessage)
{
MOZ_ASSERT(aMessage);
XRE_GetIOMessageLoop()->PostTask(
NewRunnableFunction(NetdClient::SendNetdCommandIOThread, aMessage));
}
} // namespace ipc
} // namespace mozilla

View file

@ -1,81 +0,0 @@
/* 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_system_netd_h__
#define mozilla_system_netd_h__
#include "nsISupportsImpl.h"
#include "nsAutoPtr.h"
#include "base/message_loop.h"
#include "mozilla/FileUtils.h"
#define MAX_COMMAND_SIZE 4096
namespace mozilla {
namespace ipc {
/*
* Represents raw data going to or coming from the Netd socket.
*/
struct NetdCommand
{
uint8_t mData[MAX_COMMAND_SIZE];
// Number of octets in mData.
size_t mSize;
};
class NetdConsumer
{
protected:
virtual ~NetdConsumer() { }
public:
NS_INLINE_DECL_REFCOUNTING(NetdConsumer)
virtual void MessageReceived(NetdCommand* aMessage) = 0;
};
class NetdWriteTask : public Runnable
{
NS_IMETHOD Run();
};
class NetdClient : public MessageLoopForIO::LineWatcher
{
virtual ~NetdClient();
public:
NS_INLINE_DECL_REFCOUNTING(NetdClient)
typedef std::queue<NetdCommand*> NetdCommandQueue;
NetdClient();
static void Start();
static void SendNetdCommandIOThread(NetdCommand* aMessage);
private:
void WriteNetdCommand();
virtual void OnError();
virtual void OnLineRead(int aFd, nsDependentCSubstring& aMessage);
virtual void OnFileCanWriteWithoutBlocking(int aFd);
bool OpenSocket();
MessageLoopForIO *mIOLoop;
MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
MessageLoopForIO::FileDescriptorWatcher mWriteWatcher;
ScopedClose mSocket;
NetdCommandQueue mOutgoingQ;
nsAutoPtr<NetdCommand> mCurrentNetdCommand;
size_t mCurrentWriteOffset;
size_t mReConnectTimes;
};
void StartNetd(NetdConsumer *);
void StopNetd();
void SendNetdCommand(NetdCommand *);
} // namespace ipc
} // namespace mozilla
#endif // mozilla_system_netd_h__

View file

@ -1,17 +0,0 @@
# -*- 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 += [
'Netd.h',
]
SOURCES += [
'Netd.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'

View file

@ -1,123 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <fcntl.h>
#include "UnixFdWatcher.h"
#ifdef CHROMIUM_LOG
#undef CHROMIUM_LOG
#endif
#include <stdio.h>
#define IODEBUG true
#define CHROMIUM_LOG(args...) if (IODEBUG) printf(args);
namespace mozilla {
namespace ipc {
UnixFdWatcher::~UnixFdWatcher()
{
NS_WARNING_ASSERTION(!IsOpen(), "mFd should have been closed already");
}
void
UnixFdWatcher::Close()
{
MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop);
if (NS_WARN_IF(!IsOpen())) {
/* mFd should have been open */
return;
}
OnClose();
RemoveWatchers(READ_WATCHER|WRITE_WATCHER);
mFd.dispose();
}
void
UnixFdWatcher::AddWatchers(unsigned long aWatchers, bool aPersistent)
{
MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop);
MOZ_ASSERT(IsOpen());
// Before we add a watcher, we need to remove it! Removing is always
// safe, but adding the same watcher twice can lead to endless loops
// inside libevent.
RemoveWatchers(aWatchers);
if (aWatchers & READ_WATCHER) {
MessageLoopForIO::current()->WatchFileDescriptor(
mFd,
aPersistent,
MessageLoopForIO::WATCH_READ,
&mReadWatcher,
this);
}
if (aWatchers & WRITE_WATCHER) {
MessageLoopForIO::current()->WatchFileDescriptor(
mFd,
aPersistent,
MessageLoopForIO::WATCH_WRITE,
&mWriteWatcher,
this);
}
}
void
UnixFdWatcher::RemoveWatchers(unsigned long aWatchers)
{
MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop);
MOZ_ASSERT(IsOpen());
if (aWatchers & READ_WATCHER) {
mReadWatcher.StopWatchingFileDescriptor();
}
if (aWatchers & WRITE_WATCHER) {
mWriteWatcher.StopWatchingFileDescriptor();
}
}
void
UnixFdWatcher::OnError(const char* aFunction, int aErrno)
{
MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop);
CHROMIUM_LOG("%s failed with error %d (%s)",
aFunction, aErrno, strerror(aErrno));
}
UnixFdWatcher::UnixFdWatcher(MessageLoop* aIOLoop)
: mIOLoop(aIOLoop)
{
MOZ_ASSERT(mIOLoop);
}
UnixFdWatcher::UnixFdWatcher(MessageLoop* aIOLoop, int aFd)
: mIOLoop(aIOLoop)
, mFd(aFd)
{
MOZ_ASSERT(mIOLoop);
}
void
UnixFdWatcher::SetFd(int aFd)
{
MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop);
MOZ_ASSERT(!IsOpen());
MOZ_ASSERT(FdIsNonBlocking(aFd));
mFd = aFd;
}
bool
UnixFdWatcher::FdIsNonBlocking(int aFd)
{
int flags = TEMP_FAILURE_RETRY(fcntl(aFd, F_GETFL));
return (flags > 0) && (flags & O_NONBLOCK);
}
}
}

View file

@ -1,69 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_ipc_UnixFdWatcher_h
#define mozilla_ipc_UnixFdWatcher_h
#include "base/message_loop.h"
#include "mozilla/FileUtils.h"
namespace mozilla {
namespace ipc {
class UnixFdWatcher : public MessageLoopForIO::Watcher
{
public:
enum {
READ_WATCHER = 1<<0,
WRITE_WATCHER = 1<<1
};
virtual ~UnixFdWatcher();
MessageLoop* GetIOLoop() const
{
return mIOLoop;
}
int GetFd() const
{
return mFd;
}
bool IsOpen() const
{
return GetFd() >= 0;
}
virtual void Close();
void AddWatchers(unsigned long aWatchers, bool aPersistent);
void RemoveWatchers(unsigned long aWatchers);
// Callback method that's run before closing the file descriptor
virtual void OnClose() {};
// Callback method that's run on POSIX errors
virtual void OnError(const char* aFunction, int aErrno);
protected:
UnixFdWatcher(MessageLoop* aIOLoop);
UnixFdWatcher(MessageLoop* aIOLoop, int aFd);
void SetFd(int aFd);
private:
static bool FdIsNonBlocking(int aFd);
MessageLoop* mIOLoop;
ScopedClose mFd;
MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
MessageLoopForIO::FileDescriptorWatcher mWriteWatcher;
};
}
}
#endif

View file

@ -1,45 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <fcntl.h>
#include "UnixFileWatcher.h"
namespace mozilla {
namespace ipc {
UnixFileWatcher::~UnixFileWatcher()
{
}
nsresult
UnixFileWatcher::Open(const char* aFilename, int aFlags, mode_t aMode)
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(aFlags & O_NONBLOCK);
int fd = TEMP_FAILURE_RETRY(open(aFilename, aFlags, aMode));
if (fd < 0) {
OnError("open", errno);
return NS_ERROR_FAILURE;
}
SetFd(fd);
OnOpened();
return NS_OK;
}
UnixFileWatcher::UnixFileWatcher(MessageLoop* aIOLoop)
: UnixFdWatcher(aIOLoop)
{
}
UnixFileWatcher::UnixFileWatcher(MessageLoop* aIOLoop, int aFd)
: UnixFdWatcher(aIOLoop, aFd)
{
}
}
}

View file

@ -1,33 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_ipc_UnixFileWatcher_h
#define mozilla_ipc_UnixFileWatcher_h
#include "UnixFdWatcher.h"
namespace mozilla {
namespace ipc {
class UnixFileWatcher : public UnixFdWatcher
{
public:
virtual ~UnixFileWatcher();
nsresult Open(const char* aFilename, int aFlags, mode_t aMode = 0);
// Callback method for successful open requests
virtual void OnOpened() {};
protected:
UnixFileWatcher(MessageLoop* aIOLoop);
UnixFileWatcher(MessageLoop* aIOLoop, int aFd);
};
}
}
#endif

View file

@ -1,136 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <fcntl.h>
#include "UnixSocketWatcher.h"
namespace mozilla {
namespace ipc {
UnixSocketWatcher::~UnixSocketWatcher()
{
}
void UnixSocketWatcher::Close()
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
mConnectionStatus = SOCKET_IS_DISCONNECTED;
UnixFdWatcher::Close();
}
nsresult
UnixSocketWatcher::Connect(const struct sockaddr* aAddr, socklen_t aAddrLen)
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(IsOpen());
MOZ_ASSERT(aAddr || !aAddrLen);
if (TEMP_FAILURE_RETRY(connect(GetFd(), aAddr, aAddrLen) < 0)) {
if (errno == EINPROGRESS) {
mConnectionStatus = SOCKET_IS_CONNECTING;
// Set up a write watch to receive the connect signal
AddWatchers(WRITE_WATCHER, false);
return NS_OK;
}
OnError("connect", errno);
return NS_ERROR_FAILURE;
}
mConnectionStatus = SOCKET_IS_CONNECTED;
OnConnected();
return NS_OK;
}
nsresult
UnixSocketWatcher::Listen(const struct sockaddr* aAddr, socklen_t aAddrLen)
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(IsOpen());
MOZ_ASSERT(aAddr || !aAddrLen);
if (mConnectionStatus == SOCKET_IS_DISCONNECTED) {
// We init the socket descriptor when we listen for the first time.
if (bind(GetFd(), aAddr, aAddrLen) < 0) {
OnError("bind", errno);
return NS_ERROR_FAILURE;
}
if (listen(GetFd(), 1) < 0) {
OnError("listen", errno);
return NS_ERROR_FAILURE;
}
}
mConnectionStatus = SOCKET_IS_LISTENING;
OnListening();
return NS_OK;
}
UnixSocketWatcher::UnixSocketWatcher(MessageLoop* aIOLoop)
: UnixFdWatcher(aIOLoop)
, mConnectionStatus(SOCKET_IS_DISCONNECTED)
{
}
UnixSocketWatcher::UnixSocketWatcher(MessageLoop* aIOLoop, int aFd,
ConnectionStatus aConnectionStatus)
: UnixFdWatcher(aIOLoop, aFd)
, mConnectionStatus(aConnectionStatus)
{
}
void
UnixSocketWatcher::SetSocket(int aFd, ConnectionStatus aConnectionStatus)
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
SetFd(aFd);
mConnectionStatus = aConnectionStatus;
}
void
UnixSocketWatcher::OnFileCanReadWithoutBlocking(int aFd)
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(aFd == GetFd());
if (mConnectionStatus == SOCKET_IS_CONNECTED) {
OnSocketCanReceiveWithoutBlocking();
} else if (mConnectionStatus == SOCKET_IS_LISTENING) {
OnSocketCanAcceptWithoutBlocking();
} else {
NS_NOTREACHED("invalid connection state for reading");
}
}
void
UnixSocketWatcher::OnFileCanWriteWithoutBlocking(int aFd)
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(aFd == GetFd());
if (mConnectionStatus == SOCKET_IS_CONNECTED) {
OnSocketCanSendWithoutBlocking();
} else if (mConnectionStatus == SOCKET_IS_CONNECTING) {
RemoveWatchers(WRITE_WATCHER);
int error = 0;
socklen_t len = sizeof(error);
if (getsockopt(GetFd(), SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
OnError("getsockopt", errno);
} else if (error) {
OnError("connect", error);
} else {
mConnectionStatus = SOCKET_IS_CONNECTED;
OnConnected();
}
} else {
NS_NOTREACHED("invalid connection state for writing");
}
}
}
}

View file

@ -1,72 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_ipc_UnixSocketWatcher_h
#define mozilla_ipc_UnixSocketWatcher_h
#include <sys/socket.h>
#include "UnixFdWatcher.h"
namespace mozilla {
namespace ipc {
class UnixSocketWatcher : public UnixFdWatcher
{
public:
enum ConnectionStatus {
SOCKET_IS_DISCONNECTED = 0,
SOCKET_IS_LISTENING,
SOCKET_IS_CONNECTING,
SOCKET_IS_CONNECTED
};
virtual ~UnixSocketWatcher();
virtual void Close() override;
ConnectionStatus GetConnectionStatus() const
{
return mConnectionStatus;
}
// Connect to a peer
nsresult Connect(const struct sockaddr* aAddr, socklen_t aAddrLen);
// Listen on socket for incoming connection requests
nsresult Listen(const struct sockaddr* aAddr, socklen_t aAddrLen);
// Callback method for successful connection requests
virtual void OnConnected() {};
// Callback method for successful listen requests
virtual void OnListening() {};
// Callback method for accepting from a listening socket
virtual void OnSocketCanAcceptWithoutBlocking() {};
// Callback method for receiving from socket
virtual void OnSocketCanReceiveWithoutBlocking() {};
// Callback method for sending on socket
virtual void OnSocketCanSendWithoutBlocking() {};
protected:
UnixSocketWatcher(MessageLoop* aIOLoop);
UnixSocketWatcher(MessageLoop* aIOLoop, int aFd,
ConnectionStatus aConnectionStatus);
void SetSocket(int aFd, ConnectionStatus aConnectionStatus);
private:
void OnFileCanReadWithoutBlocking(int aFd) override;
void OnFileCanWriteWithoutBlocking(int aFd) override;
ConnectionStatus mConnectionStatus;
};
}
}
#endif

View file

@ -1,21 +0,0 @@
# -*- 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 += [
'UnixFdWatcher.h',
'UnixFileWatcher.h',
'UnixSocketWatcher.h'
]
SOURCES += [
'UnixFdWatcher.cpp',
'UnixFileWatcher.cpp',
'UnixSocketWatcher.cpp'
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'

View file

@ -1,202 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ConnectionOrientedSocket.h"
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, MOZ_COUNT_DTOR
#include "UnixSocketConnector.h"
namespace mozilla {
namespace ipc {
//
// ConnectionOrientedSocketIO
//
ConnectionOrientedSocketIO::ConnectionOrientedSocketIO(
MessageLoop* aConsumerLoop,
MessageLoop* aIOLoop,
int aFd, ConnectionStatus aConnectionStatus,
UnixSocketConnector* aConnector)
: DataSocketIO(aConsumerLoop)
, UnixSocketWatcher(aIOLoop, aFd, aConnectionStatus)
, mConnector(aConnector)
, mPeerAddressLength(0)
{
MOZ_ASSERT(mConnector);
MOZ_COUNT_CTOR_INHERITED(ConnectionOrientedSocketIO, DataSocketIO);
}
ConnectionOrientedSocketIO::ConnectionOrientedSocketIO(
MessageLoop* aConsumerLoop,
MessageLoop* aIOLoop,
UnixSocketConnector* aConnector)
: DataSocketIO(aConsumerLoop)
, UnixSocketWatcher(aIOLoop)
, mConnector(aConnector)
, mPeerAddressLength(0)
{
MOZ_ASSERT(mConnector);
MOZ_COUNT_CTOR_INHERITED(ConnectionOrientedSocketIO, DataSocketIO);
}
ConnectionOrientedSocketIO::~ConnectionOrientedSocketIO()
{
MOZ_COUNT_DTOR_INHERITED(ConnectionOrientedSocketIO, DataSocketIO);
}
nsresult
ConnectionOrientedSocketIO::Accept(int aFd,
const struct sockaddr* aPeerAddress,
socklen_t aPeerAddressLength)
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTING);
SetSocket(aFd, SOCKET_IS_CONNECTED);
// Address setup
mPeerAddressLength = aPeerAddressLength;
memcpy(&mPeerAddress, aPeerAddress, mPeerAddressLength);
// Signal success and start data transfer
OnConnected();
return NS_OK;
}
nsresult
ConnectionOrientedSocketIO::Connect()
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(!IsOpen());
struct sockaddr* peerAddress =
reinterpret_cast<struct sockaddr*>(&mPeerAddress);
mPeerAddressLength = sizeof(mPeerAddress);
int fd;
nsresult rv = mConnector->CreateStreamSocket(peerAddress,
&mPeerAddressLength,
fd);
if (NS_FAILED(rv)) {
// Tell the consumer thread we've errored
GetConsumerThread()->PostTask(
MakeAndAddRef<SocketEventTask>(this, SocketEventTask::CONNECT_ERROR));
return NS_ERROR_FAILURE;
}
SetFd(fd);
// calls OnConnected() on success, or OnError() otherwise
rv = UnixSocketWatcher::Connect(peerAddress, mPeerAddressLength);
if (NS_FAILED(rv)) {
return rv;
}
return NS_OK;
}
void
ConnectionOrientedSocketIO::Send(UnixSocketIOBuffer* aBuffer)
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
EnqueueData(aBuffer);
AddWatchers(WRITE_WATCHER, false);
}
// |UnixSocketWatcher|
void
ConnectionOrientedSocketIO::OnSocketCanReceiveWithoutBlocking()
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED); // see bug 990984
ssize_t res = ReceiveData(GetFd());
if (res < 0) {
/* I/O error */
RemoveWatchers(READ_WATCHER|WRITE_WATCHER);
} else if (!res) {
/* EOF or peer shutdown */
RemoveWatchers(READ_WATCHER);
}
}
void
ConnectionOrientedSocketIO::OnSocketCanSendWithoutBlocking()
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED); // see bug 990984
MOZ_ASSERT(!IsShutdownOnIOThread());
nsresult rv = SendPendingData(GetFd());
if (NS_FAILED(rv)) {
return;
}
if (HasPendingData()) {
AddWatchers(WRITE_WATCHER, false);
}
}
void
ConnectionOrientedSocketIO::OnConnected()
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED);
GetConsumerThread()->PostTask(
MakeAndAddRef<SocketEventTask>(this, SocketEventTask::CONNECT_SUCCESS));
AddWatchers(READ_WATCHER, true);
if (HasPendingData()) {
AddWatchers(WRITE_WATCHER, false);
}
}
void
ConnectionOrientedSocketIO::OnListening()
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
NS_NOTREACHED("Invalid call to |ConnectionOrientedSocketIO::OnListening|");
}
void
ConnectionOrientedSocketIO::OnError(const char* aFunction, int aErrno)
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
UnixFdWatcher::OnError(aFunction, aErrno);
// Clean up watchers, status, fd
Close();
// Tell the consumer thread we've errored
GetConsumerThread()->PostTask(
MakeAndAddRef<SocketEventTask>(this, SocketEventTask::CONNECT_ERROR));
}
//
// ConnectionOrientedSocket
//
ConnectionOrientedSocket::ConnectionOrientedSocket()
{
MOZ_COUNT_CTOR_INHERITED(ConnectionOrientedSocket, DataSocket);
}
ConnectionOrientedSocket::~ConnectionOrientedSocket()
{
MOZ_COUNT_DTOR_INHERITED(ConnectionOrientedSocket, DataSocket);
}
}
}

View file

@ -1,122 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_ipc_ConnectionOrientedSocket_h
#define mozilla_ipc_ConnectionOrientedSocket_h
#include <sys/socket.h>
#include "DataSocket.h"
#include "mozilla/ipc/UnixSocketWatcher.h"
class MessageLoop;
namespace mozilla {
namespace ipc {
class UnixSocketConnector;
/*
* |ConnectionOrientedSocketIO| and |ConnectionOrientedSocket| define
* interfaces for implementing stream sockets on I/O and consumer thread.
* |ListenSocket| uses these classes to handle accepted sockets.
*/
class ConnectionOrientedSocketIO
: public DataSocketIO
, public UnixSocketWatcher
{
public:
virtual ~ConnectionOrientedSocketIO();
nsresult Accept(int aFd,
const struct sockaddr* aAddress,
socklen_t aAddressLength);
nsresult Connect();
void Send(UnixSocketIOBuffer* aBuffer);
// Methods for |UnixSocketWatcher|
//
void OnSocketCanReceiveWithoutBlocking() final;
void OnSocketCanSendWithoutBlocking() final;
void OnListening() final;
void OnConnected() final;
void OnError(const char* aFunction, int aErrno) final;
protected:
/**
* Constructs an instance of |ConnectionOrientedSocketIO|
*
* @param aConsumerLoop The socket's consumer thread.
* @param aIOLoop The socket's I/O loop.
* @param aFd The socket file descriptor.
* @param aConnectionStatus The connection status for |aFd|.
* @param aConnector Connector object for socket-type-specific methods.
*/
ConnectionOrientedSocketIO(MessageLoop* aConsumerLoop,
MessageLoop* aIOLoop,
int aFd, ConnectionStatus aConnectionStatus,
UnixSocketConnector* aConnector);
/**
* Constructs an instance of |ConnectionOrientedSocketIO|
*
* @param aConsumerLoop The socket's consumer thread.
* @param aIOLoop The socket's I/O loop.
* @param aConnector Connector object for socket-type-specific methods.
*/
ConnectionOrientedSocketIO(MessageLoop* aConsumerLoop,
MessageLoop* aIOLoop,
UnixSocketConnector* aConnector);
private:
/**
* Connector object used to create the connection we are currently using.
*/
UniquePtr<UnixSocketConnector> mConnector;
/**
* Number of valid bytes in |mPeerAddress|.
*/
socklen_t mPeerAddressLength;
/**
* Address of the socket's current peer.
*/
struct sockaddr_storage mPeerAddress;
};
class ConnectionOrientedSocket : public DataSocket
{
public:
/**
* Prepares an instance of |ConnectionOrientedSocket| in DISCONNECTED
* state for accepting a connection. Consumer-thread only.
*
* @param aConnector The new connector object, owned by the
* connection-oriented socket.
* @param aConsumerLoop The socket's consumer thread.
* @param aIOLoop The socket's I/O thread.
* @param[out] aIO, Returns an instance of |ConnectionOrientedSocketIO|.
* @return NS_OK on success, or an XPCOM error code otherwise.
*/
virtual nsresult PrepareAccept(UnixSocketConnector* aConnector,
MessageLoop* aConsumerLoop,
MessageLoop* aIOLoop,
ConnectionOrientedSocketIO*& aIO) = 0;
protected:
ConnectionOrientedSocket();
virtual ~ConnectionOrientedSocket();
};
}
}
#endif // mozilla_ipc_ConnectionOrientedSocket

View file

@ -1,136 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "DataSocket.h"
#ifdef MOZ_TASK_TRACER
#include "GeckoTaskTracer.h"
#endif
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, MOZ_COUNT_DTOR
#ifdef MOZ_TASK_TRACER
using namespace mozilla::tasktracer;
#endif
namespace mozilla {
namespace ipc {
//
// DataSocketIO
//
DataSocketIO::~DataSocketIO()
{
MOZ_COUNT_DTOR_INHERITED(DataSocketIO, SocketIOBase);
}
void
DataSocketIO::EnqueueData(UnixSocketIOBuffer* aBuffer)
{
if (!aBuffer->GetSize()) {
delete aBuffer; // delete empty data immediately
return;
}
mOutgoingQ.AppendElement(aBuffer);
}
bool
DataSocketIO::HasPendingData() const
{
return !mOutgoingQ.IsEmpty();
}
ssize_t
DataSocketIO::ReceiveData(int aFd)
{
MOZ_ASSERT(aFd >= 0);
UnixSocketIOBuffer* incoming;
nsresult rv = QueryReceiveBuffer(&incoming);
if (NS_FAILED(rv)) {
/* an error occured */
GetConsumerThread()->PostTask(
MakeAndAddRef<SocketRequestClosingTask>(this));
return -1;
}
ssize_t res = incoming->Receive(aFd);
if (res < 0) {
/* an I/O error occured */
DiscardBuffer();
GetConsumerThread()->PostTask(
MakeAndAddRef<SocketRequestClosingTask>(this));
return -1;
} else if (!res) {
/* EOF or peer shut down sending */
DiscardBuffer();
GetConsumerThread()->PostTask(
MakeAndAddRef<SocketRequestClosingTask>(this));
return 0;
}
#ifdef MOZ_TASK_TRACER
/* Make unix socket creation events to be the source events of TaskTracer,
* and originate the rest correlation tasks from here.
*/
AutoSourceEvent taskTracerEvent(SourceEventType::Unixsocket);
#endif
ConsumeBuffer();
return res;
}
nsresult
DataSocketIO::SendPendingData(int aFd)
{
MOZ_ASSERT(aFd >= 0);
while (HasPendingData()) {
UnixSocketIOBuffer* outgoing = mOutgoingQ.ElementAt(0);
ssize_t res = outgoing->Send(aFd);
if (res < 0) {
/* an I/O error occured */
GetConsumerThread()->PostTask(
MakeAndAddRef<SocketRequestClosingTask>(this));
return NS_ERROR_FAILURE;
} else if (!res && outgoing->GetSize()) {
/* I/O is currently blocked; try again later */
return NS_OK;
}
if (!outgoing->GetSize()) {
mOutgoingQ.RemoveElementAt(0);
delete outgoing;
}
}
return NS_OK;
}
DataSocketIO::DataSocketIO(MessageLoop* aConsumerLoop)
: SocketIOBase(aConsumerLoop)
{
MOZ_COUNT_CTOR_INHERITED(DataSocketIO, SocketIOBase);
}
//
// DataSocket
//
DataSocket::DataSocket()
{
MOZ_COUNT_CTOR_INHERITED(DataSocket, SocketBase);
}
DataSocket::~DataSocket()
{
MOZ_COUNT_DTOR_INHERITED(DataSocket, SocketBase);
}
}
}

View file

@ -1,145 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifndef mozilla_ipc_datasocket_h
#define mozilla_ipc_datasocket_h
#include "mozilla/ipc/SocketBase.h"
#include "nsTArray.h"
namespace mozilla {
namespace ipc {
//
// DataSocket
//
/**
* |DataSocket| represents a socket that can send or receive data. This
* can be a stream-based socket, a datagram-based socket, or any other
* socket that transfers data.
*/
class DataSocket : public SocketBase
{
public:
virtual ~DataSocket();
/**
* Queue data to be sent to the socket on the IO thread. Can only be called on
* originating thread.
*
* @param aBuffer Data to be sent to socket
*/
virtual void SendSocketData(UnixSocketIOBuffer* aBuffer) = 0;
protected:
DataSocket();
};
//
// DataSocketIO
//
/**
* |DataSocketIO| is a base class for Socket I/O classes that
* transfer data on the I/O thread. It provides methods for the
* most common read and write scenarios.
*/
class DataSocketIO : public SocketIOBase
{
public:
virtual ~DataSocketIO();
/**
* Allocates a buffer for receiving data from the socket. The method
* shall return the buffer in the arguments. The buffer is owned by the
* I/O class. |DataSocketIO| will never ask for more than one buffer
* at a time, so I/O classes can handout the same buffer on each invokation
* of this method. I/O-thread only.
*
* @param[out] aBuffer returns a pointer to the I/O buffer
* @return NS_OK on success, or an error code otherwise
*/
virtual nsresult QueryReceiveBuffer(UnixSocketIOBuffer** aBuffer) = 0;
/**
* Marks the current socket buffer to by consumed by the I/O class. The
* class is resonsible for releasing the buffer afterwards. I/O-thread
* only.
*
* @param aIndex the socket's index
* @param[out] aBuffer the receive buffer
* @param[out] aSize the receive buffer's size
*/
virtual void ConsumeBuffer() = 0;
/**
* Marks the current socket buffer to be discarded. The I/O class is
* resonsible for releasing the buffer's memory. I/O-thread only.
*
* @param aIndex the socket's index
*/
virtual void DiscardBuffer() = 0;
void EnqueueData(UnixSocketIOBuffer* aBuffer);
bool HasPendingData() const;
ssize_t ReceiveData(int aFd);
nsresult SendPendingData(int aFd);
protected:
DataSocketIO(MessageLoop* aConsumerLoop);
private:
/**
* Raw data queue. Must be pushed/popped from I/O thread only.
*/
nsTArray<UnixSocketIOBuffer*> mOutgoingQ;
};
//
// Tasks
//
/* |SocketIOSendTask| transfers an instance of |Tdata|, such as
* |UnixSocketRawData|, to the I/O thread and queues it up for
* sending the contained data.
*/
template<typename Tio, typename Tdata>
class SocketIOSendTask final : public SocketIOTask<Tio>
{
public:
SocketIOSendTask(Tio* aIO, Tdata* aData)
: SocketIOTask<Tio>(aIO)
, mData(aData)
{
MOZ_ASSERT(aData);
}
NS_IMETHOD Run() override
{
MOZ_ASSERT(!SocketIOTask<Tio>::IsCanceled());
Tio* io = SocketIOTask<Tio>::GetIO();
MOZ_ASSERT(!io->IsConsumerThread());
MOZ_ASSERT(!io->IsShutdownOnIOThread());
io->Send(mData);
return NS_OK;
}
private:
Tdata* mData;
};
}
}
#endif

View file

@ -1,432 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ListenSocket.h"
#include <fcntl.h>
#include "ConnectionOrientedSocket.h"
#include "DataSocket.h"
#include "ListenSocketConsumer.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Unused.h"
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, MOZ_COUNT_DTOR
#include "nsXULAppAPI.h"
#include "UnixSocketConnector.h"
namespace mozilla {
namespace ipc {
//
// ListenSocketIO
//
class ListenSocketIO final
: public UnixSocketWatcher
, public SocketIOBase
{
public:
class ListenTask;
ListenSocketIO(MessageLoop* aConsumerLoop,
MessageLoop* aIOLoop,
ListenSocket* aListenSocket,
UnixSocketConnector* aConnector);
~ListenSocketIO();
UnixSocketConnector* GetConnector() const;
// Task callback methods
//
/**
* Run bind/listen to prepare for further runs of accept()
*/
void Listen(ConnectionOrientedSocketIO* aCOSocketIO);
// I/O callback methods
//
void OnConnected() override;
void OnError(const char* aFunction, int aErrno) override;
void OnListening() override;
void OnSocketCanAcceptWithoutBlocking() override;
// Methods for |SocketIOBase|
//
SocketBase* GetSocketBase() override;
bool IsShutdownOnConsumerThread() const override;
bool IsShutdownOnIOThread() const override;
void ShutdownOnConsumerThread() override;
void ShutdownOnIOThread() override;
private:
void FireSocketError();
/**
* Consumer pointer. Non-thread-safe pointer, so should only be manipulated
* directly from consumer thread. All non-consumer-thread accesses should
* happen with mIO as container.
*/
ListenSocket* mListenSocket;
/**
* Connector object used to create the connection we are currently using.
*/
UniquePtr<UnixSocketConnector> mConnector;
/**
* If true, do not requeue whatever task we're running
*/
bool mShuttingDownOnIOThread;
/**
* Number of valid bytes in |mAddress|
*/
socklen_t mAddressLength;
/**
* Address structure of the socket currently in use
*/
struct sockaddr_storage mAddress;
ConnectionOrientedSocketIO* mCOSocketIO;
};
ListenSocketIO::ListenSocketIO(MessageLoop* aConsumerLoop,
MessageLoop* aIOLoop,
ListenSocket* aListenSocket,
UnixSocketConnector* aConnector)
: UnixSocketWatcher(aIOLoop)
, SocketIOBase(aConsumerLoop)
, mListenSocket(aListenSocket)
, mConnector(aConnector)
, mShuttingDownOnIOThread(false)
, mAddressLength(0)
, mCOSocketIO(nullptr)
{
MOZ_ASSERT(mListenSocket);
MOZ_ASSERT(mConnector);
MOZ_COUNT_CTOR_INHERITED(ListenSocketIO, SocketIOBase);
}
ListenSocketIO::~ListenSocketIO()
{
MOZ_ASSERT(IsConsumerThread());
MOZ_ASSERT(IsShutdownOnConsumerThread());
MOZ_COUNT_DTOR_INHERITED(ListenSocketIO, SocketIOBase);
}
UnixSocketConnector*
ListenSocketIO::GetConnector() const
{
return mConnector.get();
}
void
ListenSocketIO::Listen(ConnectionOrientedSocketIO* aCOSocketIO)
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(mConnector);
MOZ_ASSERT(aCOSocketIO);
struct sockaddr* address = reinterpret_cast<struct sockaddr*>(&mAddress);
mAddressLength = sizeof(mAddress);
if (!IsOpen()) {
int fd;
nsresult rv = mConnector->CreateListenSocket(address, &mAddressLength,
fd);
if (NS_FAILED(rv)) {
FireSocketError();
return;
}
SetFd(fd);
}
mCOSocketIO = aCOSocketIO;
// calls OnListening on success, or OnError otherwise
DebugOnly<nsresult> rv = UnixSocketWatcher::Listen(address, mAddressLength);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Listen failed");
}
void
ListenSocketIO::OnConnected()
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
NS_NOTREACHED("Invalid call to |ListenSocketIO::OnConnected|");
}
void
ListenSocketIO::OnListening()
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_LISTENING);
AddWatchers(READ_WATCHER, true);
/* We signal a successful 'connection' to a local address for listening. */
GetConsumerThread()->PostTask(
MakeAndAddRef<SocketEventTask>(this, SocketEventTask::CONNECT_SUCCESS));
}
void
ListenSocketIO::OnError(const char* aFunction, int aErrno)
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
UnixFdWatcher::OnError(aFunction, aErrno);
FireSocketError();
}
void
ListenSocketIO::FireSocketError()
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
// Clean up watchers, statuses, fds
Close();
// Tell the consumer thread we've errored
GetConsumerThread()->PostTask(
MakeAndAddRef<SocketEventTask>(this, SocketEventTask::CONNECT_ERROR));
}
void
ListenSocketIO::OnSocketCanAcceptWithoutBlocking()
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_LISTENING);
MOZ_ASSERT(mCOSocketIO);
RemoveWatchers(READ_WATCHER|WRITE_WATCHER);
struct sockaddr_storage storage;
socklen_t addressLength = sizeof(storage);
int fd;
nsresult rv = mConnector->AcceptStreamSocket(
GetFd(),
reinterpret_cast<struct sockaddr*>(&storage), &addressLength,
fd);
if (NS_FAILED(rv)) {
FireSocketError();
return;
}
mCOSocketIO->Accept(fd,
reinterpret_cast<struct sockaddr*>(&storage),
addressLength);
}
// |SocketIOBase|
SocketBase*
ListenSocketIO::GetSocketBase()
{
return mListenSocket;
}
bool
ListenSocketIO::IsShutdownOnConsumerThread() const
{
MOZ_ASSERT(IsConsumerThread());
return mListenSocket == nullptr;
}
bool
ListenSocketIO::IsShutdownOnIOThread() const
{
return mShuttingDownOnIOThread;
}
void
ListenSocketIO::ShutdownOnConsumerThread()
{
MOZ_ASSERT(IsConsumerThread());
MOZ_ASSERT(!IsShutdownOnConsumerThread());
mListenSocket = nullptr;
}
void
ListenSocketIO::ShutdownOnIOThread()
{
MOZ_ASSERT(!IsConsumerThread());
MOZ_ASSERT(!mShuttingDownOnIOThread);
Close(); // will also remove fd from I/O loop
mShuttingDownOnIOThread = true;
}
//
// Socket tasks
//
class ListenSocketIO::ListenTask final : public SocketIOTask<ListenSocketIO>
{
public:
ListenTask(ListenSocketIO* aIO, ConnectionOrientedSocketIO* aCOSocketIO)
: SocketIOTask<ListenSocketIO>(aIO)
, mCOSocketIO(aCOSocketIO)
{
MOZ_ASSERT(mCOSocketIO);
MOZ_COUNT_CTOR(ListenTask);
}
~ListenTask()
{
MOZ_COUNT_DTOR(ListenTask);
}
NS_IMETHOD Run() override
{
MOZ_ASSERT(!GetIO()->IsConsumerThread());
if (!IsCanceled()) {
GetIO()->Listen(mCOSocketIO);
}
return NS_OK;
}
private:
ConnectionOrientedSocketIO* mCOSocketIO;
};
//
// ListenSocket
//
ListenSocket::ListenSocket(ListenSocketConsumer* aConsumer, int aIndex)
: mIO(nullptr)
, mConsumer(aConsumer)
, mIndex(aIndex)
{
MOZ_ASSERT(mConsumer);
MOZ_COUNT_CTOR_INHERITED(ListenSocket, SocketBase);
}
ListenSocket::~ListenSocket()
{
MOZ_ASSERT(!mIO);
MOZ_COUNT_DTOR_INHERITED(ListenSocket, SocketBase);
}
nsresult
ListenSocket::Listen(UnixSocketConnector* aConnector,
MessageLoop* aConsumerLoop,
MessageLoop* aIOLoop,
ConnectionOrientedSocket* aCOSocket)
{
MOZ_ASSERT(!mIO);
mIO = new ListenSocketIO(aConsumerLoop, aIOLoop, this, aConnector);
// Prepared I/O object, now start listening.
nsresult rv = Listen(aCOSocket);
if (NS_FAILED(rv)) {
delete mIO;
mIO = nullptr;
return rv;
}
return NS_OK;
}
nsresult
ListenSocket::Listen(UnixSocketConnector* aConnector,
ConnectionOrientedSocket* aCOSocket)
{
return Listen(aConnector, MessageLoop::current(), XRE_GetIOMessageLoop(),
aCOSocket);
}
nsresult
ListenSocket::Listen(ConnectionOrientedSocket* aCOSocket)
{
MOZ_ASSERT(aCOSocket);
MOZ_ASSERT(mIO);
// We first prepare the connection-oriented socket with a
// socket connector and a socket I/O class.
UniquePtr<UnixSocketConnector> connector;
nsresult rv = mIO->GetConnector()->Duplicate(connector);
if (NS_FAILED(rv)) {
return rv;
}
ConnectionOrientedSocketIO* io;
rv = aCOSocket->PrepareAccept(connector.get(),
mIO->GetConsumerThread(), mIO->GetIOLoop(),
io);
if (NS_FAILED(rv)) {
return rv;
}
Unused << connector.release(); // now owned by |io|
// Then we start listening for connection requests.
SetConnectionStatus(SOCKET_LISTENING);
mIO->GetIOLoop()->PostTask(
MakeAndAddRef<ListenSocketIO::ListenTask>(mIO, io));
return NS_OK;
}
// |SocketBase|
void
ListenSocket::Close()
{
if (!mIO) {
return;
}
MOZ_ASSERT(mIO->IsConsumerThread());
// From this point on, we consider mIO as being deleted. We sever
// the relationship here so any future calls to listen or connect
// will create a new implementation.
mIO->ShutdownOnConsumerThread();
mIO->GetIOLoop()->PostTask(MakeAndAddRef<SocketIOShutdownTask>(mIO));
mIO = nullptr;
NotifyDisconnect();
}
void
ListenSocket::OnConnectSuccess()
{
mConsumer->OnConnectSuccess(mIndex);
}
void
ListenSocket::OnConnectError()
{
mConsumer->OnConnectError(mIndex);
}
void
ListenSocket::OnDisconnect()
{
mConsumer->OnDisconnect(mIndex);
}
} // namespace ipc
} // namespace mozilla

View file

@ -1,93 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_ipc_ListenSocket_h
#define mozilla_ipc_ListenSocket_h
#include "mozilla/ipc/SocketBase.h"
#include "nsString.h"
class MessageLoop;
namespace mozilla {
namespace ipc {
class ConnectionOrientedSocket;
class ListenSocketConsumer;
class ListenSocketIO;
class UnixSocketConnector;
class ListenSocket final : public SocketBase
{
public:
/**
* Constructs an instance of |ListenSocket|.
*
* @param aConsumer The consumer for the socket.
* @param aIndex An arbitrary index.
*/
ListenSocket(ListenSocketConsumer* aConsumer, int aIndex);
/**
* Starts a task on the socket that will try to accept a new connection
* in a non-blocking manner.
*
* @param aConnector Connector object for socket-type-specific functions
* @param aConsumerLoop The socket's consumer thread.
* @param aIOLoop The socket's I/O thread.
* @param aCOSocket The connection-oriented socket for handling the
* accepted connection.
* @return NS_OK on success, or an XPCOM error code otherwise.
*/
nsresult Listen(UnixSocketConnector* aConnector,
MessageLoop* aConsumerLoop,
MessageLoop* aIOLoop,
ConnectionOrientedSocket* aCOSocket);
/**
* Starts a task on the socket that will try to accept a new connection
* in a non-blocking manner.
*
* @param aConnector Connector object for socket-type-specific functions
* @param aCOSocket The connection-oriented socket for handling the
* accepted connection.
* @return NS_OK on success, or an XPCOM error code otherwise.
*/
nsresult Listen(UnixSocketConnector* aConnector,
ConnectionOrientedSocket* aCOSocket);
/**
* Starts a task on the socket that will try to accept a new connection
* in a non-blocking manner. This method re-uses a previously created
* listen socket.
*
* @param aCOSocket The connection-oriented socket for handling the
* accepted connection.
* @return NS_OK on success, or an XPCOM error code otherwise.
*/
nsresult Listen(ConnectionOrientedSocket* aCOSocket);
// Methods for |SocketBase|
//
void Close() override;
void OnConnectSuccess() override;
void OnConnectError() override;
void OnDisconnect() override;
protected:
virtual ~ListenSocket();
private:
ListenSocketIO* mIO;
ListenSocketConsumer* mConsumer;
int mIndex;
};
} // namespace ipc
} // namepsace mozilla
#endif // mozilla_ipc_ListenSocket_h

View file

@ -1,20 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ListenSocketConsumer.h"
namespace mozilla {
namespace ipc {
//
// ListenSocketConsumer
//
ListenSocketConsumer::~ListenSocketConsumer()
{ }
}
}

View file

@ -1,46 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_ipc_listensocketconsumer_h
#define mozilla_ipc_listensocketconsumer_h
namespace mozilla {
namespace ipc {
/**
* |ListenSocketConsumer| handles socket events.
*/
class ListenSocketConsumer
{
public:
virtual ~ListenSocketConsumer();
/**
* Callback for socket success. Consumer-thread only.
*
* @param aIndex The index that has been given to the listening socket.
*/
virtual void OnConnectSuccess(int aIndex) = 0;
/**
* Callback for socket errors. Consumer-thread only.
*
* @param aIndex The index that has been given to the listening socket.
*/
virtual void OnConnectError(int aIndex) = 0;
/**
* Callback for socket disconnect. Consumer-thread only.
*
* @param aIndex The index that has been given to the listeing socket.
*/
virtual void OnDisconnect(int aIndex) = 0;
};
}
}
#endif

View file

@ -1,449 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "SocketBase.h"
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, MOZ_COUNT_DTOR
namespace mozilla {
namespace ipc {
//
// UnixSocketIOBuffer
//
UnixSocketBuffer::UnixSocketBuffer()
: mSize(0)
, mOffset(0)
, mAvailableSpace(0)
, mData(nullptr)
{
MOZ_COUNT_CTOR(UnixSocketBuffer);
}
UnixSocketBuffer::~UnixSocketBuffer()
{
MOZ_COUNT_DTOR(UnixSocketBuffer);
// Make sure that the caller released the buffer's memory.
MOZ_ASSERT(!GetBuffer());
}
const uint8_t*
UnixSocketBuffer::Consume(size_t aLen)
{
if (NS_WARN_IF(GetSize() < aLen)) {
return nullptr;
}
uint8_t* data = mData + mOffset;
mOffset += aLen;
return data;
}
nsresult
UnixSocketBuffer::Read(void* aValue, size_t aLen)
{
const uint8_t* data = Consume(aLen);
if (!data) {
return NS_ERROR_OUT_OF_MEMORY;
}
memcpy(aValue, data, aLen);
return NS_OK;
}
uint8_t*
UnixSocketBuffer::Append(size_t aLen)
{
if (((mAvailableSpace - mSize) < aLen)) {
size_t availableSpace = mAvailableSpace + std::max(mAvailableSpace, aLen);
uint8_t* data = new uint8_t[availableSpace];
memcpy(data, mData, mSize);
mData = data;
mAvailableSpace = availableSpace;
}
uint8_t* data = mData + mSize;
mSize += aLen;
return data;
}
nsresult
UnixSocketBuffer::Write(const void* aValue, size_t aLen)
{
uint8_t* data = Append(aLen);
if (!data) {
return NS_ERROR_OUT_OF_MEMORY;
}
memcpy(data, aValue, aLen);
return NS_OK;
}
void
UnixSocketBuffer::CleanupLeadingSpace()
{
if (GetLeadingSpace()) {
if (GetSize() <= GetLeadingSpace()) {
memcpy(mData, GetData(), GetSize());
} else {
memmove(mData, GetData(), GetSize());
}
mOffset = 0;
}
}
//
// UnixSocketIOBuffer
//
UnixSocketIOBuffer::UnixSocketIOBuffer()
{
MOZ_COUNT_CTOR_INHERITED(UnixSocketIOBuffer, UnixSocketBuffer);
}
UnixSocketIOBuffer::~UnixSocketIOBuffer()
{
MOZ_COUNT_DTOR_INHERITED(UnixSocketIOBuffer, UnixSocketBuffer);
}
//
// UnixSocketRawData
//
UnixSocketRawData::UnixSocketRawData(const void* aData, size_t aSize)
{
MOZ_ASSERT(aData || !aSize);
MOZ_COUNT_CTOR_INHERITED(UnixSocketRawData, UnixSocketIOBuffer);
ResetBuffer(static_cast<uint8_t*>(memcpy(new uint8_t[aSize], aData, aSize)),
0, aSize, aSize);
}
UnixSocketRawData::UnixSocketRawData(UniquePtr<uint8_t[]> aData, size_t aSize)
{
MOZ_ASSERT(aData || !aSize);
MOZ_COUNT_CTOR_INHERITED(UnixSocketRawData, UnixSocketIOBuffer);
ResetBuffer(aData.release(), 0, aSize, aSize);
}
UnixSocketRawData::UnixSocketRawData(size_t aSize)
{
MOZ_COUNT_CTOR_INHERITED(UnixSocketRawData, UnixSocketIOBuffer);
ResetBuffer(new uint8_t[aSize], 0, 0, aSize);
}
UnixSocketRawData::~UnixSocketRawData()
{
MOZ_COUNT_DTOR_INHERITED(UnixSocketRawData, UnixSocketIOBuffer);
UniquePtr<uint8_t[]> data(GetBuffer());
ResetBuffer(nullptr, 0, 0, 0);
}
ssize_t
UnixSocketRawData::Receive(int aFd)
{
if (!GetTrailingSpace()) {
if (!GetLeadingSpace()) {
return -1; /* buffer is full */
}
/* free up space at the end of data buffer */
CleanupLeadingSpace();
}
ssize_t res =
TEMP_FAILURE_RETRY(read(aFd, GetTrailingBytes(), GetTrailingSpace()));
if (res < 0) {
/* I/O error */
return -1;
} else if (!res) {
/* EOF or peer shutdown sending */
return 0;
}
Append(res); /* mark read data as 'valid' */
return res;
}
ssize_t
UnixSocketRawData::Send(int aFd)
{
if (!GetSize()) {
return 0;
}
ssize_t res = TEMP_FAILURE_RETRY(write(aFd, GetData(), GetSize()));
if (res < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
return 0; /* socket is blocked; try again later */
}
return -1;
} else if (!res) {
/* nothing written */
return 0;
}
Consume(res);
return res;
}
//
// SocketBase
//
SocketConnectionStatus
SocketBase::GetConnectionStatus() const
{
return mConnectionStatus;
}
int
SocketBase::GetSuggestedConnectDelayMs() const
{
return mConnectDelayMs;
}
void
SocketBase::NotifySuccess()
{
mConnectionStatus = SOCKET_CONNECTED;
mConnectTimestamp = PR_IntervalNow();
OnConnectSuccess();
}
void
SocketBase::NotifyError()
{
mConnectionStatus = SOCKET_DISCONNECTED;
mConnectDelayMs = CalculateConnectDelayMs();
mConnectTimestamp = 0;
OnConnectError();
}
void
SocketBase::NotifyDisconnect()
{
mConnectionStatus = SOCKET_DISCONNECTED;
mConnectDelayMs = CalculateConnectDelayMs();
mConnectTimestamp = 0;
OnDisconnect();
}
uint32_t
SocketBase::CalculateConnectDelayMs() const
{
uint32_t connectDelayMs = mConnectDelayMs;
if (mConnectTimestamp && (PR_IntervalNow()-mConnectTimestamp) > connectDelayMs) {
// reset delay if connection has been opened for a while, or...
connectDelayMs = 0;
} else if (!connectDelayMs) {
// ...start with a delay of ~1 sec, or...
connectDelayMs = 1<<10;
} else if (connectDelayMs < (1<<16)) {
// ...otherwise increase delay by a factor of 2
connectDelayMs <<= 1;
}
return connectDelayMs;
}
SocketBase::SocketBase()
: mConnectionStatus(SOCKET_DISCONNECTED)
, mConnectTimestamp(0)
, mConnectDelayMs(0)
{
MOZ_COUNT_CTOR(SocketBase);
}
SocketBase::~SocketBase()
{
MOZ_ASSERT(mConnectionStatus == SOCKET_DISCONNECTED);
MOZ_COUNT_DTOR(SocketBase);
}
void
SocketBase::SetConnectionStatus(SocketConnectionStatus aConnectionStatus)
{
mConnectionStatus = aConnectionStatus;
}
//
// SocketIOBase
//
SocketIOBase::SocketIOBase(MessageLoop* aConsumerLoop)
: mConsumerLoop(aConsumerLoop)
{
MOZ_ASSERT(mConsumerLoop);
MOZ_COUNT_CTOR(SocketIOBase);
}
SocketIOBase::~SocketIOBase()
{
MOZ_COUNT_DTOR(SocketIOBase);
}
MessageLoop*
SocketIOBase::GetConsumerThread() const
{
return mConsumerLoop;
}
bool
SocketIOBase::IsConsumerThread() const
{
return GetConsumerThread() == MessageLoop::current();
}
//
// SocketEventTask
//
SocketEventTask::SocketEventTask(SocketIOBase* aIO, SocketEvent aEvent)
: SocketTask<SocketIOBase>(aIO)
, mEvent(aEvent)
{
MOZ_COUNT_CTOR(SocketEventTask);
}
SocketEventTask::~SocketEventTask()
{
MOZ_COUNT_DTOR(SocketEventTask);
}
NS_IMETHODIMP
SocketEventTask::Run()
{
SocketIOBase* io = SocketTask<SocketIOBase>::GetIO();
MOZ_ASSERT(io->IsConsumerThread());
if (NS_WARN_IF(io->IsShutdownOnConsumerThread())) {
// Since we've already explicitly closed and the close
// happened before this, this isn't really an error.
return NS_OK;
}
SocketBase* socketBase = io->GetSocketBase();
MOZ_ASSERT(socketBase);
if (mEvent == CONNECT_SUCCESS) {
socketBase->NotifySuccess();
} else if (mEvent == CONNECT_ERROR) {
socketBase->NotifyError();
} else if (mEvent == DISCONNECT) {
socketBase->NotifyDisconnect();
}
return NS_OK;
}
//
// SocketRequestClosingTask
//
SocketRequestClosingTask::SocketRequestClosingTask(SocketIOBase* aIO)
: SocketTask<SocketIOBase>(aIO)
{
MOZ_COUNT_CTOR(SocketRequestClosingTask);
}
SocketRequestClosingTask::~SocketRequestClosingTask()
{
MOZ_COUNT_DTOR(SocketRequestClosingTask);
}
NS_IMETHODIMP
SocketRequestClosingTask::Run()
{
SocketIOBase* io = SocketTask<SocketIOBase>::GetIO();
MOZ_ASSERT(io->IsConsumerThread());
if (NS_WARN_IF(io->IsShutdownOnConsumerThread())) {
// Since we've already explicitly closed and the close
// happened before this, this isn't really an error.
return NS_OK;
}
SocketBase* socketBase = io->GetSocketBase();
MOZ_ASSERT(socketBase);
socketBase->Close();
return NS_OK;
}
//
// SocketDeleteInstanceTask
//
SocketDeleteInstanceTask::SocketDeleteInstanceTask(SocketIOBase* aIO)
: mIO(aIO)
{
MOZ_COUNT_CTOR(SocketDeleteInstanceTask);
}
SocketDeleteInstanceTask::~SocketDeleteInstanceTask()
{
MOZ_COUNT_DTOR(SocketDeleteInstanceTask);
}
NS_IMETHODIMP
SocketDeleteInstanceTask::Run()
{
mIO.reset(); // delete instance
return NS_OK;
}
//
// SocketIOShutdownTask
//
SocketIOShutdownTask::SocketIOShutdownTask(SocketIOBase* aIO)
: SocketIOTask<SocketIOBase>(aIO)
{
MOZ_COUNT_CTOR(SocketIOShutdownTask);
}
SocketIOShutdownTask::~SocketIOShutdownTask()
{
MOZ_COUNT_DTOR(SocketIOShutdownTask);
}
NS_IMETHODIMP
SocketIOShutdownTask::Run()
{
SocketIOBase* io = SocketIOTask<SocketIOBase>::GetIO();
MOZ_ASSERT(!io->IsConsumerThread());
MOZ_ASSERT(!io->IsShutdownOnIOThread());
// At this point, there should be no new events on the I/O thread
// after this one with the possible exception of an accept task,
// which ShutdownOnIOThread will cancel for us. We are now fully
// shut down, so we can send a message to the consumer thread to
// delete |io| safely knowing that it's not reference any longer.
io->ShutdownOnIOThread();
io->GetConsumerThread()->PostTask(
MakeAndAddRef<SocketDeleteInstanceTask>(io));
return NS_OK;
}
}
}

View file

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

View file

@ -1,482 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "StreamSocket.h"
#include <fcntl.h>
#include "mozilla/RefPtr.h"
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, MOZ_COUNT_DTOR
#include "nsXULAppAPI.h"
#include "StreamSocketConsumer.h"
#include "UnixSocketConnector.h"
static const size_t MAX_READ_SIZE = 1 << 16;
namespace mozilla {
namespace ipc {
//
// StreamSocketIO
//
class StreamSocketIO final : public ConnectionOrientedSocketIO
{
public:
class ConnectTask;
class DelayedConnectTask;
class ReceiveTask;
StreamSocketIO(MessageLoop* aConsumerLoop,
MessageLoop* aIOLoop,
StreamSocket* aStreamSocket,
UnixSocketConnector* aConnector);
StreamSocketIO(MessageLoop* aConsumerLoop,
MessageLoop* aIOLoop,
int aFd, ConnectionStatus aConnectionStatus,
StreamSocket* aStreamSocket,
UnixSocketConnector* aConnector);
~StreamSocketIO();
StreamSocket* GetStreamSocket();
DataSocket* GetDataSocket();
// Delayed-task handling
//
void SetDelayedConnectTask(CancelableRunnable* aTask);
void ClearDelayedConnectTask();
void CancelDelayedConnectTask();
// Methods for |DataSocket|
//
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:
/**
* Consumer pointer. Non-thread-safe pointer, so should only be manipulated
* directly from consumer thread. All non-consumer-thread accesses should
* happen with mIO as container.
*/
StreamSocket* mStreamSocket;
/**
* If true, do not requeue whatever task we're running
*/
bool mShuttingDownOnIOThread;
/**
* Task member for delayed connect task. Should only be access on consumer
* thread.
*/
CancelableRunnable* mDelayedConnectTask;
/**
* I/O buffer for received data
*/
UniquePtr<UnixSocketRawData> mBuffer;
};
StreamSocketIO::StreamSocketIO(MessageLoop* aConsumerLoop,
MessageLoop* aIOLoop,
StreamSocket* aStreamSocket,
UnixSocketConnector* aConnector)
: ConnectionOrientedSocketIO(aConsumerLoop, aIOLoop, aConnector)
, mStreamSocket(aStreamSocket)
, mShuttingDownOnIOThread(false)
, mDelayedConnectTask(nullptr)
{
MOZ_ASSERT(mStreamSocket);
MOZ_COUNT_CTOR_INHERITED(StreamSocketIO, ConnectionOrientedSocketIO);
}
StreamSocketIO::StreamSocketIO(MessageLoop* aConsumerLoop,
MessageLoop* aIOLoop,
int aFd, ConnectionStatus aConnectionStatus,
StreamSocket* aStreamSocket,
UnixSocketConnector* aConnector)
: ConnectionOrientedSocketIO(aConsumerLoop,
aIOLoop,
aFd,
aConnectionStatus,
aConnector)
, mStreamSocket(aStreamSocket)
, mShuttingDownOnIOThread(false)
, mDelayedConnectTask(nullptr)
{
MOZ_ASSERT(mStreamSocket);
MOZ_COUNT_CTOR_INHERITED(StreamSocketIO, ConnectionOrientedSocketIO);
}
StreamSocketIO::~StreamSocketIO()
{
MOZ_ASSERT(IsConsumerThread());
MOZ_ASSERT(IsShutdownOnConsumerThread());
MOZ_COUNT_DTOR_INHERITED(StreamSocketIO, ConnectionOrientedSocketIO);
}
StreamSocket*
StreamSocketIO::GetStreamSocket()
{
return mStreamSocket;
}
DataSocket*
StreamSocketIO::GetDataSocket()
{
return GetStreamSocket();
}
void
StreamSocketIO::SetDelayedConnectTask(CancelableRunnable* aTask)
{
MOZ_ASSERT(IsConsumerThread());
mDelayedConnectTask = aTask;
}
void
StreamSocketIO::ClearDelayedConnectTask()
{
MOZ_ASSERT(IsConsumerThread());
mDelayedConnectTask = nullptr;
}
void
StreamSocketIO::CancelDelayedConnectTask()
{
MOZ_ASSERT(IsConsumerThread());
if (!mDelayedConnectTask) {
return;
}
mDelayedConnectTask->Cancel();
ClearDelayedConnectTask();
}
// |DataSocketIO|
nsresult
StreamSocketIO::QueryReceiveBuffer(UnixSocketIOBuffer** aBuffer)
{
MOZ_ASSERT(aBuffer);
if (!mBuffer) {
mBuffer = MakeUnique<UnixSocketRawData>(MAX_READ_SIZE);
}
*aBuffer = mBuffer.get();
return NS_OK;
}
/**
* |ReceiveTask| transfers data received on the I/O thread
* to an instance of |StreamSocket| on the consumer thread.
*/
class StreamSocketIO::ReceiveTask final : public SocketTask<StreamSocketIO>
{
public:
ReceiveTask(StreamSocketIO* aIO, UnixSocketBuffer* aBuffer)
: SocketTask<StreamSocketIO>(aIO)
, mBuffer(aBuffer)
{
MOZ_COUNT_CTOR(ReceiveTask);
}
~ReceiveTask()
{
MOZ_COUNT_DTOR(ReceiveTask);
}
NS_IMETHOD Run() override
{
StreamSocketIO* io = SocketTask<StreamSocketIO>::GetIO();
MOZ_ASSERT(io->IsConsumerThread());
if (NS_WARN_IF(io->IsShutdownOnConsumerThread())) {
// Since we've already explicitly closed and the close
// happened before this, this isn't really an error.
return NS_OK;
}
StreamSocket* streamSocket = io->GetStreamSocket();
MOZ_ASSERT(streamSocket);
streamSocket->ReceiveSocketData(mBuffer);
return NS_OK;
}
private:
UniquePtr<UnixSocketBuffer> mBuffer;
};
void
StreamSocketIO::ConsumeBuffer()
{
GetConsumerThread()->PostTask(
MakeAndAddRef<ReceiveTask>(this, mBuffer.release()));
}
void
StreamSocketIO::DiscardBuffer()
{
// Nothing to do.
}
// |SocketIOBase|
SocketBase*
StreamSocketIO::GetSocketBase()
{
return GetDataSocket();
}
bool
StreamSocketIO::IsShutdownOnConsumerThread() const
{
MOZ_ASSERT(IsConsumerThread());
return mStreamSocket == nullptr;
}
bool
StreamSocketIO::IsShutdownOnIOThread() const
{
return mShuttingDownOnIOThread;
}
void
StreamSocketIO::ShutdownOnConsumerThread()
{
MOZ_ASSERT(IsConsumerThread());
MOZ_ASSERT(!IsShutdownOnConsumerThread());
mStreamSocket = nullptr;
}
void
StreamSocketIO::ShutdownOnIOThread()
{
MOZ_ASSERT(!IsConsumerThread());
MOZ_ASSERT(!mShuttingDownOnIOThread);
Close(); // will also remove fd from I/O loop
mShuttingDownOnIOThread = true;
}
//
// Socket tasks
//
class StreamSocketIO::ConnectTask final : public SocketIOTask<StreamSocketIO>
{
public:
ConnectTask(StreamSocketIO* aIO)
: SocketIOTask<StreamSocketIO>(aIO)
{
MOZ_COUNT_CTOR(ReceiveTask);
}
~ConnectTask()
{
MOZ_COUNT_DTOR(ReceiveTask);
}
NS_IMETHOD Run() override
{
MOZ_ASSERT(!GetIO()->IsConsumerThread());
MOZ_ASSERT(!IsCanceled());
GetIO()->Connect();
return NS_OK;
}
};
class StreamSocketIO::DelayedConnectTask final
: public SocketIOTask<StreamSocketIO>
{
public:
DelayedConnectTask(StreamSocketIO* aIO)
: SocketIOTask<StreamSocketIO>(aIO)
{
MOZ_COUNT_CTOR(DelayedConnectTask);
}
~DelayedConnectTask()
{
MOZ_COUNT_DTOR(DelayedConnectTask);
}
NS_IMETHOD Run() override
{
MOZ_ASSERT(GetIO()->IsConsumerThread());
if (IsCanceled()) {
return NS_OK;
}
StreamSocketIO* io = GetIO();
if (io->IsShutdownOnConsumerThread()) {
return NS_OK;
}
io->ClearDelayedConnectTask();
io->GetIOLoop()->PostTask(MakeAndAddRef<ConnectTask>(io));
return NS_OK;
}
};
//
// StreamSocket
//
StreamSocket::StreamSocket(StreamSocketConsumer* aConsumer, int aIndex)
: mIO(nullptr)
, mConsumer(aConsumer)
, mIndex(aIndex)
{
MOZ_ASSERT(mConsumer);
MOZ_COUNT_CTOR_INHERITED(StreamSocket, ConnectionOrientedSocket);
}
StreamSocket::~StreamSocket()
{
MOZ_ASSERT(!mIO);
MOZ_COUNT_DTOR_INHERITED(StreamSocket, ConnectionOrientedSocket);
}
void
StreamSocket::ReceiveSocketData(UniquePtr<UnixSocketBuffer>& aBuffer)
{
mConsumer->ReceiveSocketData(mIndex, aBuffer);
}
nsresult
StreamSocket::Connect(UnixSocketConnector* aConnector, int aDelayMs,
MessageLoop* aConsumerLoop, MessageLoop* aIOLoop)
{
MOZ_ASSERT(!mIO);
mIO = new StreamSocketIO(aConsumerLoop, aIOLoop, this, aConnector);
SetConnectionStatus(SOCKET_CONNECTING);
if (aDelayMs > 0) {
RefPtr<StreamSocketIO::DelayedConnectTask> connectTask =
MakeAndAddRef<StreamSocketIO::DelayedConnectTask>(mIO);
mIO->SetDelayedConnectTask(connectTask);
MessageLoop::current()->PostDelayedTask(connectTask.forget(), aDelayMs);
} else {
aIOLoop->PostTask(MakeAndAddRef<StreamSocketIO::ConnectTask>(mIO));
}
return NS_OK;
}
nsresult
StreamSocket::Connect(UnixSocketConnector* aConnector, int aDelayMs)
{
return Connect(aConnector, aDelayMs,
MessageLoop::current(), XRE_GetIOMessageLoop());
}
// |ConnectionOrientedSocket|
nsresult
StreamSocket::PrepareAccept(UnixSocketConnector* aConnector,
MessageLoop* aConsumerLoop,
MessageLoop* aIOLoop,
ConnectionOrientedSocketIO*& aIO)
{
MOZ_ASSERT(!mIO);
MOZ_ASSERT(aConnector);
SetConnectionStatus(SOCKET_CONNECTING);
mIO = new StreamSocketIO(aConsumerLoop, aIOLoop,
-1, UnixSocketWatcher::SOCKET_IS_CONNECTING,
this, aConnector);
aIO = mIO;
return NS_OK;
}
// |DataSocket|
void
StreamSocket::SendSocketData(UnixSocketIOBuffer* aBuffer)
{
MOZ_ASSERT(mIO);
MOZ_ASSERT(mIO->IsConsumerThread());
MOZ_ASSERT(!mIO->IsShutdownOnConsumerThread());
mIO->GetIOLoop()->PostTask(
MakeAndAddRef<SocketIOSendTask<StreamSocketIO, UnixSocketIOBuffer>>(
mIO, aBuffer));
}
// |SocketBase|
void
StreamSocket::Close()
{
MOZ_ASSERT(mIO);
MOZ_ASSERT(mIO->IsConsumerThread());
mIO->CancelDelayedConnectTask();
// From this point on, we consider |mIO| as being deleted. We sever
// the relationship here so any future calls to |Connect| will create
// a new I/O object.
mIO->ShutdownOnConsumerThread();
mIO->GetIOLoop()->PostTask(MakeAndAddRef<SocketIOShutdownTask>(mIO));
mIO = nullptr;
NotifyDisconnect();
}
void
StreamSocket::OnConnectSuccess()
{
mConsumer->OnConnectSuccess(mIndex);
}
void
StreamSocket::OnConnectError()
{
mConsumer->OnConnectError(mIndex);
}
void
StreamSocket::OnDisconnect()
{
mConsumer->OnDisconnect(mIndex);
}
} // namespace ipc
} // namespace mozilla

View file

@ -1,95 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_ipc_streamsocket_h
#define mozilla_ipc_streamsocket_h
#include "ConnectionOrientedSocket.h"
class MessageLoop;
namespace mozilla {
namespace ipc {
class StreamSocketConsumer;
class StreamSocketIO;
class UnixSocketConnector;
class StreamSocket final : public ConnectionOrientedSocket
{
public:
/**
* Constructs an instance of |StreamSocket|.
*
* @param aConsumer The consumer for the socket.
* @param aIndex An arbitrary index.
*/
StreamSocket(StreamSocketConsumer* aConsumer, int aIndex);
/**
* Method to be called whenever data is received. Consumer-thread only.
*
* @param aBuffer Data received from the socket.
*/
void ReceiveSocketData(UniquePtr<UnixSocketBuffer>& aBuffer);
/**
* Starts a task on the socket that will try to connect to a socket in a
* non-blocking manner.
*
* @param aConnector Connector object for socket type specific functions
* @param aDelayMs Time delay in milliseconds.
* @param aConsumerLoop The socket's consumer thread.
* @param aIOLoop The socket's I/O thread.
* @return NS_OK on success, or an XPCOM error code otherwise.
*/
nsresult Connect(UnixSocketConnector* aConnector, int aDelayMs,
MessageLoop* aConsumerLoop, MessageLoop* aIOLoop);
/**
* Starts a task on the socket that will try to connect to a socket in a
* non-blocking manner.
*
* @param aConnector Connector object for socket type specific functions
* @param aDelayMs Time delay in milliseconds.
* @return NS_OK on success, or an XPCOM error code otherwise.
*/
nsresult Connect(UnixSocketConnector* aConnector, int aDelayMs = 0);
// 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;
protected:
virtual ~StreamSocket();
private:
StreamSocketIO* mIO;
StreamSocketConsumer* mConsumer;
int mIndex;
};
} // namespace ipc
} // namepsace mozilla
#endif // mozilla_ipc_streamsocket_h

View file

@ -1,20 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "StreamSocketConsumer.h"
namespace mozilla {
namespace ipc {
//
// StreamSocketConsumer
//
StreamSocketConsumer::~StreamSocketConsumer()
{ }
}
}

View file

@ -1,60 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_ipc_streamsocketconsumer_h
#define mozilla_ipc_streamsocketconsumer_h
#include "mozilla/UniquePtr.h"
namespace mozilla {
namespace ipc {
class UnixSocketBuffer;
/**
* |StreamSocketConsumer| handles socket events and received data.
*/
class StreamSocketConsumer
{
public:
/**
* Method to be called whenever data is received. Consumer-thread only.
*
* @param aIndex The index that has been given to the stream socket.
* @param aBuffer Data received from the socket.
*/
virtual void ReceiveSocketData(int aIndex,
UniquePtr<UnixSocketBuffer>& aBuffer) = 0;
/**
* 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:
virtual ~StreamSocketConsumer();
};
}
}
#endif

View file

@ -1,38 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "UnixSocketConnector.h"
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, MOZ_COUNT_DTOR
namespace mozilla {
namespace ipc {
UnixSocketConnector::UnixSocketConnector()
{
MOZ_COUNT_CTOR(UnixSocketConnector);
}
UnixSocketConnector::~UnixSocketConnector()
{
MOZ_COUNT_DTOR(UnixSocketConnector);
}
nsresult
UnixSocketConnector::Duplicate(UniquePtr<UnixSocketConnector>& aConnector)
{
UnixSocketConnector* connectorPtr;
auto rv = Duplicate(connectorPtr);
if (NS_FAILED(rv)) {
return rv;
}
aConnector = Move(UniquePtr<UnixSocketConnector>(connectorPtr));
return NS_OK;
}
}
}

View file

@ -1,102 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_ipc_unixsocketconnector_h
#define mozilla_ipc_unixsocketconnector_h
#include <sys/socket.h>
#include "mozilla/ipc/UnixSocketWatcher.h"
#include "nsString.h"
namespace mozilla {
namespace ipc {
/**
* |UnixSocketConnector| defines the socket creation and connection/listening
* functions for |UnixSocketConsumer|, et al. Due to the fact that socket setup
* can vary between protocols (Unix sockets, TCP sockets, Bluetooth sockets, etc),
* this allows the user to create whatever connection mechanism they need while
* still depending on libevent for non-blocking communication handling.
*/
class UnixSocketConnector
{
public:
virtual ~UnixSocketConnector();
/**
* Converts an address to a human-readable string.
*
* @param aAddress A socket address
* @param aAddressLength The number of valid bytes in |aAddress|
* @param[out] aAddressString The resulting string
* @return NS_OK on success, or an XPCOM error code otherwise.
*/
virtual nsresult ConvertAddressToString(const struct sockaddr& aAddress,
socklen_t aAddressLength,
nsACString& aAddressString) = 0;
/**
* Creates a listening socket. I/O thread only.
*
* @param[out] aAddress The listening socket's address
* @param[out] aAddressLength The number of valid bytes in |aAddress|
* @param[out] aListenFd The socket's file descriptor
* @return NS_OK on success, or an XPCOM error code otherwise.
*/
virtual nsresult CreateListenSocket(struct sockaddr* aAddress,
socklen_t* aAddressLength,
int& aListenFd) = 0;
/**
* Accepts a stream socket from a listening socket. I/O thread only.
*
* @param aListenFd The listening socket
* @param[out] aAddress Returns the stream socket's address
* @param[out] aAddressLength Returns the number of valid bytes in |aAddress|
* @param[out] aStreamFd The stream socket's file descriptor
* @return NS_OK on success, or an XPCOM error code otherwise.
*/
virtual nsresult AcceptStreamSocket(int aListenFd,
struct sockaddr* aAddress,
socklen_t* aAddressLen,
int& aStreamFd) = 0;
/**
* Creates a stream socket. I/O thread only.
*
* @param[in|out] aAddress The stream socket's address
* @param[in|out] aAddressLength The number of valid bytes in |aAddress|
* @param[out] aStreamFd The socket's file descriptor
* @return NS_OK on success, or an XPCOM error code otherwise.
*/
virtual nsresult CreateStreamSocket(struct sockaddr* aAddress,
socklen_t* aAddressLength,
int& aStreamFd) = 0;
/**
* Copies the instance of |UnixSocketConnector|. I/O thread only.
*
* @param[in] aConnector Returns a new instance of the connector class
* @return NS_OK on success, or an XPCOM error code otherwise
*/
virtual nsresult Duplicate(UnixSocketConnector*& aConnector) = 0;
/**
* Copies the instance of |UnixSocketConnector|. I/O thread only.
*
* @param[in] aConnector Returns a new instance of the connector class
* @return NS_OK on success, or an XPCOM error code otherwise
*/
nsresult Duplicate(UniquePtr<UnixSocketConnector>& aConnector);
protected:
UnixSocketConnector();
};
}
}
#endif

View file

@ -1,31 +0,0 @@
# -*- 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 += [
'ConnectionOrientedSocket.h',
'DataSocket.h',
'ListenSocket.h',
'ListenSocketConsumer.h',
'SocketBase.h',
'StreamSocket.h',
'StreamSocketConsumer.h',
'UnixSocketConnector.h'
]
SOURCES += [
'ConnectionOrientedSocket.cpp',
'DataSocket.cpp',
'ListenSocket.cpp',
'ListenSocketConsumer.cpp',
'SocketBase.cpp',
'StreamSocket.cpp',
'StreamSocketConsumer.cpp',
'UnixSocketConnector.cpp'
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'