зеркало из https://github.com/mozilla/gecko-dev.git
Bug 885982 - Part 3: Add e10s support to TCPSocket and TCPServerSocket. r=asuth,mayhemer,bz
This commit is contained in:
Родитель
eb2db2dd0f
Коммит
fbb088e702
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче