Bug 885982 - Part 3: Add e10s support to TCPSocket and TCPServerSocket. r=asuth,mayhemer,bz

This commit is contained in:
Josh Matthews 2015-03-25 10:36:56 -04:00
Родитель eb2db2dd0f
Коммит fbb088e702
26 изменённых файлов: 577 добавлений и 900 удалений

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

@ -1313,6 +1313,10 @@ DOMInterfaces = {
'wrapperCache': False
},
'TCPSocket': {
'implicitJSContext': ['send']
},
'ThreadSafeChromeUtils': {
# The codegen is dumb, and doesn't understand that this interface is only a
# collection of static methods, so we have this `concrete: False` hack.

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

@ -24,8 +24,6 @@ parent:
child:
CallbackAccept(PTCPSocket socket);
CallbackError(nsString message, nsString filename,
uint32_t lineNumber, uint32_t columnNumber);
__delete__();
};

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

@ -13,11 +13,12 @@ using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
struct TCPError {
nsString name;
nsString message;
};
union SendableData {
uint8_t[];
nsString;
nsCString;
};
union CallbackData {
@ -38,7 +39,7 @@ parent:
// Forward calling to child's open() method to parent, expect TCPOptions
// is expanded to |useSSL| (from TCPOptions.useSecureTransport) and
// |binaryType| (from TCPOption.binaryType).
Open(nsString host, uint16_t port, bool useSSL, nsString binaryType);
Open(nsString host, uint16_t port, bool useSSL, bool useArrayBuffers);
// When child's send() is called, this message requrests parent to send
// data and update it's trackingNumber.
@ -58,7 +59,7 @@ parent:
child:
// Forward events that are dispatched by parent.
Callback(nsString type, CallbackData data, nsString readyState);
Callback(nsString type, CallbackData data, uint32_t readyState);
// Update child's bufferedAmount when parent's bufferedAmount is updated.
// trackingNumber is also passed back to child to ensure the bufferedAmount

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

@ -6,6 +6,8 @@
#include "mozilla/dom/TCPServerSocketBinding.h"
#include "mozilla/dom/TCPServerSocketEvent.h"
#include "mozilla/dom/TCPSocketBinding.h"
#include "TCPServerSocketParent.h"
#include "TCPServerSocketChild.h"
#include "mozilla/dom/Event.h"
#include "mozilla/ErrorResult.h"
#include "TCPServerSocket.h"
@ -22,11 +24,15 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(TCPServerSocket,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServerSocket)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServerBridgeChild)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServerBridgeParent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(TCPServerSocket,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mServerSocket)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mServerBridgeChild)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mServerBridgeParent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_ADDREF_INHERITED(TCPServerSocket, DOMEventTargetHelper)
@ -52,10 +58,16 @@ TCPServerSocket::~TCPServerSocket()
nsresult
TCPServerSocket::Init()
{
if (mServerSocket) {
if (mServerSocket || mServerBridgeChild) {
NS_WARNING("Child TCPServerSocket is already listening.");
return NS_ERROR_FAILURE;
}
if (XRE_GetProcessType() == GeckoProcessType_Content) {
mServerBridgeChild = new TCPServerSocketChild(this, mPort, mBacklog, mUseArrayBuffers);
return NS_OK;
}
nsresult rv;
mServerSocket = do_CreateInstance("@mozilla.org/network/server-socket;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
@ -99,6 +111,9 @@ TCPServerSocket::LocalPort()
void
TCPServerSocket::Close()
{
if (mServerBridgeChild) {
mServerBridgeChild->Close();
}
if (mServerSocket) {
mServerSocket->Close();
}
@ -120,14 +135,21 @@ TCPServerSocket::FireEvent(const nsAString& aType, TCPSocket* aSocket)
event->SetTrusted(true);
bool dummy;
DispatchEvent(event, &dummy);
if (mServerBridgeParent) {
mServerBridgeParent->OnConnect(event);
}
}
NS_IMETHODIMP
TCPServerSocket::OnSocketAccepted(nsIServerSocket* aServer, nsISocketTransport* aTransport)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
nsRefPtr<TCPSocket> socket = TCPSocket::CreateAcceptedSocket(global, aTransport, mUseArrayBuffers);
if (mServerBridgeParent) {
socket->SetAppIdAndBrowser(mServerBridgeParent->GetAppId(),
mServerBridgeParent->GetInBrowser());
}
FireEvent(NS_LITERAL_STRING("connect"), socket);
return NS_OK;
}
@ -150,6 +172,23 @@ TCPServerSocket::OnStopListening(nsIServerSocket* aServer, nsresult aStatus)
return NS_OK;
}
nsresult
TCPServerSocket::AcceptChildSocket(TCPSocketChild* aSocketChild)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
nsRefPtr<TCPSocket> socket = TCPSocket::CreateAcceptedSocket(global, aSocketChild, mUseArrayBuffers);
NS_ENSURE_TRUE(socket, NS_ERROR_FAILURE);
FireEvent(NS_LITERAL_STRING("connect"), socket);
return NS_OK;
}
void
TCPServerSocket::SetServerBridgeParent(TCPServerSocketParent* aBridgeParent)
{
mServerBridgeParent = aBridgeParent;
}
JSObject*
TCPServerSocket::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{

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

@ -16,6 +16,9 @@ namespace dom {
struct ServerSocketOptions;
class GlobalObject;
class TCPSocket;
class TCPSocketChild;
class TCPServerSocketChild;
class TCPServerSocketParent;
class TCPServerSocket final : public DOMEventTargetHelper
, public nsIServerSocketListener
@ -35,6 +38,8 @@ public:
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
nsresult Init();
uint16_t LocalPort();
void Close();
@ -48,14 +53,24 @@ public:
IMPL_EVENT_HANDLER(connect);
IMPL_EVENT_HANDLER(error);
// Relay an accepted socket notification from the parent process and
// initialize this object with an existing child actor for the new socket.
nsresult AcceptChildSocket(TCPSocketChild* aSocketChild);
// Associate this object with an IPC actor in the parent process to relay
// notifications to content processes.
void SetServerBridgeParent(TCPServerSocketParent* aBridgeParent);
private:
~TCPServerSocket();
nsresult Init();
// Dispatch a TCPServerSocketEvent event of a given type at this object.
void FireEvent(const nsAString& aType, TCPSocket* aSocket);
// The server socket associated with this object.
nsCOMPtr<nsIServerSocket> mServerSocket;
// The IPC actor in the content process.
nsRefPtr<TCPServerSocketChild> mServerBridgeChild;
// The IPC actor in the parent process.
nsRefPtr<TCPServerSocketParent> mServerBridgeParent;
int32_t mPort;
uint16_t mBacklog;
// True if any accepted sockets should use array buffers for received messages.

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

@ -6,6 +6,7 @@
#include "TCPServerSocketChild.h"
#include "TCPSocketChild.h"
#include "TCPServerSocket.h"
#include "mozilla/net/NeckoChild.h"
#include "mozilla/dom/PBrowserChild.h"
#include "mozilla/dom/TabChild.h"
@ -23,7 +24,6 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(TCPServerSocketChildBase)
NS_IMPL_CYCLE_COLLECTING_RELEASE(TCPServerSocketChildBase)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TCPServerSocketChildBase)
NS_INTERFACE_MAP_ENTRY(nsITCPServerSocketChild)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
@ -46,18 +46,12 @@ NS_IMETHODIMP_(MozExternalRefCountType) TCPServerSocketChild::Release(void)
return refcnt;
}
TCPServerSocketChild::TCPServerSocketChild()
{
}
NS_IMETHODIMP
TCPServerSocketChild::Listen(nsITCPServerSocketInternal* aServerSocket, uint16_t aLocalPort,
uint16_t aBacklog, const nsAString & aBinaryType, JSContext* aCx)
TCPServerSocketChild::TCPServerSocketChild(TCPServerSocket* aServerSocket, uint16_t aLocalPort,
uint16_t aBacklog, bool aUseArrayBuffers)
{
mServerSocket = aServerSocket;
AddIPDLReference();
gNeckoChild->SendPTCPServerSocketConstructor(this, aLocalPort, aBacklog, nsString(aBinaryType));
return NS_OK;
gNeckoChild->SendPTCPServerSocketConstructor(this, aLocalPort, aBacklog, aUseArrayBuffers);
}
void
@ -83,34 +77,16 @@ TCPServerSocketChild::~TCPServerSocketChild()
bool
TCPServerSocketChild::RecvCallbackAccept(PTCPSocketChild *psocket)
{
TCPSocketChild* socket = static_cast<TCPSocketChild*>(psocket);
nsresult rv = mServerSocket->CallListenerAccept(static_cast<nsITCPSocketChild*>(socket));
if (NS_FAILED(rv)) {
NS_WARNING("CallListenerAccept threw exception.");
}
nsRefPtr<TCPSocketChild> socket = static_cast<TCPSocketChild*>(psocket);
nsresult rv = mServerSocket->AcceptChildSocket(socket);
NS_ENSURE_SUCCESS(rv, true);
return true;
}
bool
TCPServerSocketChild::RecvCallbackError(const nsString& aMessage,
const nsString& aFilename,
const uint32_t& aLineNumber,
const uint32_t& aColumnNumber)
{
nsresult rv = mServerSocket->CallListenerError(aMessage, aFilename,
aLineNumber, aColumnNumber);
if (NS_FAILED(rv)) {
NS_WARNING("CallListenerError threw exception.");
}
return true;
}
NS_IMETHODIMP
void
TCPServerSocketChild::Close()
{
SendClose();
return NS_OK;
}
} // namespace dom

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

@ -4,8 +4,10 @@
* 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_dom_TCPServerSocketChild_h
#define mozilla_dom_TCPServerSocketChild_h
#include "mozilla/net/PTCPServerSocketChild.h"
#include "nsITCPServerSocketChild.h"
#include "nsCycleCollectionParticipant.h"
#include "nsCOMPtr.h"
@ -17,7 +19,9 @@ class nsITCPServerSocketInternal;
namespace mozilla {
namespace dom {
class TCPServerSocketChildBase : public nsITCPServerSocketChild {
class TCPServerSocket;
class TCPServerSocketChildBase : public nsISupports {
public:
NS_DECL_CYCLE_COLLECTION_CLASS(TCPServerSocketChildBase)
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@ -29,7 +33,7 @@ protected:
TCPServerSocketChildBase();
virtual ~TCPServerSocketChildBase();
nsCOMPtr<nsITCPServerSocketInternal> mServerSocket;
nsRefPtr<TCPServerSocket> mServerSocket;
bool mIPCOpen;
};
@ -37,18 +41,18 @@ class TCPServerSocketChild : public mozilla::net::PTCPServerSocketChild
, public TCPServerSocketChildBase
{
public:
NS_DECL_NSITCPSERVERSOCKETCHILD
NS_IMETHOD_(MozExternalRefCountType) Release() override;
TCPServerSocketChild();
TCPServerSocketChild(TCPServerSocket* aServerSocket, uint16_t aLocalPort,
uint16_t aBacklog, bool aUseArrayBuffers);
~TCPServerSocketChild();
void Close();
virtual bool RecvCallbackAccept(PTCPSocketChild *socket) override;
virtual bool RecvCallbackError(const nsString& aMessage,
const nsString& aFilename,
const uint32_t& aLineNumber,
const uint32_t& aColumnNumber) override;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_TCPServerSocketChild_h

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

@ -5,6 +5,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIScriptSecurityManager.h"
#include "TCPServerSocket.h"
#include "TCPServerSocketParent.h"
#include "nsJSUtils.h"
#include "TCPSocketParent.h"
@ -16,21 +17,11 @@
namespace mozilla {
namespace dom {
static void
FireInteralError(mozilla::net::PTCPServerSocketParent* aActor,
uint32_t aLineNo)
{
mozilla::unused <<
aActor->SendCallbackError(NS_LITERAL_STRING("Internal error"),
NS_LITERAL_STRING(__FILE__), aLineNo, 0);
}
NS_IMPL_CYCLE_COLLECTION(TCPServerSocketParent, mServerSocket, mIntermediary)
NS_IMPL_CYCLE_COLLECTION(TCPServerSocketParent, mServerSocket)
NS_IMPL_CYCLE_COLLECTING_ADDREF(TCPServerSocketParent)
NS_IMPL_CYCLE_COLLECTING_RELEASE(TCPServerSocketParent)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TCPServerSocketParent)
NS_INTERFACE_MAP_ENTRY(nsITCPServerSocketParent)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
@ -50,26 +41,25 @@ TCPServerSocketParent::AddIPDLReference()
this->AddRef();
}
bool
TCPServerSocketParent::Init(PNeckoParent* neckoParent, const uint16_t& aLocalPort,
const uint16_t& aBacklog, const nsString& aBinaryType)
TCPServerSocketParent::TCPServerSocketParent(PNeckoParent* neckoParent,
uint16_t aLocalPort,
uint16_t aBacklog,
bool aUseArrayBuffers)
: mNeckoParent(neckoParent)
, mIPCOpen(false)
{
mNeckoParent = neckoParent;
mServerSocket = new TCPServerSocket(nullptr, aLocalPort, aUseArrayBuffers, aBacklog);
mServerSocket->SetServerBridgeParent(this);
}
nsresult rv;
mIntermediary = do_CreateInstance("@mozilla.org/tcp-socket-intermediary;1", &rv);
if (NS_FAILED(rv)) {
FireInteralError(this, __LINE__);
return true;
}
TCPServerSocketParent::~TCPServerSocketParent()
{
}
rv = mIntermediary->Listen(this, aLocalPort, aBacklog, aBinaryType, GetAppId(),
GetInBrowser(), getter_AddRefs(mServerSocket));
if (NS_FAILED(rv) || !mServerSocket) {
FireInteralError(this, __LINE__);
return true;
}
return true;
void
TCPServerSocketParent::Init()
{
NS_ENSURE_SUCCESS_VOID(mServerSocket->Init());
}
uint32_t
@ -98,13 +88,10 @@ TCPServerSocketParent::GetInBrowser()
return inBrowser;
}
NS_IMETHODIMP
TCPServerSocketParent::SendCallbackAccept(nsITCPSocketParent *socket)
nsresult
TCPServerSocketParent::SendCallbackAccept(TCPSocketParent *socket)
{
TCPSocketParent* _socket = static_cast<TCPSocketParent*>(socket);
PTCPSocketParent* _psocket = static_cast<PTCPSocketParent*>(_socket);
_socket->AddIPDLReference();
socket->AddIPDLReference();
nsresult rv;
@ -123,8 +110,8 @@ TCPServerSocketParent::SendCallbackAccept(nsITCPSocketParent *socket)
}
if (mNeckoParent) {
if (mNeckoParent->SendPTCPSocketConstructor(_psocket, host, port)) {
mozilla::unused << PTCPServerSocketParent::SendCallbackAccept(_psocket);
if (mNeckoParent->SendPTCPSocketConstructor(socket, host, port)) {
mozilla::unused << PTCPServerSocketParent::SendCallbackAccept(socket);
}
else {
NS_ERROR("Sending data from PTCPSocketParent was failed.");
@ -136,18 +123,6 @@ TCPServerSocketParent::SendCallbackAccept(nsITCPSocketParent *socket)
return NS_OK;
}
NS_IMETHODIMP
TCPServerSocketParent::SendCallbackError(const nsAString& message,
const nsAString& filename,
uint32_t lineNumber,
uint32_t columnNumber)
{
mozilla::unused <<
PTCPServerSocketParent::SendCallbackError(nsString(message), nsString(filename),
lineNumber, columnNumber);
return NS_OK;
}
bool
TCPServerSocketParent::RecvClose()
{
@ -164,7 +139,6 @@ TCPServerSocketParent::ActorDestroy(ActorDestroyReason why)
mServerSocket = nullptr;
}
mNeckoParent = nullptr;
mIntermediary = nullptr;
}
bool
@ -174,5 +148,19 @@ TCPServerSocketParent::RecvRequestDelete()
return true;
}
void
TCPServerSocketParent::OnConnect(TCPServerSocketEvent* event)
{
nsRefPtr<TCPSocket> socket = event->Socket();
socket->SetAppIdAndBrowser(GetAppId(), GetInBrowser());
nsRefPtr<TCPSocketParent> socketParent = new TCPSocketParent();
socketParent->SetSocket(socket);
socket->SetSocketBridgeParent(socketParent);
SendCallbackAccept(socketParent);
}
} // namespace dom
} // namespace mozilla

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

@ -4,29 +4,32 @@
* 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_dom_TCPServerSocketParent_h
#define mozilla_dom_TCPServerSocketParent_h
#include "mozilla/net/PNeckoParent.h"
#include "mozilla/net/PTCPServerSocketParent.h"
#include "nsITCPSocketParent.h"
#include "nsITCPServerSocketParent.h"
#include "nsCycleCollectionParticipant.h"
#include "nsCOMPtr.h"
#include "nsIDOMTCPSocket.h"
namespace mozilla {
namespace dom {
class TCPServerSocket;
class TCPServerSocketEvent;
class TCPSocketParent;
class TCPServerSocketParent : public mozilla::net::PTCPServerSocketParent
, public nsITCPServerSocketParent
, public nsISupports
{
public:
NS_DECL_CYCLE_COLLECTION_CLASS(TCPServerSocketParent)
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_NSITCPSERVERSOCKETPARENT
TCPServerSocketParent() : mNeckoParent(nullptr), mIPCOpen(false) {}
TCPServerSocketParent(PNeckoParent* neckoParent, uint16_t aLocalPort,
uint16_t aBacklog, bool aUseArrayBuffers);
bool Init(PNeckoParent* neckoParent, const uint16_t& aLocalPort, const uint16_t& aBacklog,
const nsString& aBinaryType);
void Init();
virtual bool RecvClose() override;
virtual bool RecvRequestDelete() override;
@ -37,16 +40,21 @@ public:
void AddIPDLReference();
void ReleaseIPDLReference();
void OnConnect(TCPServerSocketEvent* event);
private:
~TCPServerSocketParent() {}
~TCPServerSocketParent();
nsresult SendCallbackAccept(TCPSocketParent *socket);
virtual void ActorDestroy(ActorDestroyReason why) override;
PNeckoParent* mNeckoParent;
nsCOMPtr<nsITCPSocketIntermediary> mIntermediary;
nsCOMPtr<nsIDOMTCPServerSocket> mServerSocket;
nsRefPtr<TCPServerSocket> mServerSocket;
bool mIPCOpen;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_TCPServerSocketParent_h

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

@ -6,6 +6,7 @@
#include "mozilla/ErrorResult.h"
#include "TCPSocket.h"
#include "TCPServerSocket.h"
#include "TCPSocketChild.h"
#include "mozilla/dom/DOMError.h"
#include "mozilla/dom/TCPSocketBinding.h"
#include "mozilla/dom/TCPSocketErrorEvent.h"
@ -113,6 +114,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(TCPSocket,
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMultiplexStream)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMultiplexStreamCopier)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingDataAfterStartTLS)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSocketBridgeChild)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSocketBridgeParent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(TCPSocket,
@ -126,6 +129,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(TCPSocket,
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMultiplexStream)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMultiplexStreamCopier)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingDataAfterStartTLS)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSocketBridgeChild)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSocketBridgeParent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_ADDREF_INHERITED(TCPSocket, DOMEventTargetHelper)
@ -151,7 +156,9 @@ TCPSocket::TCPSocket(nsIGlobalObject* aGlobal, const nsAString& aHost, uint16_t
, mAsyncCopierActive(false)
, mWaitingForDrain(false)
, mInnerWindowID(0)
, mBufferedAmount(0)
, mSuspendCount(0)
, mTrackingNumber(0)
, mWaitingForStartTLS(false)
#ifdef MOZ_WIDGET_GONK
, mTxBytes(0)
@ -237,6 +244,12 @@ TCPSocket::Init()
mReadyState = TCPReadyState::Connecting;
if (XRE_GetProcessType() == GeckoProcessType_Content) {
mSocketBridgeChild = new TCPSocketChild(mHost, mPort);
mSocketBridgeChild->SendOpen(this, mSsl, mUseArrayBuffers);
return NS_OK;
}
nsCOMPtr<nsISocketTransportService> sts =
do_GetService("@mozilla.org/network/socket-transport-service;1");
@ -261,6 +274,16 @@ TCPSocket::Init()
return NS_OK;
}
void
TCPSocket::InitWithSocketChild(TCPSocketChild* aSocketBridge)
{
mSocketBridgeChild = aSocketBridge;
mReadyState = TCPReadyState::Open;
mSocketBridgeChild->SetSocket(this);
mSocketBridgeChild->GetHost(mHost);
mSocketBridgeChild->GetPort(&mPort);
}
nsresult
TCPSocket::InitWithTransport(nsISocketTransport* aTransport)
{
@ -303,6 +326,11 @@ TCPSocket::UpgradeToSecure(mozilla::ErrorResult& aRv)
mSsl = true;
if (mSocketBridgeChild) {
mSocketBridgeChild->SendStartTLS();
return;
}
uint32_t count = 0;
mMultiplexStream->GetCount(&count);
if (!count) {
@ -358,6 +386,11 @@ TCPSocket::NotifyCopyComplete(nsresult aStatus)
{
mAsyncCopierActive = false;
mMultiplexStream->RemoveStream(0);
if (mSocketBridgeParent) {
mozilla::unused << mSocketBridgeParent->SendUpdateBufferedAmount(BufferedAmount(),
mTrackingNumber);
}
if (NS_FAILED(aStatus)) {
MaybeReportErrorAndCloseIfOpen(aStatus);
return;
@ -390,7 +423,9 @@ TCPSocket::NotifyCopyComplete(nsresult aStatus)
}
}
if (mWaitingForDrain) {
// If we have a connected child, we let the child decide whether
// ondrain should be dispatched.
if (mWaitingForDrain && !mSocketBridgeParent) {
mWaitingForDrain = false;
FireEvent(NS_LITERAL_STRING("drain"));
}
@ -416,6 +451,11 @@ TCPSocket::ActivateTLS()
void
TCPSocket::FireErrorEvent(const nsAString& aName, const nsAString& aType)
{
if (mSocketBridgeParent) {
mSocketBridgeParent->FireErrorEvent(aName, aType, mReadyState);
return;
}
TCPSocketErrorEventInit init;
init.mBubbles = false;
init.mCancelable = false;
@ -432,6 +472,11 @@ TCPSocket::FireErrorEvent(const nsAString& aName, const nsAString& aType)
void
TCPSocket::FireEvent(const nsAString& aType)
{
if (mSocketBridgeParent) {
mSocketBridgeParent->FireEvent(aType, mReadyState);
return;
}
AutoJSAPI api;
if (NS_WARN_IF(!api.Init(GetOwner()))) {
return;
@ -443,6 +488,8 @@ TCPSocket::FireEvent(const nsAString& aType)
void
TCPSocket::FireDataEvent(JSContext* aCx, const nsAString& aType, JS::Handle<JS::Value> aData)
{
MOZ_ASSERT(!mSocketBridgeParent);
RootedDictionary<TCPSocketEventInit> init(aCx);
init.mBubbles = false;
init.mCancelable = false;
@ -482,6 +529,9 @@ TCPSocket::Ssl()
uint64_t
TCPSocket::BufferedAmount()
{
if (mSocketBridgeChild) {
return mBufferedAmount;
}
if (mMultiplexStream) {
uint64_t available = 0;
mMultiplexStream->Available(&available);
@ -493,6 +543,10 @@ TCPSocket::BufferedAmount()
void
TCPSocket::Suspend()
{
if (mSocketBridgeChild) {
mSocketBridgeChild->SendSuspend();
return;
}
if (mInputStreamPump) {
mInputStreamPump->Suspend();
}
@ -502,6 +556,10 @@ TCPSocket::Suspend()
void
TCPSocket::Resume(mozilla::ErrorResult& aRv)
{
if (mSocketBridgeChild) {
mSocketBridgeChild->SendResume();
return;
}
if (!mSuspendCount) {
aRv.Throw(NS_ERROR_FAILURE);
return;
@ -645,6 +703,11 @@ TCPSocket::Close()
mReadyState = TCPReadyState::Closing;
if (mSocketBridgeChild) {
mSocketBridgeChild->SendClose();
return;
}
uint32_t count = 0;
mMultiplexStream->GetCount(&count);
if (!count) {
@ -653,64 +716,101 @@ TCPSocket::Close()
mSocketInputStream->Close();
}
void
TCPSocket::SendWithTrackingNumber(const nsACString& aData,
const uint32_t& aTrackingNumber,
mozilla::ErrorResult& aRv)
{
MOZ_ASSERT(mSocketBridgeParent);
mTrackingNumber = aTrackingNumber;
// The JSContext isn't necessary for string values; it's a codegen limitation.
Send(nullptr, aData, aRv);
}
bool
TCPSocket::Send(const nsACString& aData, mozilla::ErrorResult& aRv)
TCPSocket::Send(JSContext* aCx, const nsACString& aData, mozilla::ErrorResult& aRv)
{
if (mReadyState != TCPReadyState::Open) {
aRv.Throw(NS_ERROR_FAILURE);
return false;
}
nsCOMPtr<nsIInputStream> stream;
nsresult rv = NS_NewCStringInputStream(getter_AddRefs(stream), aData);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return false;
}
uint64_t byteLength;
rv = stream->Available(&byteLength);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return false;
nsCOMPtr<nsIInputStream> stream;
if (mSocketBridgeChild) {
mSocketBridgeChild->SendSend(aData, ++mTrackingNumber);
byteLength = aData.Length();
} else {
nsresult rv = NS_NewCStringInputStream(getter_AddRefs(stream), aData);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return false;
}
rv = stream->Available(&byteLength);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return false;
}
}
return Send(stream, byteLength);
}
void
TCPSocket::SendWithTrackingNumber(JSContext* aCx,
const ArrayBuffer& aData,
uint32_t aByteOffset,
const Optional<uint32_t>& aByteLength,
const uint32_t& aTrackingNumber,
mozilla::ErrorResult& aRv)
{
MOZ_ASSERT(mSocketBridgeParent);
mTrackingNumber = aTrackingNumber;
Send(aCx, aData, aByteOffset, aByteLength, aRv);
}
bool
TCPSocket::Send(const ArrayBuffer& aData,
TCPSocket::Send(JSContext* aCx,
const ArrayBuffer& aData,
uint32_t aByteOffset,
const Optional<uint32_t>& aByteLength,
mozilla::ErrorResult& aRv)
{
AutoJSAPI api;
if (!api.Init(GetOwner()) ||
mReadyState != TCPReadyState::Open) {
if (mReadyState != TCPReadyState::Open) {
aRv.Throw(NS_ERROR_FAILURE);
return false;
}
nsCOMPtr<nsIArrayBufferInputStream> stream;
aData.ComputeLengthAndData();
uint32_t byteLength = aByteLength.WasPassed() ? aByteLength.Value() : aData.Length();
JS::Rooted<JSObject*> obj(api.cx(), aData.Obj());
JSAutoCompartment ac(api.cx(), obj);
JS::Rooted<JS::Value> value(api.cx(), JS::ObjectValue(*obj));
if (mSocketBridgeChild) {
nsresult rv = mSocketBridgeChild->SendSend(aData, aByteOffset, byteLength, ++mTrackingNumber);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
return false;
}
} else {
JS::Rooted<JSObject*> obj(aCx, aData.Obj());
JSAutoCompartment ac(aCx, obj);
JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*obj));
nsCOMPtr<nsIArrayBufferInputStream> stream =
do_CreateInstance("@mozilla.org/io/arraybuffer-input-stream;1");
nsresult rv = stream->SetData(value, aByteOffset, byteLength, api.cx());
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
return false;
stream = do_CreateInstance("@mozilla.org/io/arraybuffer-input-stream;1");
nsresult rv = stream->SetData(value, aByteOffset, byteLength, aCx);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
return false;
}
}
return Send(stream, byteLength);
}
bool
TCPSocket::Send(nsIInputStream* aStream, uint32_t aByteLength)
{
bool bufferFull = BufferedAmount() + aByteLength > BUFFER_SIZE;
uint64_t newBufferedAmount = BufferedAmount() + aByteLength;
bool bufferFull = newBufferedAmount > BUFFER_SIZE;
if (bufferFull) {
// If we buffered more than some arbitrary amount of data,
// (65535 right now) we should tell the caller so they can
@ -720,6 +820,13 @@ TCPSocket::Send(nsIInputStream* aStream, uint32_t aByteLength)
mWaitingForDrain = true;
}
if (mSocketBridgeChild) {
// In the child, we just add the buffer length to our bufferedAmount and let
// the parent update our bufferedAmount when the data have been sent.
mBufferedAmount = newBufferedAmount;
return !bufferFull;
}
if (mWaitingForStartTLS) {
// When we are waiting for starttls, newStream is added to pendingData
// and will be appended to multiplexStream after tls had been set up.
@ -766,6 +873,16 @@ TCPSocket::CreateAcceptedSocket(nsIGlobalObject* aGlobal,
return socket.forget();
}
already_AddRefed<TCPSocket>
TCPSocket::CreateAcceptedSocket(nsIGlobalObject* aGlobal,
TCPSocketChild* aBridge,
bool aUseArrayBuffers)
{
nsRefPtr<TCPSocket> socket = new TCPSocket(aGlobal, EmptyString(), 0, false, aUseArrayBuffers);
socket->InitWithSocketChild(aBridge);
return socket.forget();
}
already_AddRefed<TCPSocket>
TCPSocket::Constructor(const GlobalObject& aGlobal,
const nsAString& aHost,
@ -845,11 +962,11 @@ NS_IMETHODIMP
TCPSocket::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext, nsIInputStream* aStream,
uint64_t aOffset, uint32_t aCount)
{
AutoJSAPI api;
if (!api.Init(GetOwner())) {
return NS_ERROR_FAILURE;
}
JSContext* cx = api.cx();
#ifdef MOZ_WIDGET_GONK
// Collect received amount for network statistics.
mRxBytes += aCount;
SaveNetworkStats(false);
#endif
if (mUseArrayBuffers) {
nsTArray<uint8_t> buffer;
@ -860,28 +977,46 @@ TCPSocket::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext, nsIInput
MOZ_ASSERT(actual == aCount);
buffer.SetLength(actual);
if (mSocketBridgeParent) {
mSocketBridgeParent->FireArrayBufferDataEvent(buffer, mReadyState);
return NS_OK;
}
AutoJSAPI api;
if (!api.Init(GetOwner())) {
return NS_ERROR_FAILURE;
}
JSContext* cx = api.cx();
JS::Rooted<JS::Value> value(cx);
if (!ToJSValue(cx, TypedArrayCreator<Uint8Array>(buffer), &value)) {
return NS_ERROR_FAILURE;
}
FireDataEvent(cx, NS_LITERAL_STRING("data"), value);
} else {
nsCString data;
nsresult rv = mInputStreamScriptable->ReadBytes(aCount, data);
NS_ENSURE_SUCCESS(rv, rv);
JS::Rooted<JS::Value> value(cx);
if (!ToJSValue(cx, NS_ConvertASCIItoUTF16(data), &value)) {
return NS_ERROR_FAILURE;
}
FireDataEvent(cx, NS_LITERAL_STRING("data"), value);
return NS_OK;
}
#ifdef MOZ_WIDGET_GONK
// Collect received amount for network statistics.
mRxBytes += aCount;
SaveNetworkStats(false);
#endif
nsCString data;
nsresult rv = mInputStreamScriptable->ReadBytes(aCount, data);
NS_ENSURE_SUCCESS(rv, rv);
if (mSocketBridgeParent) {
mSocketBridgeParent->FireStringDataEvent(data, mReadyState);
return NS_OK;
}
AutoJSAPI api;
if (!api.Init(GetOwner())) {
return NS_ERROR_FAILURE;
}
JSContext* cx = api.cx();
JS::Rooted<JS::Value> value(cx);
if (!ToJSValue(cx, NS_ConvertASCIItoUTF16(data), &value)) {
return NS_ERROR_FAILURE;
}
FireDataEvent(cx, NS_LITERAL_STRING("data"), value);
return NS_OK;
}
@ -909,6 +1044,43 @@ TCPSocket::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, nsresult a
return NS_OK;
}
void
TCPSocket::SetSocketBridgeParent(TCPSocketParent* aBridgeParent)
{
mSocketBridgeParent = aBridgeParent;
}
void
TCPSocket::SetAppIdAndBrowser(uint32_t aAppId, bool aInBrowser)
{
#ifdef MOZ_WIDGET_GONK
mAppId = aAppId;
mInBrowser = aInBrowser;
#endif
}
void
TCPSocket::UpdateReadyState(uint32_t aReadyState)
{
MOZ_ASSERT(mSocketBridgeChild);
mReadyState = static_cast<TCPReadyState>(aReadyState);
}
void
TCPSocket::UpdateBufferedAmount(uint32_t aBufferedAmount, uint32_t aTrackingNumber)
{
if (aTrackingNumber != mTrackingNumber) {
return;
}
mBufferedAmount = aBufferedAmount;
if (!mBufferedAmount) {
if (mWaitingForDrain) {
mWaitingForDrain = false;
FireEvent(NS_LITERAL_STRING("drain"));
}
}
}
#ifdef MOZ_WIDGET_GONK
void
TCPSocket::SaveNetworkStats(bool aEnforce)

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

@ -32,7 +32,8 @@ namespace dom {
class DOMError;
struct ServerSocketOptions;
class TCPServerSocket;
class USVStringOrArrayBuffer;
class TCPSocketChild;
class TCPSocketParent;
// This interface is only used for legacy navigator.mozTCPSocket API compatibility.
class LegacyMozTCPSocket : public nsISupports
@ -98,8 +99,9 @@ public:
void Suspend();
void Resume(ErrorResult& aRv);
void Close();
bool Send(const nsCString& aData, ErrorResult& aRv);
bool Send(const ArrayBuffer& aData,
bool Send(JSContext* aCx, const nsACString& aData, ErrorResult& aRv);
bool Send(JSContext* aCx,
const ArrayBuffer& aData,
uint32_t aByteOffset,
const Optional<uint32_t>& aByteLength,
ErrorResult& aRv);
@ -114,10 +116,30 @@ public:
const SocketOptions& aOptions,
ErrorResult& aRv);
// Perform a send operation that's asssociated with a sequence number. Used in
// IPC scenarios to track the number of bytes buffered at any given time.
void SendWithTrackingNumber(const nsACString& aData,
const uint32_t& aTrackingNumber,
ErrorResult& aRv);
void SendWithTrackingNumber(JSContext* aCx,
const ArrayBuffer& aData,
uint32_t aByteOffset,
const Optional<uint32_t>& aByteLength,
const uint32_t& aTrackingNumber,
ErrorResult& aRv);
// Create a TCPSocket object from an existing low-level socket connection.
// Used by the TCPServerSocket implementation when a new connection is accepted.
static already_AddRefed<TCPSocket>
CreateAcceptedSocket(nsIGlobalObject* aGlobal, nsISocketTransport* aTransport, bool aUseArrayBuffers);
// Create a TCPSocket object from an existing child-side IPC actor.
// Used by the TCPServerSocketChild implementation when a new connection is accepted.
static already_AddRefed<TCPSocket>
CreateAcceptedSocket(nsIGlobalObject* aGlobal, TCPSocketChild* aSocketBridge, bool aUseArrayBuffers);
// Initialize this socket's associated app and browser information.
void SetAppIdAndBrowser(uint32_t aAppId, bool aInBrowser);
// Initialize this socket's associated IPC actor in the parent process.
void SetSocketBridgeParent(TCPSocketParent* aBridgeParent);
static bool SocketEnabled();
@ -132,9 +154,23 @@ public:
// Inform this socket that a buffered send() has completed sending.
void NotifyCopyComplete(nsresult aStatus);
// Set this child socket's number of buffered bytes, based on the count from the parent
// process associated with the given sequence id.
void UpdateBufferedAmount(uint32_t aAmount, uint32_t aTrackingNumber);
// Set this child socket's ready state, based on the state in the parent process.
void UpdateReadyState(uint32_t aReadyState);
// Dispatch an "error" event at this object.
void FireErrorEvent(const nsAString& aName, const nsAString& aMessage);
// Dispatch an event of the given type at this object.
void FireEvent(const nsAString& aType);
// Dispatch a "data" event at this object.
void FireDataEvent(JSContext* aCx, const nsAString& aType, JS::Handle<JS::Value> aData);
private:
~TCPSocket();
// Initialize this socket with an existing IPC actor.
void InitWithSocketChild(TCPSocketChild* aBridge);
// Initialize this socket from an existing low-level connection.
nsresult InitWithTransport(nsISocketTransport* aTransport);
// Initialize the input/output streams for this socket object.
@ -148,12 +184,6 @@ private:
nsresult EnsureCopying();
// Enable TLS on this socket.
void ActivateTLS();
// Dispatch an "error" event at this object.
void FireErrorEvent(const nsAString& aName, const nsAString& aMessage);
// Dispatch an event of the given type at this object.
void FireEvent(const nsAString& aType);
// Dispatch a "data" event at this object.
void FireDataEvent(JSContext* aCx, const nsAString& aType, JS::Handle<JS::Value> aData);
// Dispatch an error event if necessary, then dispatch a "close" event.
nsresult MaybeReportErrorAndCloseIfOpen(nsresult status);
#ifdef MOZ_WIDGET_GONK
@ -169,6 +199,11 @@ private:
// Whether this socket is using a secure transport.
bool mSsl;
// The associated IPC actor in a child process.
nsRefPtr<TCPSocketChild> mSocketBridgeChild;
// The associated IPC actor in a parent process.
nsRefPtr<TCPSocketParent> mSocketBridgeParent;
// Raw socket streams
nsCOMPtr<nsISocketTransport> mTransport;
nsCOMPtr<nsIInputStream> mSocketInputStream;
@ -191,9 +226,17 @@ private:
// The id of the window that created this socket.
uint64_t mInnerWindowID;
// The current number of buffered bytes. Only used in content processes when IPC is enabled.
uint64_t mBufferedAmount;
// The number of times this socket has had `Suspend` called without a corresponding `Resume`.
uint32_t mSuspendCount;
// The current sequence number (ie. number of send operations) that have been processed.
// This is used in the IPC scenario by the child process to filter out outdated notifications
// about the amount of buffered data present in the parent process.
uint32_t mTrackingNumber;
// True if this socket has been upgraded to secure after the initial connection,
// but the actual upgrade is waiting for an in-progress copy operation to complete.
bool mWaitingForStartTLS;

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

@ -11,25 +11,20 @@
#include "mozilla/net/NeckoChild.h"
#include "mozilla/dom/PBrowserChild.h"
#include "mozilla/dom/TabChild.h"
#include "nsIDOMTCPSocket.h"
#include "nsJSUtils.h"
#include "TCPSocket.h"
#include "nsContentUtils.h"
#include "jsapi.h"
#include "jsfriendapi.h"
#include "jswrapper.h"
using mozilla::net::gNeckoChild;
namespace IPC {
bool
DeserializeArrayBuffer(JS::Handle<JSObject*> aObj,
DeserializeArrayBuffer(JSContext* cx,
const InfallibleTArray<uint8_t>& aBuffer,
JS::MutableHandle<JS::Value> aVal)
{
mozilla::AutoSafeJSContext cx;
JSAutoCompartment ac(cx, aObj);
mozilla::UniquePtr<uint8_t[], JS::FreePolicy> data(js_pod_malloc<uint8_t>(aBuffer.Length()));
if (!data)
return false;
@ -57,19 +52,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(TCPSocketChildBase)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(TCPSocketChildBase)
tmp->mWindowObj = nullptr;
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSocket)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(TCPSocketChildBase)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mWindowObj)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(TCPSocketChildBase)
NS_IMPL_CYCLE_COLLECTING_RELEASE(TCPSocketChildBase)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TCPSocketChildBase)
NS_INTERFACE_MAP_ENTRY(nsITCPSocketChild)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
@ -94,36 +86,20 @@ NS_IMETHODIMP_(MozExternalRefCountType) TCPSocketChild::Release(void)
return refcnt;
}
TCPSocketChild::TCPSocketChild()
: mHost()
, mPort(0)
TCPSocketChild::TCPSocketChild(const nsAString& aHost, const uint16_t& aPort)
: mHost(aHost)
, mPort(aPort)
{
}
void TCPSocketChild::Init(const nsString& aHost, const uint16_t& aPort) {
mHost = aHost;
mPort = aPort;
}
NS_IMETHODIMP
TCPSocketChild::SendOpen(nsITCPSocketInternal* aSocket,
const nsAString& aHost, uint16_t aPort,
bool aUseSSL, const nsAString& aBinaryType,
nsIDOMWindow* aWindow, JS::Handle<JS::Value> aWindowObj,
JSContext* aCx)
void
TCPSocketChild::SendOpen(TCPSocket* aSocket, bool aUseSSL, bool aUseArrayBuffers)
{
mSocket = aSocket;
MOZ_ASSERT(aWindowObj.isObject());
mWindowObj = js::CheckedUnwrap(&aWindowObj.toObject());
if (!mWindowObj) {
return NS_ERROR_FAILURE;
}
AddIPDLReference();
gNeckoChild->SendPTCPSocketConstructor(this, nsString(aHost), aPort);
PTCPSocketChild::SendOpen(nsString(aHost), aPort,
aUseSSL, nsString(aBinaryType));
return NS_OK;
gNeckoChild->SendPTCPSocketConstructor(this, mHost, mPort);
PTCPSocketChild::SendOpen(mHost, mPort, aUseSSL, aUseArrayBuffers);
}
void
@ -150,147 +126,95 @@ bool
TCPSocketChild::RecvUpdateBufferedAmount(const uint32_t& aBuffered,
const uint32_t& aTrackingNumber)
{
if (NS_FAILED(mSocket->UpdateBufferedAmount(aBuffered, aTrackingNumber))) {
NS_ERROR("Shouldn't fail!");
}
mSocket->UpdateBufferedAmount(aBuffered, aTrackingNumber);
return true;
}
bool
TCPSocketChild::RecvCallback(const nsString& aType,
const CallbackData& aData,
const nsString& aReadyState)
const uint32_t& aReadyState)
{
if (NS_FAILED(mSocket->UpdateReadyState(aReadyState)))
NS_ERROR("Shouldn't fail!");
mSocket->UpdateReadyState(aReadyState);
nsresult rv = NS_ERROR_FAILURE;
if (aData.type() == CallbackData::Tvoid_t) {
rv = mSocket->CallListenerVoid(aType);
mSocket->FireEvent(aType);
} else if (aData.type() == CallbackData::TTCPError) {
const TCPError& err(aData.get_TCPError());
rv = mSocket->CallListenerError(aType, err.name());
mSocket->FireErrorEvent(err.name(), err.message());
} else if (aData.type() == CallbackData::TSendableData) {
const SendableData& data = aData.get_SendableData();
if (data.type() == SendableData::TArrayOfuint8_t) {
JSContext* cx = nsContentUtils::GetSafeJSContext();
JSAutoRequest ar(cx);
JS::Rooted<JS::Value> val(cx);
JS::Rooted<JSObject*> window(cx, mWindowObj);
bool ok = IPC::DeserializeArrayBuffer(window, data.get_ArrayOfuint8_t(), &val);
NS_ENSURE_TRUE(ok, true);
rv = mSocket->CallListenerArrayBuffer(aType, val);
AutoJSAPI api;
if (NS_WARN_IF(!api.Init(mSocket->GetOwner()))) {
return true;
}
JSContext* cx = api.cx();
JS::Rooted<JS::Value> val(cx);
} else if (data.type() == SendableData::TnsString) {
rv = mSocket->CallListenerData(aType, data.get_nsString());
if (data.type() == SendableData::TArrayOfuint8_t) {
bool ok = IPC::DeserializeArrayBuffer(cx, data.get_ArrayOfuint8_t(), &val);
NS_ENSURE_TRUE(ok, true);
} else if (data.type() == SendableData::TnsCString) {
bool ok = ToJSValue(cx, NS_ConvertASCIItoUTF16(data.get_nsCString()), &val);
NS_ENSURE_TRUE(ok, true);
} else {
MOZ_CRASH("Invalid callback data type!");
}
mSocket->FireDataEvent(cx, aType, val);
} else {
MOZ_CRASH("Invalid callback type!");
}
NS_ENSURE_SUCCESS(rv, true);
return true;
}
NS_IMETHODIMP
TCPSocketChild::SendStartTLS()
void
TCPSocketChild::SendSend(const nsACString& aData, uint32_t aTrackingNumber)
{
PTCPSocketChild::SendStartTLS();
return NS_OK;
SendData(nsCString(aData), aTrackingNumber);
}
NS_IMETHODIMP
TCPSocketChild::SendSuspend()
{
PTCPSocketChild::SendSuspend();
return NS_OK;
}
NS_IMETHODIMP
TCPSocketChild::SendResume()
{
PTCPSocketChild::SendResume();
return NS_OK;
}
NS_IMETHODIMP
TCPSocketChild::SendClose()
{
PTCPSocketChild::SendClose();
return NS_OK;
}
NS_IMETHODIMP
TCPSocketChild::SendSend(JS::Handle<JS::Value> aData,
nsresult
TCPSocketChild::SendSend(const ArrayBuffer& aData,
uint32_t aByteOffset,
uint32_t aByteLength,
uint32_t aTrackingNumber,
JSContext* aCx)
uint32_t aTrackingNumber)
{
if (aData.isString()) {
JSString* jsstr = aData.toString();
nsAutoJSString str;
bool ok = str.init(aCx, jsstr);
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
SendData(str, aTrackingNumber);
} else {
NS_ENSURE_TRUE(aData.isObject(), NS_ERROR_FAILURE);
JS::Rooted<JSObject*> obj(aCx, &aData.toObject());
NS_ENSURE_TRUE(JS_IsArrayBufferObject(obj), NS_ERROR_FAILURE);
uint32_t buflen = JS_GetArrayBufferByteLength(obj);
aByteOffset = std::min(buflen, aByteOffset);
uint32_t nbytes = std::min(buflen - aByteOffset, aByteLength);
FallibleTArray<uint8_t> fallibleArr;
{
JS::AutoCheckCannotGC nogc;
uint8_t* data = JS_GetArrayBufferData(obj, nogc);
if (!data) {
return NS_ERROR_OUT_OF_MEMORY;
}
if (!fallibleArr.InsertElementsAt(0, data + aByteOffset, nbytes,
fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}
}
InfallibleTArray<uint8_t> arr;
arr.SwapElements(fallibleArr);
SendData(arr, aTrackingNumber);
uint32_t buflen = aData.Length();
uint32_t offset = std::min(buflen, aByteOffset);
uint32_t nbytes = std::min(buflen - aByteOffset, aByteLength);
FallibleTArray<uint8_t> fallibleArr;
if (!fallibleArr.InsertElementsAt(0, aData.Data() + offset, nbytes, fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}
InfallibleTArray<uint8_t> arr;
arr.SwapElements(fallibleArr);
SendData(arr, aTrackingNumber);
return NS_OK;
}
NS_IMETHODIMP
TCPSocketChild::SetSocketAndWindow(nsITCPSocketInternal *aSocket,
JS::Handle<JS::Value> aWindowObj,
JSContext* aCx)
void
TCPSocketChild::SetSocket(TCPSocket* aSocket)
{
mSocket = aSocket;
MOZ_ASSERT(aWindowObj.isObject());
mWindowObj = js::CheckedUnwrap(&aWindowObj.toObject());
if (!mWindowObj) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_IMETHODIMP
void
TCPSocketChild::GetHost(nsAString& aHost)
{
aHost = mHost;
return NS_OK;
}
NS_IMETHODIMP
void
TCPSocketChild::GetPort(uint16_t* aPort)
{
*aPort = mPort;
return NS_OK;
}
bool

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

@ -8,20 +8,16 @@
#define mozilla_dom_TCPSocketChild_h
#include "mozilla/net/PTCPSocketChild.h"
#include "nsITCPSocketChild.h"
#include "nsCycleCollectionParticipant.h"
#include "nsCOMPtr.h"
#include "js/TypeDecls.h"
#define TCPSOCKETCHILD_CID \
{ 0xa589d96f, 0x7e09, 0x4edf, { 0xa0, 0x1a, 0xeb, 0x49, 0x51, 0xf4, 0x2f, 0x37 } }
class nsITCPSocketInternal;
namespace mozilla {
namespace dom {
class TCPSocketChildBase : public nsITCPSocketChild {
class TCPSocket;
class TCPSocketChildBase : public nsISupports {
public:
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TCPSocketChildBase)
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@ -33,8 +29,7 @@ protected:
TCPSocketChildBase();
virtual ~TCPSocketChildBase();
nsCOMPtr<nsITCPSocketInternal> mSocket;
JS::Heap<JSObject*> mWindowObj;
nsRefPtr<TCPSocket> mSocket;
bool mIPCOpen;
};
@ -42,17 +37,25 @@ class TCPSocketChild : public mozilla::net::PTCPSocketChild
, public TCPSocketChildBase
{
public:
NS_DECL_NSITCPSOCKETCHILD
NS_IMETHOD_(MozExternalRefCountType) Release() override;
TCPSocketChild();
TCPSocketChild(const nsAString& aHost, const uint16_t& aPort);
~TCPSocketChild();
void Init(const nsString& aHost, const uint16_t& aPort);
void SendOpen(TCPSocket* aSocket, bool aUseSSL, bool aUseArrayBuffers);
void SendSend(const nsACString& aData, uint32_t aTrackingNumber);
nsresult SendSend(const ArrayBuffer& aData,
uint32_t aByteOffset,
uint32_t aByteLength,
uint32_t aTrackingNumber);
void SetSocket(TCPSocket* aSocket);
void GetHost(nsAString& aHost);
void GetPort(uint16_t* aPort);
virtual bool RecvCallback(const nsString& aType,
const CallbackData& aData,
const nsString& aReadyState) override;
const uint32_t& aReadyState) override;
virtual bool RecvRequestDelete() override;
virtual bool RecvUpdateBufferedAmount(const uint32_t& aBufferred,
const uint32_t& aTrackingNumber) override;

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

@ -24,7 +24,7 @@ namespace IPC {
//Defined in TCPSocketChild.cpp
extern bool
DeserializeArrayBuffer(JS::Handle<JSObject*> aObj,
DeserializeArrayBuffer(JSContext* aCx,
const InfallibleTArray<uint8_t>& aBuffer,
JS::MutableHandle<JS::Value> aVal);
@ -38,33 +38,15 @@ FireInteralError(mozilla::net::PTCPSocketParent* aActor, uint32_t aLineNo)
{
mozilla::unused <<
aActor->SendCallback(NS_LITERAL_STRING("onerror"),
TCPError(NS_LITERAL_STRING("InvalidStateError")),
NS_LITERAL_STRING("connecting"));
TCPError(NS_LITERAL_STRING("InvalidStateError"), NS_LITERAL_STRING("Internal error")),
static_cast<uint32_t>(TCPReadyState::Connecting));
}
NS_IMPL_CYCLE_COLLECTION_CLASS(TCPSocketParentBase)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(TCPSocketParentBase)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSocket)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIntermediary)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(TCPSocketParentBase)
tmp->mIntermediaryObj = nullptr;
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSocket)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIntermediary)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(TCPSocketParentBase)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mIntermediaryObj)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TCPSocketParentBase)
NS_INTERFACE_MAP_ENTRY(nsITCPSocketParent)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION(TCPSocketParentBase, mSocket)
NS_IMPL_CYCLE_COLLECTING_ADDREF(TCPSocketParentBase)
NS_IMPL_CYCLE_COLLECTING_RELEASE(TCPSocketParentBase)
@ -72,7 +54,6 @@ TCPSocketParentBase::TCPSocketParentBase()
: mIPCOpen(false)
{
mObserver = new mozilla::net::OfflineObserver(this);
mozilla::HoldJSObjects(this);
}
TCPSocketParentBase::~TCPSocketParentBase()
@ -80,7 +61,6 @@ TCPSocketParentBase::~TCPSocketParentBase()
if (mObserver) {
mObserver->RemoveObserver();
}
mozilla::DropJSObjects(this);
}
uint32_t
@ -130,8 +110,6 @@ TCPSocketParent::OfflineNotification(nsISupports *aSubject)
if (mSocket && NS_IsAppOffline(appId)) {
mSocket->Close();
mSocket = nullptr;
mIntermediaryObj = nullptr;
mIntermediary = nullptr;
}
return NS_OK;
@ -166,7 +144,7 @@ NS_IMETHODIMP_(MozExternalRefCountType) TCPSocketParent::Release(void)
bool
TCPSocketParent::RecvOpen(const nsString& aHost, const uint16_t& aPort, const bool& aUseSSL,
const nsString& aBinaryType)
const bool& aUseArrayBuffers)
{
// We don't have browser actors in xpcshell, and hence can't run automated
// tests without this loophole.
@ -186,37 +164,20 @@ TCPSocketParent::RecvOpen(const nsString& aHost, const uint16_t& aPort, const bo
return true;
}
nsresult rv;
mIntermediary = do_CreateInstance("@mozilla.org/tcp-socket-intermediary;1", &rv);
if (NS_FAILED(rv)) {
FireInteralError(this, __LINE__);
return true;
}
rv = mIntermediary->Open(this, aHost, aPort, aUseSSL, aBinaryType, appId,
inBrowser, getter_AddRefs(mSocket));
if (NS_FAILED(rv) || !mSocket) {
FireInteralError(this, __LINE__);
return true;
}
mSocket = new TCPSocket(nullptr, aHost, aPort, aUseSSL, aUseArrayBuffers);
mSocket->SetAppIdAndBrowser(appId, inBrowser);
mSocket->SetSocketBridgeParent(this);
NS_ENSURE_SUCCESS(mSocket->Init(), true);
return true;
}
NS_IMETHODIMP
TCPSocketParent::InitJS(JS::Handle<JS::Value> aIntermediary, JSContext* aCx)
{
MOZ_ASSERT(aIntermediary.isObject());
mIntermediaryObj = &aIntermediary.toObject();
return NS_OK;
}
bool
TCPSocketParent::RecvStartTLS()
{
NS_ENSURE_TRUE(mSocket, true);
nsresult rv = mSocket->UpgradeToSecure();
NS_ENSURE_SUCCESS(rv, true);
ErrorResult rv;
mSocket->UpgradeToSecure(rv);
NS_ENSURE_FALSE(rv.Failed(), true);
return true;
}
@ -224,8 +185,7 @@ bool
TCPSocketParent::RecvSuspend()
{
NS_ENSURE_TRUE(mSocket, true);
nsresult rv = mSocket->Suspend();
NS_ENSURE_SUCCESS(rv, true);
mSocket->Suspend();
return true;
}
@ -233,8 +193,9 @@ bool
TCPSocketParent::RecvResume()
{
NS_ENSURE_TRUE(mSocket, true);
nsresult rv = mSocket->Resume();
NS_ENSURE_SUCCESS(rv, true);
ErrorResult rv;
mSocket->Resume(rv);
NS_ENSURE_FALSE(rv.Failed(), true);
return true;
}
@ -242,29 +203,31 @@ bool
TCPSocketParent::RecvData(const SendableData& aData,
const uint32_t& aTrackingNumber)
{
NS_ENSURE_TRUE(mIntermediary, true);
nsresult rv;
ErrorResult rv;
switch (aData.type()) {
case SendableData::TArrayOfuint8_t: {
AutoSafeJSContext cx;
JSAutoRequest ar(cx);
JS::Rooted<JS::Value> val(cx);
JS::Rooted<JSObject*> obj(cx, mIntermediaryObj);
IPC::DeserializeArrayBuffer(obj, aData.get_ArrayOfuint8_t(), &val);
rv = mIntermediary->OnRecvSendArrayBuffer(val, aTrackingNumber);
NS_ENSURE_SUCCESS(rv, true);
AutoSafeJSContext autoCx;
JS::Rooted<JS::Value> val(autoCx);
const nsTArray<uint8_t>& buffer = aData.get_ArrayOfuint8_t();
bool ok = IPC::DeserializeArrayBuffer(autoCx, buffer, &val);
NS_ENSURE_TRUE(ok, true);
RootedTypedArray<ArrayBuffer> data(autoCx);
data.Init(&val.toObject());
Optional<uint32_t> byteLength(buffer.Length());
mSocket->SendWithTrackingNumber(autoCx, data, 0, byteLength, aTrackingNumber, rv);
break;
}
case SendableData::TnsString:
rv = mIntermediary->OnRecvSendString(aData.get_nsString(), aTrackingNumber);
NS_ENSURE_SUCCESS(rv, true);
case SendableData::TnsCString: {
const nsCString& strData = aData.get_nsCString();
mSocket->SendWithTrackingNumber(strData, aTrackingNumber, rv);
break;
}
default:
MOZ_CRASH("unexpected SendableData type");
}
NS_ENSURE_FALSE(rv.Failed(), true);
return true;
}
@ -272,123 +235,70 @@ bool
TCPSocketParent::RecvClose()
{
NS_ENSURE_TRUE(mSocket, true);
nsresult rv = mSocket->Close();
NS_ENSURE_SUCCESS(rv, true);
mSocket->Close();
return true;
}
NS_IMETHODIMP
TCPSocketParent::SendEvent(const nsAString& aType, JS::Handle<JS::Value> aDataVal,
const nsAString& aReadyState, JSContext* aCx)
void
TCPSocketParent::FireErrorEvent(const nsAString& aName, const nsAString& aType, TCPReadyState aReadyState)
{
if (!mIPCOpen) {
NS_WARNING("Dropping callback due to no IPC connection");
return NS_OK;
}
CallbackData data;
if (aDataVal.isString()) {
JSString* jsstr = aDataVal.toString();
nsAutoJSString str;
if (!str.init(aCx, jsstr)) {
FireInteralError(this, __LINE__);
return NS_ERROR_OUT_OF_MEMORY;
}
data = SendableData(str);
} else if (aDataVal.isUndefined() || aDataVal.isNull()) {
data = mozilla::void_t();
} else if (aDataVal.isObject()) {
JS::Rooted<JSObject *> obj(aCx, &aDataVal.toObject());
if (JS_IsArrayBufferObject(obj)) {
FallibleTArray<uint8_t> fallibleArr;
uint32_t errLine = 0;
do {
JS::AutoCheckCannotGC nogc;
uint32_t nbytes = JS_GetArrayBufferByteLength(obj);
uint8_t* buffer = JS_GetArrayBufferData(obj, nogc);
if (!buffer) {
errLine = __LINE__;
break;
}
if (!fallibleArr.InsertElementsAt(0, buffer, nbytes, fallible)) {
errLine = __LINE__;
break;
}
} while (false);
if (errLine) {
FireInteralError(this, errLine);
return NS_ERROR_OUT_OF_MEMORY;
}
InfallibleTArray<uint8_t> arr;
arr.SwapElements(fallibleArr);
data = SendableData(arr);
} else {
nsAutoJSString name;
JS::Rooted<JS::Value> val(aCx);
if (!JS_GetProperty(aCx, obj, "name", &val)) {
NS_ERROR("No name property on supposed error object");
} else if (val.isString()) {
if (!name.init(aCx, val.toString())) {
NS_WARNING("couldn't initialize string");
}
}
data = TCPError(name);
}
} else {
NS_ERROR("Unexpected JS value encountered");
FireInteralError(this, __LINE__);
return NS_ERROR_FAILURE;
}
mozilla::unused <<
PTCPSocketParent::SendCallback(nsString(aType), data,
nsString(aReadyState));
return NS_OK;
SendEvent(NS_LITERAL_STRING("error"), TCPError(nsString(aName), nsString(aType)), aReadyState);
}
NS_IMETHODIMP
TCPSocketParent::SetSocketAndIntermediary(nsIDOMTCPSocket *socket,
nsITCPSocketIntermediary *intermediary,
JSContext* cx)
void
TCPSocketParent::FireEvent(const nsAString& aType, TCPReadyState aReadyState)
{
return SendEvent(aType, mozilla::void_t(), aReadyState);
}
void
TCPSocketParent::FireArrayBufferDataEvent(nsTArray<uint8_t>& aBuffer, TCPReadyState aReadyState)
{
InfallibleTArray<uint8_t> arr;
arr.SwapElements(aBuffer);
SendableData data(arr);
SendEvent(NS_LITERAL_STRING("data"), data, aReadyState);
}
void
TCPSocketParent::FireStringDataEvent(const nsACString& aData, TCPReadyState aReadyState)
{
SendEvent(NS_LITERAL_STRING("data"), SendableData(nsCString(aData)), aReadyState);
}
void
TCPSocketParent::SendEvent(const nsAString& aType, CallbackData aData, TCPReadyState aReadyState)
{
mozilla::unused << PTCPSocketParent::SendCallback(nsString(aType), aData,
static_cast<uint32_t>(aReadyState));
}
void
TCPSocketParent::SetSocket(TCPSocket *socket)
{
mSocket = socket;
mIntermediary = intermediary;
return NS_OK;
}
NS_IMETHODIMP
TCPSocketParent::SendUpdateBufferedAmount(uint32_t aBufferedAmount,
uint32_t aTrackingNumber)
{
mozilla::unused << PTCPSocketParent::SendUpdateBufferedAmount(aBufferedAmount,
aTrackingNumber);
return NS_OK;
}
NS_IMETHODIMP
nsresult
TCPSocketParent::GetHost(nsAString& aHost)
{
if (!mSocket) {
NS_ERROR("No internal socket instance mSocket!");
return NS_ERROR_FAILURE;
}
return mSocket->GetHost(aHost);
mSocket->GetHost(aHost);
return NS_OK;
}
NS_IMETHODIMP
nsresult
TCPSocketParent::GetPort(uint16_t* aPort)
{
if (!mSocket) {
NS_ERROR("No internal socket instance mSocket!");
return NS_ERROR_FAILURE;
}
return mSocket->GetPort(aPort);
*aPort = mSocket->Port();
return NS_OK;
}
void
@ -398,8 +308,6 @@ TCPSocketParent::ActorDestroy(ActorDestroyReason why)
mSocket->Close();
}
mSocket = nullptr;
mIntermediaryObj = nullptr;
mIntermediary = nullptr;
}
bool

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

@ -7,6 +7,7 @@
#ifndef mozilla_dom_TCPSocketParent_h
#define mozilla_dom_TCPSocketParent_h
#include "mozilla/dom/TCPSocketBinding.h"
#include "mozilla/net/PTCPSocketParent.h"
#include "nsITCPSocketParent.h"
#include "nsCycleCollectionParticipant.h"
@ -21,11 +22,13 @@
namespace mozilla {
namespace dom {
class TCPSocketParentBase : public nsITCPSocketParent
class TCPSocket;
class TCPSocketParentBase : public nsISupports
, public mozilla::net::DisconnectableParent
{
public:
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TCPSocketParentBase)
NS_DECL_CYCLE_COLLECTION_CLASS(TCPSocketParentBase)
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
void AddIPDLReference();
@ -35,9 +38,7 @@ protected:
TCPSocketParentBase();
virtual ~TCPSocketParentBase();
JS::Heap<JSObject*> mIntermediaryObj;
nsCOMPtr<nsITCPSocketIntermediary> mIntermediary;
nsCOMPtr<nsIDOMTCPSocket> mSocket;
nsRefPtr<TCPSocket> mSocket;
nsRefPtr<mozilla::net::OfflineObserver> mObserver;
bool mIPCOpen;
};
@ -46,13 +47,12 @@ class TCPSocketParent : public mozilla::net::PTCPSocketParent
, public TCPSocketParentBase
{
public:
NS_DECL_NSITCPSOCKETPARENT
NS_IMETHOD_(MozExternalRefCountType) Release() override;
TCPSocketParent() {}
virtual bool RecvOpen(const nsString& aHost, const uint16_t& aPort,
const bool& useSSL, const nsString& aBinaryType) override;
const bool& useSSL, const bool& aUseArrayBuffers) override;
virtual bool RecvStartTLS() override;
virtual bool RecvSuspend() override;
@ -65,8 +65,18 @@ public:
virtual uint32_t GetAppId() override;
bool GetInBrowser();
void FireErrorEvent(const nsAString& aName, const nsAString& aType, TCPReadyState aReadyState);
void FireEvent(const nsAString& aType, TCPReadyState aReadyState);
void FireArrayBufferDataEvent(nsTArray<uint8_t>& aBuffer, TCPReadyState aReadyState);
void FireStringDataEvent(const nsACString& aData, TCPReadyState aReadyState);
void SetSocket(TCPSocket *socket);
nsresult GetHost(nsAString& aHost);
nsresult GetPort(uint16_t* aPort);
private:
virtual void ActorDestroy(ActorDestroyReason why) override;
void SendEvent(const nsAString& aType, CallbackData aData, TCPReadyState aReadyState);
};
} // namespace dom

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

@ -6,11 +6,6 @@
DIRS += ['interfaces']
XPCSHELL_TESTS_MANIFESTS += [
'tests/unit/xpcshell.ini',
'tests/unit_ipc/xpcshell.ini',
]
if CONFIG['MOZ_B2G_RIL']:
XPCSHELL_TESTS_MANIFESTS += ['tests/unit_stats/xpcshell.ini']

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

@ -1,371 +0,0 @@
/**
* Test TCPSocket.js by creating an XPCOM-style server socket, then sending
* data in both directions and making sure each side receives their data
* correctly and with the proper events.
*
* This test is derived from netwerk/test/unit/test_socks.js, except we don't
* involve a subprocess.
*
* Future work:
* - SSL. see https://bugzilla.mozilla.org/show_bug.cgi?id=466524
* https://bugzilla.mozilla.org/show_bug.cgi?id=662180
* Alternatively, mochitests could be used.
* - Testing overflow logic.
*
**/
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;
const CC = Components.Constructor;
/**
*
* Constants
*
*/
// Some binary data to send.
const DATA_ARRAY = [0, 255, 254, 0, 1, 2, 3, 0, 255, 255, 254, 0],
DATA_ARRAY_BUFFER = new ArrayBuffer(DATA_ARRAY.length),
TYPED_DATA_ARRAY = new Uint8Array(DATA_ARRAY_BUFFER),
HELLO_WORLD = "hlo wrld. ",
BIG_ARRAY = new Array(65539),
BIG_ARRAY_2 = new Array(65539);
TYPED_DATA_ARRAY.set(DATA_ARRAY, 0);
for (var i_big = 0; i_big < BIG_ARRAY.length; i_big++) {
BIG_ARRAY[i_big] = Math.floor(Math.random() * 256);
BIG_ARRAY_2[i_big] = Math.floor(Math.random() * 256);
}
const BIG_ARRAY_BUFFER = new ArrayBuffer(BIG_ARRAY.length),
BIG_ARRAY_BUFFER_2 = new ArrayBuffer(BIG_ARRAY_2.length);
const BIG_TYPED_ARRAY = new Uint8Array(BIG_ARRAY_BUFFER),
BIG_TYPED_ARRAY_2 = new Uint8Array(BIG_ARRAY_BUFFER_2);
BIG_TYPED_ARRAY.set(BIG_ARRAY);
BIG_TYPED_ARRAY_2.set(BIG_ARRAY_2);
const ServerSocket = CC("@mozilla.org/network/server-socket;1",
"nsIServerSocket",
"init"),
InputStreamPump = CC("@mozilla.org/network/input-stream-pump;1",
"nsIInputStreamPump",
"init"),
BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
"nsIBinaryInputStream",
"setInputStream"),
BinaryOutputStream = CC("@mozilla.org/binaryoutputstream;1",
"nsIBinaryOutputStream",
"setOutputStream"),
TCPSocket = new (CC("@mozilla.org/tcp-socket;1",
"nsIDOMTCPSocket"))();
const gInChild = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
Cu.import("resource://gre/modules/Services.jsm");
/**
*
* Helper functions
*
*/
function is_content() {
return this._inChild = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
}
/**
* Spin up a listening socket and associate at most one live, accepted socket
* with ourselves.
*/
function TestServer() {
this.listener = ServerSocket(-1, true, -1);
do_print('server: listening on ' + this.listener.port);
this.listener.asyncListen(this);
this.binaryInput = null;
this.input = null;
this.binaryOutput = null;
this.output = null;
this.onconnect = null;
this.ondata = null;
this.onclose = null;
}
TestServer.prototype = {
onSocketAccepted: function(socket, trans) {
if (this.input)
do_throw("More than one live connection!?");
do_print('server: got client connection');
this.input = trans.openInputStream(0, 0, 0);
this.binaryInput = new BinaryInputStream(this.input);
this.output = trans.openOutputStream(0, 0, 0);
this.binaryOutput = new BinaryOutputStream(this.output);
new InputStreamPump(this.input, -1, -1, 0, 0, false).asyncRead(this, null);
if (this.onconnect)
this.onconnect();
else
do_throw("Received unexpected connection!");
},
onStopListening: function(socket) {
},
onDataAvailable: function(request, context, inputStream, offset, count) {
var readData = this.binaryInput.readByteArray(count);
if (this.ondata) {
try {
this.ondata(readData);
} catch(ex) {
// re-throw if this is from do_throw
if (ex === Cr.NS_ERROR_ABORT)
throw ex;
// log if there was a test problem
do_print('Caught exception: ' + ex + '\n' + ex.stack);
do_throw('test is broken; bad ondata handler; see above');
}
} else {
do_throw('Received ' + count + ' bytes of unexpected data!');
}
},
onStartRequest: function(request, context) {
},
onStopRequest: function(request, context, status) {
if (this.onclose)
this.onclose();
else
do_throw("Received unexpected close!");
},
close: function() {
this.binaryInput.close();
this.binaryOutput.close();
},
/**
* Forget about the socket we knew about before.
*/
reset: function() {
this.binaryInput = null;
this.input = null;
this.binaryOutput = null;
this.output = null;
},
};
function makeSuccessCase(name) {
return function() {
do_print('got expected: ' + name);
run_next_test();
};
}
function makeJointSuccess(names) {
let funcs = {}, successCount = 0;
names.forEach(function(name) {
funcs[name] = function() {
do_print('got expected: ' + name);
if (++successCount === names.length)
run_next_test();
};
});
return funcs;
}
function makeFailureCase(name) {
return function() {
let argstr;
if (arguments.length) {
argstr = '(args: ' +
Array.map(arguments, function(x) { return x.data + ""; }).join(" ") + ')';
}
else {
argstr = '(no arguments)';
}
do_throw('got unexpected: ' + name + ' ' + argstr);
};
}
function makeExpectData(name, expectedData, fromEvent, callback) {
let dataBuffer = fromEvent ? null : [], done = false;
let dataBufferView = null;
return function(receivedData) {
if (receivedData.data) {
receivedData = receivedData.data;
}
let recvLength = receivedData.byteLength !== undefined ?
receivedData.byteLength : receivedData.length;
if (fromEvent) {
if (dataBuffer) {
let newBuffer = new ArrayBuffer(dataBuffer.byteLength + recvLength);
let newBufferView = new Uint8Array(newBuffer);
newBufferView.set(dataBufferView, 0);
newBufferView.set(receivedData, dataBuffer.byteLength);
dataBuffer = newBuffer;
dataBufferView = newBufferView;
}
else {
dataBuffer = receivedData;
dataBufferView = new Uint8Array(dataBuffer);
}
}
else {
dataBuffer = dataBuffer.concat(receivedData);
}
do_print(name + ' received ' + recvLength + ' bytes');
if (done)
do_throw(name + ' Received data event when already done!');
let dataView = dataBuffer.byteLength !== undefined ? new Uint8Array(dataBuffer) : dataBuffer;
if (dataView.length >= expectedData.length) {
// check the bytes are equivalent
for (let i = 0; i < expectedData.length; i++) {
if (dataView[i] !== expectedData[i]) {
do_throw(name + ' Received mismatched character at position ' + i);
}
}
if (dataView.length > expectedData.length)
do_throw(name + ' Received ' + dataView.length + ' bytes but only expected ' +
expectedData.length + ' bytes.');
done = true;
if (callback) {
callback();
} else {
run_next_test();
}
}
};
}
var server = null, sock = null, failure_drain = null;
/**
*
* Test functions
*
*/
/**
* Connect the socket to the server. This test is added as the first
* test, and is also added after every test which results in the socket
* being closed.
*/
function connectSock() {
server.reset();
var yayFuncs = makeJointSuccess(['serveropen', 'clientopen']);
sock = TCPSocket.open(
'127.0.0.1', server.listener.port,
{ binaryType: 'arraybuffer' });
sock.onopen = yayFuncs.clientopen;
sock.ondrain = null;
sock.ondata = makeFailureCase('data');
sock.onerror = makeFailureCase('error');
sock.onclose = makeFailureCase('close');
server.onconnect = yayFuncs.serveropen;
server.ondata = makeFailureCase('serverdata');
server.onclose = makeFailureCase('serverclose');
}
function cleanup() {
do_print("Cleaning up");
sock.close();
if (!gInChild)
Services.prefs.clearUserPref('dom.mozTCPSocket.enabled');
run_next_test();
}
// Test child behavior when child thinks it's buffering but parent doesn't
// buffer.
// 1. set bufferedAmount of content socket to a value that will make next
// send() call return false.
// 2. send a small data to make send() return false, but it won't make
// parent buffer.
// 3. we should get a ondrain.
function childbuffered() {
let yays = makeJointSuccess(['ondrain', 'serverdata',
'clientclose', 'serverclose']);
sock.ondrain = function() {
yays.ondrain();
sock.close();
};
server.ondata = makeExpectData(
'ondata', DATA_ARRAY, false, yays.serverdata);
let internalSocket = sock.QueryInterface(Ci.nsITCPSocketInternal);
internalSocket.updateBufferedAmount(65535, // almost reach buffering threshold
0);
if (sock.send(DATA_ARRAY_BUFFER)) {
do_throw("expected sock.send to return false.");
}
sock.onclose = yays.clientclose;
server.onclose = yays.serverclose;
}
// Test child's behavior when send() of child return true but parent buffers
// data.
// 1. send BIG_ARRAY to make parent buffer. This would make child wait for
// drain as well.
// 2. set child's bufferedAmount to zero, so child will no longer wait for
// drain but parent will dispatch a drain event.
// 3. wait for 1 second, to make sure there's no ondrain event dispatched in
// child.
function childnotbuffered() {
let yays = makeJointSuccess(['serverdata', 'clientclose', 'serverclose']);
server.ondata = makeExpectData('ondata', BIG_ARRAY, false, yays.serverdata);
if (sock.send(BIG_ARRAY_BUFFER)) {
do_throw("sock.send(BIG_TYPED_ARRAY) did not return false to indicate buffering");
}
let internalSocket = sock.QueryInterface(Ci.nsITCPSocketInternal);
internalSocket.updateBufferedAmount(0, // setting zero will clear waitForDrain in sock.
1);
// shouldn't get ondrain, even after parent have cleared its buffer.
sock.ondrain = makeFailureCase('drain');
sock.onclose = yays.clientclose;
server.onclose = yays.serverclose;
do_timeout(1000, function() {
sock.close();
});
};
if (is_content()) {
add_test(connectSock);
add_test(childnotbuffered);
add_test(connectSock);
add_test(childbuffered);
// clean up
add_test(cleanup);
} else {
do_check_true(true, 'non-content process wants to pretend to one test');
}
function run_test() {
if (!gInChild)
Services.prefs.setBoolPref('dom.mozTCPSocket.enabled', true);
server = new TestServer();
run_next_test();
}

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

@ -1,6 +0,0 @@
[DEFAULT]
head =
tail =
skip-if = toolkit == 'gonk'
[test_tcpsocket.js]

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

@ -1,9 +0,0 @@
Components.utils.import("resource://gre/modules/Services.jsm");
function run_test() {
Services.prefs.setBoolPref('dom.mozTCPSocket.enabled', true);
run_test_in_child("../unit/test_tcpsocket.js", function() {
Services.prefs.clearUserPref('dom.mozTCPSocket.enabled');
do_test_finished();
});
}

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

@ -1,6 +0,0 @@
[DEFAULT]
head =
tail =
skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_tcpsocket_ipc.js]

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

@ -85,9 +85,6 @@
#include "mozilla/Attributes.h"
#include "mozilla/dom/DOMException.h"
#include "mozilla/dom/DOMRequest.h"
#include "mozilla/dom/network/TCPSocketChild.h"
#include "mozilla/dom/network/TCPSocketParent.h"
#include "mozilla/dom/network/TCPServerSocketChild.h"
#include "mozilla/dom/network/UDPSocketChild.h"
#include "mozilla/dom/quota/QuotaManager.h"
#include "mozilla/dom/workers/ServiceWorkerManager.h"
@ -275,9 +272,6 @@ using mozilla::dom::quota::QuotaManager;
using mozilla::dom::workers::ServiceWorkerManager;
using mozilla::dom::workers::ServiceWorkerPeriodicUpdater;
using mozilla::dom::workers::WorkerDebuggerManager;
using mozilla::dom::TCPSocketChild;
using mozilla::dom::TCPSocketParent;
using mozilla::dom::TCPServerSocketChild;
using mozilla::dom::UDPSocketChild;
using mozilla::dom::time::TimeService;
using mozilla::net::StreamingProtocolControllerService;
@ -665,9 +659,6 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsNullPrincipal, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsStructuredCloneContainer)
NS_GENERIC_FACTORY_CONSTRUCTOR(OSFileConstantsService)
NS_GENERIC_FACTORY_CONSTRUCTOR(TCPSocketChild)
NS_GENERIC_FACTORY_CONSTRUCTOR(TCPSocketParent)
NS_GENERIC_FACTORY_CONSTRUCTOR(TCPServerSocketChild)
NS_GENERIC_FACTORY_CONSTRUCTOR(UDPSocketChild)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(GeckoMediaPluginService, GeckoMediaPluginService::GetGeckoMediaPluginService)
@ -837,9 +828,6 @@ NS_DEFINE_NAMED_CID(MOBILE_MESSAGE_DATABASE_SERVICE_CID);
NS_DEFINE_NAMED_CID(NS_POWERMANAGERSERVICE_CID);
NS_DEFINE_NAMED_CID(OSFILECONSTANTSSERVICE_CID);
NS_DEFINE_NAMED_CID(NS_ALARMHALSERVICE_CID);
NS_DEFINE_NAMED_CID(TCPSOCKETCHILD_CID);
NS_DEFINE_NAMED_CID(TCPSOCKETPARENT_CID);
NS_DEFINE_NAMED_CID(TCPSERVERSOCKETCHILD_CID);
NS_DEFINE_NAMED_CID(UDPSOCKETCHILD_CID);
NS_DEFINE_NAMED_CID(NS_TIMESERVICE_CID);
NS_DEFINE_NAMED_CID(NS_MEDIASTREAMCONTROLLERSERVICE_CID);
@ -1147,9 +1135,6 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = {
{ &kNS_POWERMANAGERSERVICE_CID, false, nullptr, nsIPowerManagerServiceConstructor },
{ &kOSFILECONSTANTSSERVICE_CID, true, nullptr, OSFileConstantsServiceConstructor },
{ &kNS_ALARMHALSERVICE_CID, false, nullptr, nsIAlarmHalServiceConstructor },
{ &kTCPSOCKETCHILD_CID, false, nullptr, TCPSocketChildConstructor },
{ &kTCPSOCKETPARENT_CID, false, nullptr, TCPSocketParentConstructor },
{ &kTCPSERVERSOCKETCHILD_CID, false, nullptr, TCPServerSocketChildConstructor },
{ &kUDPSOCKETCHILD_CID, false, nullptr, UDPSocketChildConstructor },
{ &kGECKO_MEDIA_PLUGIN_SERVICE_CID, true, nullptr, GeckoMediaPluginServiceConstructor },
{ &kNS_TIMESERVICE_CID, false, nullptr, nsITimeServiceConstructor },
@ -1318,9 +1303,6 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
{ POWERMANAGERSERVICE_CONTRACTID, &kNS_POWERMANAGERSERVICE_CID },
{ OSFILECONSTANTSSERVICE_CONTRACTID, &kOSFILECONSTANTSSERVICE_CID },
{ ALARMHALSERVICE_CONTRACTID, &kNS_ALARMHALSERVICE_CID },
{ "@mozilla.org/tcp-socket-child;1", &kTCPSOCKETCHILD_CID },
{ "@mozilla.org/tcp-socket-parent;1", &kTCPSOCKETPARENT_CID },
{ "@mozilla.org/tcp-server-socket-child;1", &kTCPSERVERSOCKETCHILD_CID },
{ "@mozilla.org/udp-socket-child;1", &kUDPSOCKETCHILD_CID },
{ TIMESERVICE_CONTRACTID, &kNS_TIMESERVICE_CID },
{ MEDIASTREAMCONTROLLERSERVICE_CONTRACTID, &kNS_MEDIASTREAMCONTROLLERSERVICE_CID },

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

@ -210,8 +210,7 @@ PTCPSocketChild*
NeckoChild::AllocPTCPSocketChild(const nsString& host,
const uint16_t& port)
{
TCPSocketChild* p = new TCPSocketChild();
p->Init(host, port);
TCPSocketChild* p = new TCPSocketChild(host, port);
p->AddIPDLReference();
return p;
}
@ -227,7 +226,7 @@ NeckoChild::DeallocPTCPSocketChild(PTCPSocketChild* child)
PTCPServerSocketChild*
NeckoChild::AllocPTCPServerSocketChild(const uint16_t& aLocalPort,
const uint16_t& aBacklog,
const nsString& aBinaryType)
const bool& aUseArrayBuffers)
{
NS_NOTREACHED("AllocPTCPServerSocket should not be called");
return nullptr;

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

@ -48,7 +48,7 @@ protected:
virtual PTCPServerSocketChild*
AllocPTCPServerSocketChild(const uint16_t& aLocalPort,
const uint16_t& aBacklog,
const nsString& aBinaryType) override;
const bool& aUseArrayBuffers) override;
virtual bool DeallocPTCPServerSocketChild(PTCPServerSocketChild*) override;
virtual PUDPSocketChild* AllocPUDPSocketChild(const Principal& aPrincipal,
const nsCString& aFilter) override;

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

@ -457,10 +457,10 @@ NeckoParent::DeallocPTCPSocketParent(PTCPSocketParent* actor)
PTCPServerSocketParent*
NeckoParent::AllocPTCPServerSocketParent(const uint16_t& aLocalPort,
const uint16_t& aBacklog,
const nsString& aBinaryType)
const uint16_t& aBacklog,
const bool& aUseArrayBuffers)
{
TCPServerSocketParent* p = new TCPServerSocketParent();
TCPServerSocketParent* p = new TCPServerSocketParent(this, aLocalPort, aBacklog, aUseArrayBuffers);
p->AddIPDLReference();
return p;
}
@ -469,10 +469,10 @@ bool
NeckoParent::RecvPTCPServerSocketConstructor(PTCPServerSocketParent* aActor,
const uint16_t& aLocalPort,
const uint16_t& aBacklog,
const nsString& aBinaryType)
const bool& aUseArrayBuffers)
{
return static_cast<TCPServerSocketParent*>(aActor)->
Init(this, aLocalPort, aBacklog, aBinaryType);
static_cast<TCPServerSocketParent*>(aActor)->Init();
return true;
}
bool

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

@ -146,11 +146,11 @@ protected:
virtual PTCPServerSocketParent*
AllocPTCPServerSocketParent(const uint16_t& aLocalPort,
const uint16_t& aBacklog,
const nsString& aBinaryType) override;
const bool& aUseArrayBuffers) override;
virtual bool RecvPTCPServerSocketConstructor(PTCPServerSocketParent*,
const uint16_t& aLocalPort,
const uint16_t& aBacklog,
const nsString& aBinaryType) override;
const bool& aUseArrayBuffers) override;
virtual bool DeallocPTCPServerSocketParent(PTCPServerSocketParent*) override;
virtual PUDPSocketParent* AllocPUDPSocketParent(const Principal& aPrincipal,
const nsCString& aFilter) override;

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

@ -67,7 +67,7 @@ parent:
FTPChannelCreationArgs args);
PWebSocket(PBrowserOrId browser, SerializedLoadContext loadContext);
PTCPServerSocket(uint16_t localPort, uint16_t backlog, nsString binaryType);
PTCPServerSocket(uint16_t localPort, uint16_t backlog, bool useArrayBuffers);
PUDPSocket(Principal principal, nsCString filter);
PDNSRequest(nsCString hostName, uint32_t flags, nsCString networkInterface);