mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-29 20:07:30 +09:00
parent
5830ff1f2b
commit
74df182488
232 changed files with 256 additions and 36730 deletions
|
|
@ -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']
|
||||
|
||||
|
|
|
|||
|
|
@ -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']:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
{ }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
|
@ -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'
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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'
|
||||
|
|
@ -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']
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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__
|
||||
|
|
@ -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'
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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'
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
{ }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
{ }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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'
|
||||
Loading…
Add table
Add a link
Reference in a new issue