2012-09-24 11:53:49 -07:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
#include "TCPSocketChild.h"
|
|
|
|
#include "mozilla/net/NeckoChild.h"
|
|
|
|
#include "mozilla/dom/PBrowserChild.h"
|
|
|
|
#include "mozilla/dom/TabChild.h"
|
|
|
|
#include "nsIDOMTCPSocket.h"
|
|
|
|
#include "nsJSUtils.h"
|
|
|
|
#include "nsContentUtils.h"
|
|
|
|
#include "jsapi.h"
|
|
|
|
#include "jsfriendapi.h"
|
2013-04-23 08:12:53 -07:00
|
|
|
#include "jswrapper.h"
|
2012-09-24 11:53:49 -07:00
|
|
|
|
|
|
|
using mozilla::net::gNeckoChild;
|
|
|
|
|
|
|
|
namespace IPC {
|
|
|
|
|
|
|
|
bool
|
2013-05-10 19:39:45 -07:00
|
|
|
DeserializeArrayBuffer(JS::Handle<JSObject*> aObj,
|
2013-04-19 02:25:33 -07:00
|
|
|
const InfallibleTArray<uint8_t>& aBuffer,
|
2013-05-10 19:39:45 -07:00
|
|
|
JS::MutableHandle<JS::Value> aVal)
|
2012-09-24 11:53:49 -07:00
|
|
|
{
|
|
|
|
JSContext* cx = nsContentUtils::GetSafeJSContext();
|
|
|
|
JSAutoCompartment ac(cx, aObj);
|
|
|
|
|
2013-05-04 00:52:57 -07:00
|
|
|
JS::Rooted<JSObject*> obj(cx, JS_NewArrayBuffer(cx, aBuffer.Length()));
|
2012-09-24 11:53:49 -07:00
|
|
|
if (!obj)
|
|
|
|
return false;
|
2012-11-14 09:56:26 -08:00
|
|
|
uint8_t* data = JS_GetArrayBufferData(obj);
|
2012-09-24 11:53:49 -07:00
|
|
|
if (!data)
|
|
|
|
return false;
|
|
|
|
memcpy(data, aBuffer.Elements(), aBuffer.Length());
|
2013-05-10 19:39:45 -07:00
|
|
|
aVal.set(OBJECT_TO_JSVAL(obj));
|
2012-09-24 11:53:49 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace IPC
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
namespace dom {
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_1(TCPSocketChildBase, mSocket)
|
|
|
|
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
|
|
|
|
|
|
|
|
TCPSocketChildBase::TCPSocketChildBase()
|
|
|
|
: mIPCOpen(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
TCPSocketChildBase::~TCPSocketChildBase()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP_(nsrefcnt) TCPSocketChild::Release(void)
|
|
|
|
{
|
|
|
|
nsrefcnt refcnt = TCPSocketChildBase::Release();
|
|
|
|
if (refcnt == 1 && mIPCOpen) {
|
|
|
|
PTCPSocketChild::SendRequestDelete();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return refcnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
TCPSocketChild::TCPSocketChild()
|
|
|
|
: mSocketObj(nullptr)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
TCPSocketChild::Open(nsITCPSocketInternal* aSocket, const nsAString& aHost,
|
|
|
|
uint16_t aPort, bool aUseSSL, const nsAString& aBinaryType,
|
|
|
|
nsIDOMWindow* aWindow, const JS::Value& aSocketObj,
|
|
|
|
JSContext* aCx)
|
|
|
|
{
|
|
|
|
mSocket = aSocket;
|
|
|
|
MOZ_ASSERT(aSocketObj.isObject());
|
2013-04-23 08:29:30 -07:00
|
|
|
mSocketObj = js::CheckedUnwrap(&aSocketObj.toObject());
|
2013-04-23 08:12:53 -07:00
|
|
|
if (!mSocketObj) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2012-09-24 11:53:49 -07:00
|
|
|
AddIPDLReference();
|
|
|
|
gNeckoChild->SendPTCPSocketConstructor(this, nsString(aHost), aPort,
|
|
|
|
aUseSSL, nsString(aBinaryType),
|
|
|
|
GetTabChildFrom(aWindow));
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TCPSocketChildBase::ReleaseIPDLReference()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(mIPCOpen);
|
|
|
|
mIPCOpen = false;
|
|
|
|
this->Release();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TCPSocketChildBase::AddIPDLReference()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(!mIPCOpen);
|
|
|
|
mIPCOpen = true;
|
|
|
|
this->AddRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
TCPSocketChild::~TCPSocketChild()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
TCPSocketChild::RecvCallback(const nsString& aType,
|
|
|
|
const CallbackData& aData,
|
|
|
|
const nsString& aReadyState,
|
|
|
|
const uint32_t& aBuffered)
|
|
|
|
{
|
|
|
|
if (NS_FAILED(mSocket->UpdateReadyStateAndBuffered(aReadyState, aBuffered)))
|
|
|
|
NS_ERROR("Shouldn't fail!");
|
|
|
|
|
|
|
|
nsresult rv = NS_ERROR_FAILURE;
|
|
|
|
if (aData.type() == CallbackData::Tvoid_t) {
|
|
|
|
rv = mSocket->CallListenerVoid(aType);
|
|
|
|
|
2013-05-02 00:51:54 -07:00
|
|
|
} else if (aData.type() == CallbackData::TTCPError) {
|
|
|
|
const TCPError& err(aData.get_TCPError());
|
|
|
|
rv = mSocket->CallListenerError(aType, err.name());
|
2012-09-24 11:53:49 -07:00
|
|
|
|
|
|
|
} else if (aData.type() == CallbackData::TSendableData) {
|
|
|
|
const SendableData& data = aData.get_SendableData();
|
|
|
|
|
|
|
|
if (data.type() == SendableData::TArrayOfuint8_t) {
|
2013-05-10 19:39:45 -07:00
|
|
|
JSContext* cx = nsContentUtils::GetSafeJSContext();
|
|
|
|
JS::Rooted<JS::Value> val(cx);
|
|
|
|
JS::Rooted<JSObject*> socket(cx, mSocketObj);
|
|
|
|
bool ok = IPC::DeserializeArrayBuffer(socket, data.get_ArrayOfuint8_t(), &val);
|
2013-04-23 09:05:06 -07:00
|
|
|
NS_ENSURE_TRUE(ok, true);
|
2012-09-24 11:53:49 -07:00
|
|
|
rv = mSocket->CallListenerArrayBuffer(aType, val);
|
|
|
|
|
|
|
|
} else if (data.type() == SendableData::TnsString) {
|
|
|
|
rv = mSocket->CallListenerData(aType, data.get_nsString());
|
|
|
|
|
|
|
|
} else {
|
|
|
|
MOZ_NOT_REACHED("Invalid callback data type!");
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
MOZ_NOT_REACHED("Invalid callback type!");
|
|
|
|
}
|
|
|
|
NS_ENSURE_SUCCESS(rv, true);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
TCPSocketChild::Suspend()
|
|
|
|
{
|
|
|
|
SendSuspend();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
TCPSocketChild::Resume()
|
|
|
|
{
|
|
|
|
SendResume();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
TCPSocketChild::Close()
|
|
|
|
{
|
|
|
|
SendClose();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2013-04-19 02:25:33 -07:00
|
|
|
TCPSocketChild::Send(const JS::Value& aData,
|
|
|
|
uint32_t aByteOffset,
|
|
|
|
uint32_t aByteLength,
|
|
|
|
JSContext* aCx)
|
2012-09-24 11:53:49 -07:00
|
|
|
{
|
|
|
|
if (aData.isString()) {
|
|
|
|
JSString* jsstr = aData.toString();
|
|
|
|
nsDependentJSString str;
|
|
|
|
bool ok = str.init(aCx, jsstr);
|
|
|
|
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
|
|
|
|
SendData(str);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
NS_ENSURE_TRUE(aData.isObject(), NS_ERROR_FAILURE);
|
2013-05-04 00:52:57 -07:00
|
|
|
JS::Rooted<JSObject*> obj(aCx, &aData.toObject());
|
2013-04-19 02:25:33 -07:00
|
|
|
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);
|
|
|
|
uint8_t* data = JS_GetArrayBufferData(obj);
|
2012-09-24 11:53:49 -07:00
|
|
|
if (!data) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
FallibleTArray<uint8_t> fallibleArr;
|
|
|
|
if (!fallibleArr.InsertElementsAt(0, data, nbytes)) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
InfallibleTArray<uint8_t> arr;
|
|
|
|
arr.SwapElements(fallibleArr);
|
|
|
|
SendData(arr);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace dom
|
|
|
|
} // namespace mozilla
|