Bug 1109338: Part 2: Sharing UDPSocket between PNecko and PBackground r=bent

This commit is contained in:
Randell Jesup 2015-05-29 10:14:14 -04:00
Родитель 859e49874b
Коммит 556337fa7c
14 изменённых файлов: 299 добавлений и 23 удалений

Просмотреть файл

@ -6,6 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PNecko;
include protocol PBackground;
include protocol PBlob;
include InputStreamParams;
@ -37,7 +38,7 @@ namespace net {
//-------------------------------------------------------------------
protocol PUDPSocket
{
manager PNecko;
manager PNecko or PBackground;
parent:
Bind(UDPAddressInfo addressInfo, bool addressReuse, bool loopback);

Просмотреть файл

@ -9,6 +9,11 @@
#include "mozilla/ipc/InputStreamUtils.h"
#include "mozilla/net/NeckoChild.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "mozilla/ipc/BackgroundUtils.h"
#include "mozilla/ipc/PBackgroundSharedTypes.h"
#include "nsIIPCBackgroundChildCreateCallback.h"
using mozilla::net::gNeckoChild;
@ -63,7 +68,8 @@ NS_IMETHODIMP_(MozExternalRefCountType) UDPSocketChild::Release(void)
}
UDPSocketChild::UDPSocketChild()
:mLocalPort(0)
:mBackgroundManager(nullptr)
,mLocalPort(0)
{
}
@ -71,8 +77,96 @@ UDPSocketChild::~UDPSocketChild()
{
}
class UDPSocketBackgroundChildCallback final :
public nsIIPCBackgroundChildCreateCallback
{
bool* mDone;
public:
explicit UDPSocketBackgroundChildCallback(bool* aDone)
: mDone(aDone)
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(mDone);
MOZ_ASSERT(!*mDone);
}
NS_DECL_ISUPPORTS
private:
~UDPSocketBackgroundChildCallback()
{ }
virtual void
ActorCreated(PBackgroundChild* aActor) override
{
*mDone = true;
}
virtual void
ActorFailed() override
{
*mDone = true;
}
};
NS_IMPL_ISUPPORTS(UDPSocketBackgroundChildCallback, nsIIPCBackgroundChildCreateCallback)
nsresult
UDPSocketChild::CreatePBackgroundSpinUntilDone()
{
using mozilla::ipc::BackgroundChild;
// Spinning the event loop in MainThread would be dangerous
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!BackgroundChild::GetForCurrentThread());
bool done = false;
nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback =
new UDPSocketBackgroundChildCallback(&done);
if (NS_WARN_IF(!BackgroundChild::GetOrCreateForCurrentThread(callback))) {
return NS_ERROR_FAILURE;
}
nsIThread* thread = NS_GetCurrentThread();
while (!done) {
if (NS_WARN_IF(!NS_ProcessNextEvent(thread, true /* aMayWait */))) {
return NS_ERROR_FAILURE;
}
}
if (NS_WARN_IF(!BackgroundChild::GetForCurrentThread())) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
// nsIUDPSocketChild Methods
NS_IMETHODIMP
UDPSocketChild::SetBackgroundSpinsEvents()
{
using mozilla::ipc::BackgroundChild;
PBackgroundChild* existingBackgroundChild =
BackgroundChild::GetForCurrentThread();
// If it's not spun up yet, block until it is, and retry
if (!existingBackgroundChild) {
nsresult rv = CreatePBackgroundSpinUntilDone();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
existingBackgroundChild =
BackgroundChild::GetForCurrentThread();
MOZ_ASSERT(existingBackgroundChild);
}
// By now PBackground is guaranteed to be/have-been up
mBackgroundManager = existingBackgroundChild;
return NS_OK;
}
NS_IMETHODIMP
UDPSocketChild::Bind(nsIUDPSocketInternal* aSocket,
nsIPrincipal* aPrincipal,
@ -88,8 +182,15 @@ UDPSocketChild::Bind(nsIUDPSocketInternal* aSocket,
mSocket = aSocket;
AddIPDLReference();
gNeckoChild->SendPUDPSocketConstructor(this, IPC::Principal(aPrincipal),
mFilterName);
if (mBackgroundManager) {
// If we want to support a passed-in principal here we'd need to
// convert it to a PrincipalInfo
MOZ_ASSERT(!aPrincipal);
mBackgroundManager->SendPUDPSocketConstructor(this, void_t(), mFilterName);
} else {
gNeckoChild->SendPUDPSocketConstructor(this, IPC::Principal(aPrincipal),
mFilterName);
}
SendBind(UDPAddressInfo(nsCString(aHost), aPort), aAddressReuse, aLoopback);
return NS_OK;

Просмотреть файл

@ -42,6 +42,8 @@ public:
UDPSocketChild();
virtual ~UDPSocketChild();
nsresult CreatePBackgroundSpinUntilDone();
virtual bool RecvCallbackOpened(const UDPAddressInfo& aAddressInfo) override;
virtual bool RecvCallbackClosed() override;
virtual bool RecvCallbackReceivedData(const UDPAddressInfo& aAddressInfo,
@ -55,6 +57,7 @@ private:
const uint8_t* aData,
const uint32_t aByteLength);
mozilla::ipc::PBackgroundChild* mBackgroundManager;
uint16_t mLocalPort;
nsCString mLocalAddress;
nsCString mFilterName;

Просмотреть файл

@ -20,6 +20,7 @@
#include "mozilla/dom/TabParent.h"
#include "nsIPermissionManager.h"
#include "nsIScriptSecurityManager.h"
#include "mozilla/ipc/PBackgroundParent.h"
#if defined(PR_LOGGING)
//
@ -35,8 +36,18 @@ namespace dom {
NS_IMPL_ISUPPORTS(UDPSocketParent, nsIUDPSocketListener)
UDPSocketParent::UDPSocketParent()
: mIPCOpen(true)
UDPSocketParent::UDPSocketParent(PBackgroundParent* aManager)
: mBackgroundManager(aManager)
, mNeckoManager(nullptr)
, mIPCOpen(true)
{
mObserver = new mozilla::net::OfflineObserver(this);
}
UDPSocketParent::UDPSocketParent(PNeckoParent* aManager)
: mBackgroundManager(nullptr)
, mNeckoManager(aManager)
, mIPCOpen(true)
{
mObserver = new mozilla::net::OfflineObserver(this);
}
@ -87,12 +98,22 @@ bool
UDPSocketParent::Init(const IPC::Principal& aPrincipal,
const nsACString& aFilter)
{
MOZ_ASSERT_IF(mBackgroundManager, !aPrincipal);
// will be used once we move all UDPSocket to PBackground, or
// if we add in Principal checking for mtransport
unused << mBackgroundManager;
mPrincipal = aPrincipal;
if (net::UsingNeckoIPCSecurity() &&
mPrincipal &&
!ContentParent::IgnoreIPCPrincipal()) {
if (!AssertAppPrincipal(Manager()->Manager(), mPrincipal)) {
return false;
if (mNeckoManager) {
if (!AssertAppPrincipal(mNeckoManager->Manager(), mPrincipal)) {
return false;
}
} else {
// PBackground is (for now) using a STUN filter for verification
// it's not being used for DoS
}
nsCOMPtr<nsIPermissionManager> permMgr =
@ -130,7 +151,7 @@ UDPSocketParent::Init(const IPC::Principal& aPrincipal,
}
// We don't have browser actors in xpcshell, and hence can't run automated
// tests without this loophole.
if (net::UsingNeckoIPCSecurity() && !mFilter &&
if (net::UsingNeckoIPCSecurity() && !mFilter &&
(!mPrincipal || ContentParent::IgnoreIPCPrincipal())) {
return false;
}

Просмотреть файл

@ -15,6 +15,10 @@
#include "mozilla/dom/PermissionMessageUtils.h"
namespace mozilla {
namespace net {
class PNeckoParent;
}
namespace dom {
class UDPSocketParent : public mozilla::net::PUDPSocketParent
@ -25,7 +29,8 @@ public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIUDPSOCKETLISTENER
UDPSocketParent();
explicit UDPSocketParent(PBackgroundParent* aManager);
explicit UDPSocketParent(PNeckoParent* aManager);
bool Init(const IPC::Principal& aPrincipal, const nsACString& aFilter);
@ -54,6 +59,10 @@ private:
void FireInternalError(uint32_t aLineNo);
// One of these will be null and the other non-null.
PBackgroundParent* mBackgroundManager;
PNeckoParent* mNeckoManager;
bool mIPCOpen;
nsCOMPtr<nsIUDPSocket> mSocket;
nsCOMPtr<nsIUDPSocketFilter> mFilter;

Просмотреть файл

@ -19,13 +19,16 @@ union NetAddr;
native NetAddr(mozilla::net::NetAddr);
[ptr] native NetAddrPtr(mozilla::net::NetAddr);
[scriptable, uuid(dd636fc5-05a0-401c-832f-2c07f3477c60)]
[scriptable, uuid(481f15ce-224a-40b6-9927-7effbc326776)]
interface nsIUDPSocketChild : nsISupports
{
readonly attribute unsigned short localPort;
readonly attribute AUTF8String localAddress;
attribute AUTF8String filterName;
// Allow hosting this over PBackground instead of PNecko
[noscript] void setBackgroundSpinsEvents();
// Tell the chrome process to bind the UDP socket to a given local host and port
void bind(in nsIUDPSocketInternal socket, in nsIPrincipal principal,
in AUTF8String host, in unsigned short port,

Просмотреть файл

@ -15,6 +15,8 @@
#include "mozilla/dom/ipc/BlobChild.h"
#include "mozilla/ipc/PBackgroundTestChild.h"
#include "mozilla/layout/VsyncChild.h"
#include "mozilla/net/PUDPSocketChild.h"
#include "mozilla/dom/network/UDPSocketChild.h"
#include "nsID.h"
#include "nsTraceRefcnt.h"
@ -48,6 +50,9 @@ public:
namespace mozilla {
namespace ipc {
using mozilla::dom::UDPSocketChild;
using mozilla::net::PUDPSocketChild;
using mozilla::dom::cache::PCacheChild;
using mozilla::dom::cache::PCacheStorageChild;
using mozilla::dom::cache::PCacheStreamControlChild;
@ -213,6 +218,23 @@ BackgroundChildImpl::DeallocPVsyncChild(PVsyncChild* aActor)
return true;
}
PUDPSocketChild*
BackgroundChildImpl::AllocPUDPSocketChild(const OptionalPrincipalInfo& aPrincipalInfo,
const nsCString& aFilter)
{
MOZ_CRASH("AllocPUDPSocket should not be called");
return nullptr;
}
bool
BackgroundChildImpl::DeallocPUDPSocketChild(PUDPSocketChild* child)
{
UDPSocketChild* p = static_cast<UDPSocketChild*>(child);
p->ReleaseIPDLReference();
return true;
}
// -----------------------------------------------------------------------------
// BroadcastChannel API
// -----------------------------------------------------------------------------

Просмотреть файл

@ -83,6 +83,12 @@ protected:
virtual bool
DeallocPVsyncChild(PVsyncChild* aActor) override;
virtual PUDPSocketChild*
AllocPUDPSocketChild(const OptionalPrincipalInfo& aPrincipalInfo,
const nsCString& aFilter) override;
virtual bool
DeallocPUDPSocketChild(PUDPSocketChild* aActor) override;
virtual PBroadcastChannelChild*
AllocPBroadcastChannelChild(const PrincipalInfo& aPrincipalInfo,
const nsString& aOrigin,

Просмотреть файл

@ -20,6 +20,7 @@
#include "mozilla/ipc/PBackgroundSharedTypes.h"
#include "mozilla/ipc/PBackgroundTestParent.h"
#include "mozilla/layout/VsyncParent.h"
#include "mozilla/dom/network/UDPSocketParent.h"
#include "nsIAppsService.h"
#include "nsNetUtil.h"
#include "nsRefPtr.h"
@ -37,6 +38,7 @@ using mozilla::ipc::AssertIsOnBackgroundThread;
using mozilla::dom::cache::PCacheParent;
using mozilla::dom::cache::PCacheStorageParent;
using mozilla::dom::cache::PCacheStreamControlParent;
using mozilla::dom::UDPSocketParent;
namespace {
@ -252,6 +254,92 @@ BackgroundParentImpl::DeallocPVsyncParent(PVsyncParent* aActor)
return true;
}
namespace {
class InitUDPSocketParentCallback final : public nsRunnable
{
public:
InitUDPSocketParentCallback(UDPSocketParent* aActor,
const nsACString& aFilter)
: mActor(aActor)
, mFilter(aFilter)
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
}
NS_IMETHODIMP
Run()
{
AssertIsInMainProcess();
IPC::Principal principal;
if (!mActor->Init(principal, mFilter)) {
MOZ_CRASH("UDPSocketCallback - failed init");
}
return NS_OK;
}
private:
~InitUDPSocketParentCallback() {};
nsRefPtr<UDPSocketParent> mActor;
nsCString mFilter;
};
}
auto
BackgroundParentImpl::AllocPUDPSocketParent(const OptionalPrincipalInfo& /* unused */,
const nsCString& /* unused */)
-> PUDPSocketParent*
{
nsRefPtr<UDPSocketParent> p = new UDPSocketParent(this);
return p.forget().take();
}
bool
BackgroundParentImpl::RecvPUDPSocketConstructor(PUDPSocketParent* aActor,
const OptionalPrincipalInfo& aOptionalPrincipal,
const nsCString& aFilter)
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
if (aOptionalPrincipal.type() == OptionalPrincipalInfo::TPrincipalInfo) {
// Support for checking principals (for non-mtransport use) will be handled in
// bug 1167039
return false;
}
// No principal - This must be from mtransport (WebRTC/ICE) - We'd want
// to DispatchToMainThread() here, but if we do we must block RecvBind()
// until Init() gets run. Since we don't have a principal, and we verify
// we have a filter, we can safely skip the Dispatch and just invoke Init()
// to install the filter.
// For mtransport, this will always be "stun", which doesn't allow outbound packets if
// they aren't STUN packets until a STUN response is seen.
if (!aFilter.EqualsASCII("stun")) {
return false;
}
IPC::Principal principal;
if (!static_cast<UDPSocketParent*>(aActor)->Init(principal, aFilter)) {
MOZ_CRASH("UDPSocketCallback - failed init");
}
return true;
}
bool
BackgroundParentImpl::DeallocPUDPSocketParent(PUDPSocketParent* actor)
{
UDPSocketParent* p = static_cast<UDPSocketParent*>(actor);
p->Release();
return true;
}
mozilla::dom::PBroadcastChannelParent*
BackgroundParentImpl::AllocPBroadcastChannelParent(
const PrincipalInfo& aPrincipalInfo,
@ -482,8 +570,10 @@ public:
}
AssertIsOnBackgroundThread();
mCallback->Run();
mCallback = nullptr;
if (mCallback) {
mCallback->Run();
mCallback = nullptr;
}
return NS_OK;
}

Просмотреть файл

@ -119,7 +119,18 @@ protected:
AllocPCacheStreamControlParent() override;
virtual bool
DeallocPCacheStreamControlParent(dom::cache::PCacheStreamControlParent* aActor) override;
DeallocPCacheStreamControlParent(dom::cache::PCacheStreamControlParent* aActor)
override;
virtual PUDPSocketParent*
AllocPUDPSocketParent(const OptionalPrincipalInfo& pInfo,
const nsCString& aFilter) override;
virtual bool
RecvPUDPSocketConstructor(PUDPSocketParent*,
const OptionalPrincipalInfo& aPrincipalInfo,
const nsCString& aFilter) override;
virtual bool
DeallocPUDPSocketParent(PUDPSocketParent*) override;
};
} // namespace ipc

Просмотреть файл

@ -10,8 +10,9 @@ include protocol PCache;
include protocol PCacheStorage;
include protocol PCacheStreamControl;
include protocol PFileDescriptorSet;
include protocol PVsync;
include protocol PMedia;
include protocol PUDPSocket;
include protocol PVsync;
include DOMTypes;
include PBackgroundSharedTypes;
@ -34,8 +35,9 @@ sync protocol PBackground
manages PCacheStorage;
manages PCacheStreamControl;
manages PFileDescriptorSet;
manages PVsync;
manages PMedia;
manages PUDPSocket;
manages PVsync;
parent:
// Only called at startup during mochitests to check the basic infrastructure.
@ -46,6 +48,7 @@ parent:
PVsync();
PMedia();
PUDPSocket(OptionalPrincipalInfo pInfo, nsCString filter);
PBroadcastChannel(PrincipalInfo pInfo, nsString origin, nsString channel,
bool privateBrowsing);

Просмотреть файл

@ -1172,19 +1172,24 @@ int NrSocketIpc::read(void* buf, size_t maxlen, size_t *len) {
void NrSocketIpc::create_i(const nsACString &host, const uint16_t port) {
ASSERT_ON_THREAD(io_thread_);
ReentrantMonitorAutoEnter mon(monitor_);
nsresult rv;
nsCOMPtr<nsIUDPSocketChild> socketChild = do_CreateInstance("@mozilla.org/udp-socket-child;1", &rv);
if (NS_FAILED(rv)) {
err_ = true;
MOZ_ASSERT(false, "Failed to create UDPSocketChild");
mon.NotifyAll();
return;
}
socket_child_ = socketChild;
socket_child_->SetFilterName(nsCString("stun"));
// This can spin the event loop; don't do that with the monitor held
socketChild->SetBackgroundSpinsEvents();
ReentrantMonitorAutoEnter mon(monitor_);
if (!socket_child_) {
socket_child_ = socketChild;
socket_child_->SetFilterName(nsCString("stun"));
} else {
socketChild = nullptr;
}
nsRefPtr<NrSocketIpcProxy> proxy(new NrSocketIpcProxy);
rv = proxy->Init(this);
@ -1194,6 +1199,7 @@ void NrSocketIpc::create_i(const nsACString &host, const uint16_t port) {
return;
}
// XXX bug 1126232 - don't use null Principal!
if (NS_FAILED(socket_child_->Bind(proxy, nullptr, host, port,
/* reuse = */ false,
/* loopback = */ false))) {
@ -1426,4 +1432,3 @@ int NR_async_cancel(NR_SOCKET sock,int how) {
nr_socket_vtbl* NrSocketBase::vtbl() {
return &nr_socket_local_vtbl;
}

Просмотреть файл

@ -86,6 +86,7 @@ class STUNUDPSocketFilter : public nsIUDPSocketFilter {
: white_list_(),
pending_requests_() {}
// Allocated/freed and used on the PBackground IPC thread
NS_DECL_ISUPPORTS
NS_DECL_NSIUDPSOCKETFILTER

Просмотреть файл

@ -483,7 +483,7 @@ PUDPSocketParent*
NeckoParent::AllocPUDPSocketParent(const Principal& /* unused */,
const nsCString& /* unused */)
{
nsRefPtr<UDPSocketParent> p = new UDPSocketParent();
nsRefPtr<UDPSocketParent> p = new UDPSocketParent(this);
return p.forget().take();
}