michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include michael@0: #include "TCPSocketChild.h" michael@0: #include "mozilla/unused.h" michael@0: #include "mozilla/net/NeckoChild.h" michael@0: #include "mozilla/dom/PBrowserChild.h" michael@0: #include "mozilla/dom/TabChild.h" michael@0: #include "nsIDOMTCPSocket.h" michael@0: #include "nsJSUtils.h" michael@0: #include "nsContentUtils.h" michael@0: #include "jsapi.h" michael@0: #include "jsfriendapi.h" michael@0: #include "jswrapper.h" michael@0: michael@0: using mozilla::net::gNeckoChild; michael@0: michael@0: namespace IPC { michael@0: michael@0: bool michael@0: DeserializeArrayBuffer(JS::Handle aObj, michael@0: const InfallibleTArray& aBuffer, michael@0: JS::MutableHandle aVal) michael@0: { michael@0: mozilla::AutoSafeJSContext cx; michael@0: JSAutoCompartment ac(cx, aObj); michael@0: michael@0: JS::Rooted obj(cx, JS_NewArrayBuffer(cx, aBuffer.Length())); michael@0: if (!obj) michael@0: return false; michael@0: uint8_t* data = JS_GetArrayBufferData(obj); michael@0: if (!data) michael@0: return false; michael@0: memcpy(data, aBuffer.Elements(), aBuffer.Length()); michael@0: aVal.set(OBJECT_TO_JSVAL(obj)); michael@0: return true; michael@0: } michael@0: michael@0: } // namespace IPC michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION(TCPSocketChildBase, mSocket) michael@0: NS_IMPL_CYCLE_COLLECTING_ADDREF(TCPSocketChildBase) michael@0: NS_IMPL_CYCLE_COLLECTING_RELEASE(TCPSocketChildBase) michael@0: michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TCPSocketChildBase) michael@0: NS_INTERFACE_MAP_ENTRY(nsITCPSocketChild) michael@0: NS_INTERFACE_MAP_ENTRY(nsISupports) michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: TCPSocketChildBase::TCPSocketChildBase() michael@0: : mIPCOpen(false) michael@0: { michael@0: } michael@0: michael@0: TCPSocketChildBase::~TCPSocketChildBase() michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP_(MozExternalRefCountType) TCPSocketChild::Release(void) michael@0: { michael@0: nsrefcnt refcnt = TCPSocketChildBase::Release(); michael@0: if (refcnt == 1 && mIPCOpen) { michael@0: PTCPSocketChild::SendRequestDelete(); michael@0: return 1; michael@0: } michael@0: return refcnt; michael@0: } michael@0: michael@0: TCPSocketChild::TCPSocketChild() michael@0: : mWindowObj(nullptr) michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TCPSocketChild::SendOpen(nsITCPSocketInternal* aSocket, michael@0: const nsAString& aHost, uint16_t aPort, michael@0: bool aUseSSL, const nsAString& aBinaryType, michael@0: nsIDOMWindow* aWindow, JS::Handle aWindowObj, michael@0: JSContext* aCx) michael@0: { michael@0: mSocket = aSocket; michael@0: michael@0: MOZ_ASSERT(aWindowObj.isObject()); michael@0: mWindowObj = js::CheckedUnwrap(&aWindowObj.toObject()); michael@0: if (!mWindowObj) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: AddIPDLReference(); michael@0: gNeckoChild->SendPTCPSocketConstructor(this); michael@0: PTCPSocketChild::SendOpen(nsString(aHost), aPort, michael@0: aUseSSL, nsString(aBinaryType)); michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: TCPSocketChildBase::ReleaseIPDLReference() michael@0: { michael@0: MOZ_ASSERT(mIPCOpen); michael@0: mIPCOpen = false; michael@0: this->Release(); michael@0: } michael@0: michael@0: void michael@0: TCPSocketChildBase::AddIPDLReference() michael@0: { michael@0: MOZ_ASSERT(!mIPCOpen); michael@0: mIPCOpen = true; michael@0: this->AddRef(); michael@0: } michael@0: michael@0: TCPSocketChild::~TCPSocketChild() michael@0: { michael@0: } michael@0: michael@0: bool michael@0: TCPSocketChild::RecvUpdateBufferedAmount(const uint32_t& aBuffered, michael@0: const uint32_t& aTrackingNumber) michael@0: { michael@0: if (NS_FAILED(mSocket->UpdateBufferedAmount(aBuffered, aTrackingNumber))) { michael@0: NS_ERROR("Shouldn't fail!"); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TCPSocketChild::RecvCallback(const nsString& aType, michael@0: const CallbackData& aData, michael@0: const nsString& aReadyState) michael@0: { michael@0: if (NS_FAILED(mSocket->UpdateReadyState(aReadyState))) michael@0: NS_ERROR("Shouldn't fail!"); michael@0: michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: if (aData.type() == CallbackData::Tvoid_t) { michael@0: rv = mSocket->CallListenerVoid(aType); michael@0: michael@0: } else if (aData.type() == CallbackData::TTCPError) { michael@0: const TCPError& err(aData.get_TCPError()); michael@0: rv = mSocket->CallListenerError(aType, err.name()); michael@0: michael@0: } else if (aData.type() == CallbackData::TSendableData) { michael@0: const SendableData& data = aData.get_SendableData(); michael@0: michael@0: if (data.type() == SendableData::TArrayOfuint8_t) { michael@0: JSContext* cx = nsContentUtils::GetSafeJSContext(); michael@0: JSAutoRequest ar(cx); michael@0: JS::Rooted val(cx); michael@0: JS::Rooted window(cx, mWindowObj); michael@0: bool ok = IPC::DeserializeArrayBuffer(window, data.get_ArrayOfuint8_t(), &val); michael@0: NS_ENSURE_TRUE(ok, true); michael@0: rv = mSocket->CallListenerArrayBuffer(aType, val); michael@0: michael@0: } else if (data.type() == SendableData::TnsString) { michael@0: rv = mSocket->CallListenerData(aType, data.get_nsString()); michael@0: michael@0: } else { michael@0: MOZ_CRASH("Invalid callback data type!"); michael@0: } michael@0: michael@0: } else { michael@0: MOZ_CRASH("Invalid callback type!"); michael@0: } michael@0: NS_ENSURE_SUCCESS(rv, true); michael@0: return true; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TCPSocketChild::SendStartTLS() michael@0: { michael@0: PTCPSocketChild::SendStartTLS(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TCPSocketChild::SendSuspend() michael@0: { michael@0: PTCPSocketChild::SendSuspend(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TCPSocketChild::SendResume() michael@0: { michael@0: PTCPSocketChild::SendResume(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TCPSocketChild::SendClose() michael@0: { michael@0: PTCPSocketChild::SendClose(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TCPSocketChild::SendSend(JS::Handle aData, michael@0: uint32_t aByteOffset, michael@0: uint32_t aByteLength, michael@0: uint32_t aTrackingNumber, michael@0: JSContext* aCx) michael@0: { michael@0: if (aData.isString()) { michael@0: JSString* jsstr = aData.toString(); michael@0: nsDependentJSString str; michael@0: bool ok = str.init(aCx, jsstr); michael@0: NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); michael@0: SendData(str, aTrackingNumber); michael@0: } else { michael@0: NS_ENSURE_TRUE(aData.isObject(), NS_ERROR_FAILURE); michael@0: JS::Rooted obj(aCx, &aData.toObject()); michael@0: NS_ENSURE_TRUE(JS_IsArrayBufferObject(obj), NS_ERROR_FAILURE); michael@0: uint32_t buflen = JS_GetArrayBufferByteLength(obj); michael@0: aByteOffset = std::min(buflen, aByteOffset); michael@0: uint32_t nbytes = std::min(buflen - aByteOffset, aByteLength); michael@0: uint8_t* data = JS_GetArrayBufferData(obj); michael@0: if (!data) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: FallibleTArray fallibleArr; michael@0: if (!fallibleArr.InsertElementsAt(0, data + aByteOffset, nbytes)) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: InfallibleTArray arr; michael@0: arr.SwapElements(fallibleArr); michael@0: SendData(arr, aTrackingNumber); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TCPSocketChild::SetSocketAndWindow(nsITCPSocketInternal *aSocket, michael@0: JS::Handle aWindowObj, michael@0: JSContext* aCx) michael@0: { michael@0: mSocket = aSocket; michael@0: MOZ_ASSERT(aWindowObj.isObject()); michael@0: mWindowObj = js::CheckedUnwrap(&aWindowObj.toObject()); michael@0: if (!mWindowObj) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: TCPSocketChild::RecvRequestDelete() michael@0: { michael@0: mozilla::unused << Send__delete__(this); michael@0: return true; michael@0: } michael@0: michael@0: } // namespace dom michael@0: } // namespace mozilla